api-v2/deps/poison/lib/poison/decoder.ex
2025-04-16 10:03:13 -03:00

126 lines
2.8 KiB
Elixir

defmodule Poison.DecodeError do
@type t :: %__MODULE__{message: String.t(), value: any}
defexception message: nil, value: nil
def message(%{message: nil, value: value}) do
"unable to decode value: #{inspect(value)}"
end
def message(%{message: message}) do
message
end
end
defmodule Poison.Decode do
@moduledoc false
alias Poison.Decoder
def transform(value, options) when is_map(value) or is_list(value) do
case Map.get(options, :as) do
nil -> value
as -> transform(value, Map.get(options, :keys), as, options)
end
end
def transform(value, _options) do
value
end
defp transform(nil, _keys, _as, _options), do: nil
defp transform(value, keys, %{__struct__: _} = as, options) do
transform_struct(value, keys, as, options)
end
defp transform(value, keys, as, options) when is_map(as) do
transform_map(value, keys, as, options)
end
defp transform(value, keys, [as], options) do
for v <- value, do: transform(v, keys, as, options)
end
defp transform(value, _keys, _as, _options) do
value
end
defp transform_map(value, keys, as, options) do
Enum.reduce(as, value, fn {key, as}, acc ->
case Map.get(acc, key) do
value when is_map(value) or is_list(value) ->
Map.put(acc, key, transform(value, keys, as, options))
_ ->
acc
end
end)
end
defp transform_struct(value, keys, as, options)
when keys in [:atoms, :atoms!] do
as
|> Map.from_struct()
|> Map.merge(value)
|> do_transform_struct(keys, as, options)
end
defp transform_struct(value, keys, as, options) do
as
|> Map.from_struct()
|> Enum.reduce(%{}, fn {key, default}, acc ->
Map.put(acc, key, Map.get(value, Atom.to_string(key), default))
end)
|> do_transform_struct(keys, as, options)
end
defp do_transform_struct(value, keys, as, options) do
default = struct(as.__struct__)
as
|> Map.from_struct()
|> Enum.reduce(%{}, fn {key, as}, acc ->
new_value =
case Map.fetch(value, key) do
{:ok, ^as} when is_map(as) or is_list(as) ->
Map.get(default, key)
{:ok, value} when is_map(value) or is_list(value) ->
transform(value, keys, as, options)
{:ok, value} ->
value
:error ->
Map.get(default, key)
end
Map.put(acc, key, new_value)
end)
|> Map.put(:__struct__, as.__struct__)
|> Decoder.decode(options)
end
end
defprotocol Poison.Decoder do
@fallback_to_any true
@typep keys :: :atoms | :atoms!
@typep as :: map | struct | [as]
@type options :: %{
optional(:keys) => keys,
optional(:as) => as
}
@spec decode(t, options) :: any
def decode(value, options)
end
defimpl Poison.Decoder, for: Any do
def decode(value, _options) do
value
end
end