Files

94 lines
2.6 KiB
Elixir

defmodule :zj do
@moduledoc false
def encode(term) do
term
|> normalize_for_json(:loose)
|> Jason.encode!()
|> String.to_charlist()
end
def decode(stream) do
with {:ok, decoded} <- stream |> :unicode.characters_to_binary() |> Jason.decode() do
{:ok, to_charlist_values(decoded)}
end
end
def binary_encode(term) do
term
|> normalize_for_json(:strict)
|> Jason.encode!()
end
def binary_decode(stream) do
with {:ok, decoded} <- stream |> :unicode.characters_to_binary() |> Jason.decode() do
{:ok, replace_null(decoded)}
end
end
defp to_charlist_values(nil), do: :undefined
defp to_charlist_values(value) when is_binary(value), do: String.to_charlist(value)
defp to_charlist_values(value) when is_list(value) do
Enum.map(value, &to_charlist_values/1)
end
defp to_charlist_values(value) when is_map(value) do
Map.new(value, fn {key, item} ->
{to_charlist_values(key), to_charlist_values(item)}
end)
end
defp to_charlist_values(value), do: value
defp replace_null(nil), do: :undefined
defp replace_null(value) when is_list(value), do: Enum.map(value, &replace_null/1)
defp replace_null(value) when is_map(value) do
Map.new(value, fn {key, item} -> {key, replace_null(item)} end)
end
defp replace_null(value), do: value
defp normalize_for_json(:undefined, _mode), do: nil
defp normalize_for_json(value, _mode) when is_binary(value), do: value
defp normalize_for_json(value, _mode) when is_number(value), do: value
defp normalize_for_json(value, _mode) when value in [nil, true, false], do: value
defp normalize_for_json(value, _mode) when is_atom(value) do
Atom.to_string(value)
end
defp normalize_for_json(value, :loose) when is_list(value) do
if List.ascii_printable?(value) do
List.to_string(value)
else
Enum.map(value, &normalize_for_json(&1, :loose))
end
end
defp normalize_for_json(value, :strict) when is_list(value) do
Enum.map(value, &normalize_for_json(&1, :strict))
end
defp normalize_for_json(value, mode) when is_tuple(value) do
value
|> Tuple.to_list()
|> Enum.map(&normalize_for_json(&1, mode))
end
defp normalize_for_json(value, mode) when is_map(value) do
Map.new(value, fn {key, item} ->
{normalize_key(key), normalize_for_json(item, mode)}
end)
end
defp normalize_for_json(value, _mode) do
to_string(value)
end
defp normalize_key(key) when is_binary(key) or is_atom(key), do: key
defp normalize_key(key) when is_list(key), do: List.to_string(key)
defp normalize_key(key), do: to_string(key)
end