Current section

Files

Jump to
optimal lib type.ex
Raw

lib/type.ex

defmodule Optimal.Type do
@scalar_types [
:any,
:atom,
:binary,
:bitstring,
:boolean,
:float,
:function,
:int,
:integer,
:keyword,
:list,
:map,
:nil,
:number,
:pid,
:port,
:reference,
:string,
:struct,
:tuple,
]
def validate_types(types, field_name, _opts, _schema) do
Enum.reduce(types, [], fn field_and_type, errors ->
type =
case field_and_type do
{_field, type} -> type
_ -> :any
end
if valid_type?(type) do
errors
else
[{field_name, "No such Optimal type: #{inspect(type)}"}]
end
end)
end
#TODO: Support nested schemas
def matches_type?(types, value) when is_list(types), do: Enum.any?(types, &matches_type?(&1, value))
def matches_type?(:any, _), do: true
def matches_type?({:keyword, value_type}, value) do
matches_type?(:keyword, value) and Enum.all?(value, fn {_k, v} -> matches_type?(value_type, v) end)
end
def matches_type?({:list, type}, value) do
matches_type?(:list, value) and Enum.all?(value, &matches_type?(type, &1))
end
def matches_type?({:function, arity}, value) when is_function(value, arity), do: true
def matches_type?({:function, _}, _), do: false
def matches_type?({:struct, struct}, %struct{}), do: true
def matches_type?({:struct, _}, _), do: false
def matches_type?(%struct{}, %struct{}), do: true
def matches_type?(%_{}, _), do: false
def matches_type?({:enum, list}, value), do: value in list
# Below this line is only scalar types. Do not move things below/above this line.
def matches_type?(type, _) when type not in @scalar_types, do: raise("Unreachable: no type #{inspect(type)}")
def matches_type?(:int, value) when is_integer(value), do: true
def matches_type?(:integer, value) when is_integer(value), do: true
def matches_type?(:bitstring, value) when is_bitstring(value), do: true
def matches_type?(:string, value) when is_binary(value), do: true
def matches_type?(:binary, value) when is_binary(value), do: true
def matches_type?(:float, value) when is_float(value), do: true
def matches_type?(:keyword, value), do: Keyword.keyword?(value)
def matches_type?(:list, value) when is_list(value), do: true
def matches_type?(:boolean, value) when is_boolean(value), do: true
def matches_type?(:atom, value) when is_atom(value), do: true
def matches_type?(:nil, nil), do: true
def matches_type?(:function, value) when is_function(value), do: true
def matches_type?(:map, value) when is_map(value), do: true
def matches_type?(:number, value) when is_number(value), do: true
def matches_type?(:pid, value) when is_pid(value), do: true
def matches_type?(:port, value) when is_port(value), do: true
def matches_type?(:reference, value) when is_reference(value), do: true
def matches_type?(:tuple, value) when is_tuple(value), do: true
def matches_type?(:struct, %_{}), do: true
def matches_type?(_, _), do: false
def valid_type?(:any), do: true
def valid_type?(types) when is_list(types), do: Enum.all?(types, &valid_type?/1)
def valid_type?({:function, i}) when is_integer(i) and i >= 0, do: true
def valid_type?({:keyword, type}), do: valid_type?(type)
def valid_type?({:list, type}), do: valid_type?(type)
def valid_type?({:struct, module}) when is_atom(module), do: true
def valid_type?({:enum, values}) when is_list(values), do: true
def valid_type?(%_{}), do: true
def valid_type?(type) when type in @scalar_types, do: true
def valid_type?(_), do: false
def merge(same, same), do: same
def merge(left, right), do: [left, right]
end