94 lines
2.6 KiB
Elixir
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
|