defmodule Hugs.StructDefinition do alias Hugs.FieldDefinition alias Hugs.PropsDefinition @enforce_keys [:module, :props] defstruct @enforce_keys def new(module) do %__MODULE__{module: module, props: PropsDefinition.new()} end def add_field(%__MODULE__{props: m} = this, %FieldDefinition{} = field) do verify_struct_field!(this, field) %__MODULE__{this | props: PropsDefinition.add_field(m, field)} end def add_constraint(%__MODULE__{props: m} = this, module, fun, args) do %__MODULE__{this | props: PropsDefinition.add_constraint(m, module, fun, args)} end def constraints(%__MODULE__{props: m}), do: PropsDefinition.constraints(m) defp verify_struct_field!(_this, %FieldDefinition{} = field) do %FieldDefinition{key: key, required: _req?, default: _default, optional: opt?} = field if not is_atom(key), do: raise("only atoms are supported for struct keys, got: #{inspect(key)}") if opt?, do: raise("struct fields cannot be :optional") # if not req? and default == :__undef__ do # IO.warn( # "field #{inspect(key)} of struct #{inspect(this.module)} is not required and was not given a default value. :__undef__ base default value will be used" # ) # end end def required_keys(%__MODULE__{props: m}), do: PropsDefinition.required_keys(m) def default_pairs(%__MODULE__{props: m}), do: PropsDefinition.default_pairs(m, false) end