Current section

Files

Jump to
decode src decode.erl
Raw

src/decode.erl

-module(decode).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([into/1, parameter/1, from/2, map/2, map_errors/2, then/2, list/1, field/3, dict/2, optional/1, collapse_errors/2, one_of/1, at/2, fail/1]).
-export_type([decoder/1]).
-opaque decoder(FQU) :: {decoder,
fun((gleam@dynamic:dynamic_()) -> {ok, FQU} |
{error, list(gleam@dynamic:decode_error())})}.
-spec into(FQZ) -> decoder(FQZ).
into(Constructor) ->
{decoder, fun(_) -> {ok, Constructor} end}.
-spec parameter(fun((FRB) -> FRC)) -> fun((FRB) -> FRC).
parameter(Body) ->
Body.
-spec from(decoder(FRJ), gleam@dynamic:dynamic_()) -> {ok, FRJ} |
{error, list(gleam@dynamic:decode_error())}.
from(Decoder, Data) ->
(erlang:element(2, Decoder))(Data).
-spec map(decoder(FSN), fun((FSN) -> FSP)) -> decoder(FSP).
map(Decoder, Transformer) ->
{decoder, fun(D) -> case (erlang:element(2, Decoder))(D) of
{ok, A} ->
{ok, Transformer(A)};
{error, E} ->
{error, E}
end end}.
-spec map_errors(
decoder(FSR),
fun((list(gleam@dynamic:decode_error())) -> list(gleam@dynamic:decode_error()))
) -> decoder(FSR).
map_errors(Decoder, Transformer) ->
{decoder, fun(D) -> case (erlang:element(2, Decoder))(D) of
{ok, A} ->
{ok, A};
{error, E} ->
{error, Transformer(E)}
end end}.
-spec then(decoder(FSZ), fun((FSZ) -> decoder(FTB))) -> decoder(FTB).
then(Decoder, Next) ->
{decoder, fun(D) -> case (erlang:element(2, Decoder))(D) of
{ok, A} ->
_pipe = Next(A),
from(_pipe, D);
{error, E} ->
{error, E}
end end}.
-spec list(decoder(FRM)) -> decoder(list(FRM)).
list(Item) ->
{decoder, gleam@dynamic:list(erlang:element(2, Item))}.
-spec field(decoder(fun((FRD) -> FRE)), any(), decoder(FRD)) -> decoder(FRE).
field(Decoder, Field_name, Field_decoder) ->
{decoder,
fun(Data) ->
Constructor = (erlang:element(2, Decoder))(Data),
Data@1 = (gleam@dynamic:field(
Field_name,
fun(_capture) -> from(Field_decoder, _capture) end
))(Data),
case {Constructor, Data@1} of
{{ok, Constructor@1}, {ok, Data@2}} ->
{ok, Constructor@1(Data@2)};
{{error, E1}, {error, E2}} ->
{error, lists:append(E1, E2)};
{_, {error, Errors}} ->
{error, Errors};
{{error, Errors}, _} ->
{error, Errors}
end
end}.
-spec dict(decoder(FRQ), decoder(FRS)) -> decoder(gleam@dict:dict(FRQ, FRS)).
dict(Key, Value) ->
{decoder,
gleam@dynamic:dict(erlang:element(2, Key), erlang:element(2, Value))}.
-spec optional(decoder(FRX)) -> decoder(gleam@option:option(FRX)).
optional(Item) ->
{decoder, gleam@dynamic:optional(erlang:element(2, Item))}.
-spec collapse_errors(decoder(FSW), binary()) -> decoder(FSW).
collapse_errors(Decoder, Name) ->
{decoder, fun(D) -> case (erlang:element(2, Decoder))(D) of
{ok, A} ->
{ok, A};
{error, _} ->
{error,
[{decode_error, Name, gleam@dynamic:classify(D), []}]}
end end}.
-spec run_decoders(gleam@dynamic:dynamic_(), list(decoder(FTI))) -> {ok, FTI} |
{error, list(gleam@dynamic:decode_error())}.
run_decoders(Data, Decoders) ->
case Decoders of
[] ->
{error,
[{decode_error,
<<"nothing"/utf8>>,
gleam@dynamic:classify(Data),
[]}]};
[Decoder] ->
from(Decoder, Data);
[Decoder@1 | Decoders@1] ->
case from(Decoder@1, Data) of
{ok, Value} ->
{ok, Value};
{error, _} ->
run_decoders(Data, Decoders@1)
end
end.
-spec one_of(list(decoder(FTE))) -> decoder(FTE).
one_of(Decoders) ->
{decoder, fun(D) -> run_decoders(D, Decoders) end}.
-spec push_path(list(gleam@dynamic:decode_error()), any()) -> list(gleam@dynamic:decode_error()).
push_path(Errors, Key) ->
Key@1 = gleam@dynamic:from(Key),
Decoder = gleam@dynamic:any(
[fun gleam@dynamic:string/1,
fun(X) ->
gleam@result:map(
gleam@dynamic:int(X),
fun gleam@int:to_string/1
)
end]
),
Key@3 = case Decoder(Key@1) of
{ok, Key@2} ->
Key@2;
{error, _} ->
<<<<"<"/utf8, (gleam@dynamic:classify(Key@1))/binary>>/binary,
">"/utf8>>
end,
gleam@list:map(
Errors,
fun(Error) ->
erlang:setelement(4, Error, [Key@3 | erlang:element(4, Error)])
end
).
-spec index(
any(),
fun((gleam@dynamic:dynamic_()) -> {ok, FSH} |
{error, list(gleam@dynamic:decode_error())}),
gleam@dynamic:dynamic_()
) -> {ok, FSH} | {error, list(gleam@dynamic:decode_error())}.
index(Key, Inner, Data) ->
case decode_ffi:index(Data, Key) of
{ok, Data@1} ->
case Inner(Data@1) of
{ok, Data@2} ->
{ok, Data@2};
{error, Errors} ->
{error, push_path(Errors, Key)}
end;
{error, Kind} ->
{error, [{decode_error, Kind, gleam@dynamic:classify(Data), []}]}
end.
-spec at(list(any()), decoder(FSD)) -> decoder(FSD).
at(Path, Inner) ->
{decoder,
fun(Data) ->
Decoder = gleam@list:fold_right(
Path,
erlang:element(2, Inner),
fun(Dyn_decoder, Segment) ->
fun(_capture) -> index(Segment, Dyn_decoder, _capture) end
end
),
Decoder(Data)
end}.
-spec fail(binary()) -> decoder(any()).
fail(Expected) ->
{decoder,
fun(D) ->
{error, [{decode_error, Expected, gleam@dynamic:classify(D), []}]}
end}.