Packages
jsv
0.1.0
0.21.2
0.21.1
0.21.0
0.20.0
0.19.6
0.19.5
0.19.4
0.19.3
0.19.2
0.19.1
0.19.0
0.18.3
0.18.2
0.18.1
0.18.0
0.17.1
0.17.0
0.16.0
0.15.2
0.15.1
0.15.0
0.14.0
0.13.1
0.13.0
0.12.0
0.11.5
0.11.4
0.11.3
retired
0.11.2
0.11.1
0.11.0
0.10.1
0.10.0
0.9.0
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.3
0.6.2
0.6.0
0.5.1
0.5.0
0.4.0
0.3.0
0.2.0
0.1.0
A JSON Schema Validator with complete support for the latest specifications.
Current section
Files
Jump to
Current section
Files
lib/jsv/atom_tools.ex
defmodule JSV.AtomTools do
@moduledoc false
alias JSV.Schema
# # Tries Map.fetch/2 with both atom and binary key. The first attempt is made
# # with the binary key because we expect to work more often with raw schemas.
# #
# # Schemas defined with atom, as structs, are expected to be used and
# # transformed to validators at compile-time, where a loss of performance is
# # acceptable.
# defmacro map_fetch_prop(map, atom_form) when is_atom(atom_form) do
# str_form = Atom.to_string(atom_form)
# quote bind_quoted: binding() do
# case map do
# %{^str_form => value} -> {:ok, value}
# %{^atom_form => value} -> {:ok, value}
# %{} -> :error
# other -> :erlang.error({:badmap, other}, [map, atom_form])
# end
# end
# end
# defmacro map_fetch_prop!(map, atom_form) when is_atom(atom_form) do
# str_form = Atom.to_string(atom_form)
# quote bind_quoted: binding() do
# case map do
# %{^str_form => value} -> value
# %{^atom_form => value} -> value
# %{} -> raise KeyError, key: atom_form, term: map
# other -> :erlang.error({:badmap, other}, [map, atom_form])
# end
# end
# end
# defmacro map_get_prop(map, atom_form, default) when is_atom(atom_form) do
# str_form = Atom.to_string(atom_form)
# quote bind_quoted: binding() do
# case map do
# %{^str_form => value} -> value
# %{^atom_form => value} -> value
# %{} -> default
# other -> :erlang.error({:badmap, other}, [map, atom_form, default])
# end
# end
# end
# # This is the only place in this library where the string $id is defined. So
# # we are sure to always use the atom/binary compatible functions.
# defmacro id_bin do
# "$id"
# end
def fmap_atom_to_binary(term) do
# Checking before is faster (benchmark in ./tools)
if atom_props?(term) do
deatom(term)
else
term
end
end
@doc false
def deatom(term)
def deatom(term) when term == nil when term == true when term == false do
term
end
def deatom(term) when is_atom(term) do
Atom.to_string(term)
end
def deatom(term) when is_binary(term) when is_number(term) do
term
end
def deatom(%Schema{} = term) do
deatom_schema_struct(term)
end
def deatom(term) when is_struct(term) do
deatom(Map.from_struct(term))
end
def deatom(term) when is_map(term) do
Map.new(term, fn {k, v} -> {deatom_key(k), deatom(v)} end)
end
def deatom([h | t]) do
[deatom(h) | deatom(t)]
end
def deatom([]) do
[]
end
defp deatom_key(term) when term == nil when term == true when term == false do
Atom.to_string(term)
end
defp deatom_key(term) do
deatom(term)
end
def deatom_schema_struct(schema) do
schema
|> Map.from_struct()
|> Enum.flat_map(fn
{_, nil} -> []
{:__struct__, _} -> []
{k, v} -> [{deatom_key(k), deatom(v)}]
end)
|> Map.new()
end
@doc """
Returns true if the given value (and sub values) contains atoms. Does not
return true for `true`, `false` and `nil` except if keys in a map.
"""
def atom_props?(term)
def atom_props?(term) when is_map(term) do
atom_props_iter?(:maps.iterator(term))
end
def atom_props?(term) when is_number(term) when is_binary(term) do
false
end
# Special atoms as values does not count as an atom prop
def atom_props?(term) when term == true when term == false when term == nil do
false
end
def atom_props?(term) when is_atom(term) do
true
end
def atom_props?([h | t]) do
atom_props?(h) || atom_props?(t)
end
def atom_props?([]) do
false
end
defp atom_props_iter?(iter) do
case :maps.next(iter) do
{k, v, iter} -> is_atom(k) || atom_props?(v) || atom_props_iter?(iter)
:none -> false
end
end
end