Current section
Files
Jump to
Current section
Files
lib/typable.ex
defprotocol Typable do
@moduledoc """
Protocol which describes type identifier of Elixir term
"""
@fallback_to_any true
@type t :: Typable.t()
@doc """
Returns module which represents type identifier of given term
## Examples
```
iex> Typable.type_of(1)
Integer
iex> Typable.type_of(self())
PID
iex> Typable.type_of(%URI{})
URI
```
"""
@spec type_of(t) :: module
def type_of(t)
end
[
# scalars
Atom,
BitString,
Float,
Function,
Integer,
PID,
Port,
Reference,
# collections
Tuple,
List,
Map
]
|> Enum.each(fn type ->
defimpl Typable, for: type do
def type_of(_), do: unquote(type)
end
end)
defimpl Typable, for: Any do
def type_of(%type{}), do: type
end
defmodule Type do
@moduledoc """
Utilities for Typable protocol
"""
defdelegate type_of(x), to: Typable
@doc """
Returns term which is instance of given type.
Have compile-time guarantees.
## Examples
```
iex> require Type
iex> Type.instance_of(Integer)
0
iex> Type.instance_of(Port)
#Port<0.0>
iex> Type.instance_of(URI)
%URI{}
iex> quote do
...> require Type
...> Type.instance_of(TypeNotExist)
...> end
...> |> Code.eval_quoted()
** (UndefinedFunctionError) function TypeNotExist.__struct__/0 is undefined (module TypeNotExist is not available)
```
"""
defmacro instance_of(quoted_type) do
{type, []} = Code.eval_quoted(quoted_type, [], __CALLER__)
mk_instance(type)
end
# scalars
defp mk_instance(Atom), do: nil
defp mk_instance(BitString), do: ""
defp mk_instance(Float), do: 0.0
defp mk_instance(Function) do
quote location: :keep do
&self/0
end
end
defp mk_instance(Integer), do: 0
defp mk_instance(PID) do
quote location: :keep do
:erlang.list_to_pid('<0.0.0>')
end
end
defp mk_instance(Port) do
quote location: :keep do
:erlang.list_to_port('#Port<0.0>')
end
end
defp mk_instance(Reference) do
quote location: :keep do
:erlang.list_to_ref('#Ref<0.0.0.0>')
end
end
# collections
defp mk_instance(Tuple) do
quote location: :keep do
{}
end
end
defp mk_instance(List) do
quote location: :keep do
[]
end
end
defp mk_instance(Map) do
quote location: :keep do
%{}
end
end
# other types
defp mk_instance(type) do
type.__struct__()
|> Macro.escape()
end
end