Packages
Typed distributed messaging for Gleam on the BEAM.
Current section
Files
Jump to
Current section
Files
src/distribute@codec.erl
-module(distribute@codec).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/distribute/codec.gleam").
-export([encode/2, decode/2, decode_sized/2, to_decoder/1, string_sized_decoder/0, string_decoder/0, int_encoder/0, int_sized_decoder/0, int_decoder/0, float_encoder/0, float_sized_decoder/0, float_decoder/0, bool_encoder/0, bool_sized_decoder/0, bool_decoder/0, bitarray_encoder/0, bitarray_sized_decoder/0, bitarray_decoder/0, nil_encoder/0, nil_sized_decoder/0, nil_decoder/0, subject_encoder/0, subject_sized_decoder/0, subject_decoder/0, int/0, string_encoder/0, string/0, float/0, bool/0, bitarray/0, nil/0, subject/0, map/3, decode_error_to_string/1, encode_error_to_string/1, list/1, list_decoder/1, list_sized_decoder/1, list_encoder/1]).
-export_type([encode_error/0, decode_error/0, codec/1]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-type encode_error() :: {invalid_value, binary()} |
{encode_failed, binary()} |
{value_too_large, binary()}.
-type decode_error() :: {invalid_binary, binary()} |
{type_mismatch, binary()} |
{decode_failed, binary()} |
{insufficient_data, binary()} |
decode_timeout |
{tag_mismatch, binary(), binary()} |
{version_mismatch, integer(), integer()}.
-type codec(FLQ) :: {codec,
fun((FLQ) -> {ok, bitstring()} | {error, encode_error()}),
fun((bitstring()) -> {ok, FLQ} | {error, decode_error()}),
fun((bitstring()) -> {ok, {FLQ, bitstring()}} | {error, decode_error()})}.
-file("src/distribute/codec.gleam", 55).
-spec encode(fun((FMA) -> {ok, bitstring()} | {error, encode_error()}), FMA) -> {ok,
bitstring()} |
{error, encode_error()}.
encode(Encoder, Value) ->
Encoder(Value).
-file("src/distribute/codec.gleam", 59).
-spec decode(
fun((bitstring()) -> {ok, FME} | {error, decode_error()}),
bitstring()
) -> {ok, FME} | {error, decode_error()}.
decode(Decoder, Data) ->
Decoder(Data).
-file("src/distribute/codec.gleam", 63).
-spec decode_sized(
fun((bitstring()) -> {ok, {FMI, bitstring()}} | {error, decode_error()}),
bitstring()
) -> {ok, {FMI, bitstring()}} | {error, decode_error()}.
decode_sized(Decoder, Data) ->
Decoder(Data).
-file("src/distribute/codec.gleam", 71).
?DOC(" Turn a `SizedDecoder` into a `Decoder` (drops remaining bytes).\n").
-spec to_decoder(
fun((bitstring()) -> {ok, {FMM, bitstring()}} | {error, decode_error()})
) -> fun((bitstring()) -> {ok, FMM} | {error, decode_error()}).
to_decoder(Sized) ->
fun(Data) -> case Sized(Data) of
{ok, {Value, _}} ->
{ok, Value};
{error, E} ->
{error, E}
end end.
-file("src/distribute/codec.gleam", 95).
-spec string_sized_decoder() -> fun((bitstring()) -> {ok,
{binary(), bitstring()}} |
{error, decode_error()}).
string_sized_decoder() ->
fun(Data) -> case Data of
<<Len:16, Rest/binary>> ->
Rest_size = erlang:byte_size(Rest),
case Rest_size >= Len of
false ->
{error, {insufficient_data, <<"string"/utf8>>}};
true ->
gleam@result:'try'(
begin
_pipe = gleam_stdlib:bit_array_slice(
Rest,
0,
Len
),
gleam@result:replace_error(
_pipe,
{insufficient_data, <<"string slice"/utf8>>}
)
end,
fun(Str_bytes) ->
gleam@result:'try'(
begin
_pipe@1 = gleam@bit_array:to_string(
Str_bytes
),
gleam@result:replace_error(
_pipe@1,
{invalid_binary,
<<"invalid UTF-8"/utf8>>}
)
end,
fun(S) ->
Remaining = case gleam_stdlib:bit_array_slice(
Rest,
Len,
Rest_size - Len
) of
{ok, R} ->
R;
{error, _} ->
<<>>
end,
{ok, {S, Remaining}}
end
)
end
)
end;
_ ->
{error,
{invalid_binary, <<"missing string length prefix"/utf8>>}}
end end.
-file("src/distribute/codec.gleam", 124).
-spec string_decoder() -> fun((bitstring()) -> {ok, binary()} |
{error, decode_error()}).
string_decoder() ->
to_decoder(string_sized_decoder()).
-file("src/distribute/codec.gleam", 132).
-spec int_encoder() -> fun((integer()) -> {ok, bitstring()} |
{error, encode_error()}).
int_encoder() ->
fun(I) -> {ok, <<I:64>>} end.
-file("src/distribute/codec.gleam", 136).
-spec int_sized_decoder() -> fun((bitstring()) -> {ok, {integer(), bitstring()}} |
{error, decode_error()}).
int_sized_decoder() ->
fun(Data) -> case Data of
<<I:64/signed, Rest/binary>> ->
{ok, {I, Rest}};
_ ->
{error, {invalid_binary, <<"int64"/utf8>>}}
end end.
-file("src/distribute/codec.gleam", 145).
-spec int_decoder() -> fun((bitstring()) -> {ok, integer()} |
{error, decode_error()}).
int_decoder() ->
to_decoder(int_sized_decoder()).
-file("src/distribute/codec.gleam", 153).
-spec float_encoder() -> fun((float()) -> {ok, bitstring()} |
{error, encode_error()}).
float_encoder() ->
fun(F) -> {ok, <<F/float>>} end.
-file("src/distribute/codec.gleam", 157).
-spec float_sized_decoder() -> fun((bitstring()) -> {ok, {float(), bitstring()}} |
{error, decode_error()}).
float_sized_decoder() ->
fun(Data) -> case Data of
<<F/float, Rest/binary>> ->
{ok, {F, Rest}};
_ ->
{error, {invalid_binary, <<"float64"/utf8>>}}
end end.
-file("src/distribute/codec.gleam", 166).
-spec float_decoder() -> fun((bitstring()) -> {ok, float()} |
{error, decode_error()}).
float_decoder() ->
to_decoder(float_sized_decoder()).
-file("src/distribute/codec.gleam", 174).
-spec bool_encoder() -> fun((boolean()) -> {ok, bitstring()} |
{error, encode_error()}).
bool_encoder() ->
fun(B) -> case B of
true ->
{ok, <<1>>};
false ->
{ok, <<0>>}
end end.
-file("src/distribute/codec.gleam", 183).
-spec bool_sized_decoder() -> fun((bitstring()) -> {ok,
{boolean(), bitstring()}} |
{error, decode_error()}).
bool_sized_decoder() ->
fun(Data) -> case Data of
<<1, Rest/binary>> ->
{ok, {true, Rest}};
<<0, Rest@1/binary>> ->
{ok, {false, Rest@1}};
_ ->
{error, {invalid_binary, <<"bool"/utf8>>}}
end end.
-file("src/distribute/codec.gleam", 193).
-spec bool_decoder() -> fun((bitstring()) -> {ok, boolean()} |
{error, decode_error()}).
bool_decoder() ->
to_decoder(bool_sized_decoder()).
-file("src/distribute/codec.gleam", 201).
-spec bitarray_encoder() -> fun((bitstring()) -> {ok, bitstring()} |
{error, encode_error()}).
bitarray_encoder() ->
fun(Bytes) ->
Len = erlang:byte_size(Bytes),
{ok, <<Len:32, Bytes/bitstring>>}
end.
-file("src/distribute/codec.gleam", 208).
-spec bitarray_sized_decoder() -> fun((bitstring()) -> {ok,
{bitstring(), bitstring()}} |
{error, decode_error()}).
bitarray_sized_decoder() ->
fun(Data) -> case Data of
<<Len:32, Rest/binary>> ->
Rest_size = erlang:byte_size(Rest),
case Rest_size >= Len of
false ->
{error, {insufficient_data, <<"bitarray"/utf8>>}};
true ->
gleam@result:'try'(
begin
_pipe = gleam_stdlib:bit_array_slice(
Rest,
0,
Len
),
gleam@result:replace_error(
_pipe,
{insufficient_data,
<<"bitarray slice"/utf8>>}
)
end,
fun(Bytes) ->
Remaining = case gleam_stdlib:bit_array_slice(
Rest,
Len,
Rest_size - Len
) of
{ok, R} ->
R;
{error, _} ->
<<>>
end,
{ok, {Bytes, Remaining}}
end
)
end;
_ ->
{error, {invalid_binary, <<"bitarray length prefix"/utf8>>}}
end end.
-file("src/distribute/codec.gleam", 233).
-spec bitarray_decoder() -> fun((bitstring()) -> {ok, bitstring()} |
{error, decode_error()}).
bitarray_decoder() ->
to_decoder(bitarray_sized_decoder()).
-file("src/distribute/codec.gleam", 272).
-spec encode_list_elements(
list(FNQ),
fun((FNQ) -> {ok, bitstring()} | {error, encode_error()}),
bitstring()
) -> {ok, bitstring()} | {error, encode_error()}.
encode_list_elements(Items, Enc, Acc) ->
case Items of
[] ->
{ok, Acc};
[Head | Tail] ->
gleam@result:'try'(
Enc(Head),
fun(Bytes) ->
encode_list_elements(
Tail,
Enc,
gleam@bit_array:append(Acc, Bytes)
)
end
)
end.
-file("src/distribute/codec.gleam", 308).
-spec nil_encoder() -> fun((nil) -> {ok, bitstring()} | {error, encode_error()}).
nil_encoder() ->
fun(_) -> {ok, <<>>} end.
-file("src/distribute/codec.gleam", 312).
-spec nil_sized_decoder() -> fun((bitstring()) -> {ok, {nil, bitstring()}} |
{error, decode_error()}).
nil_sized_decoder() ->
fun(Data) -> {ok, {nil, Data}} end.
-file("src/distribute/codec.gleam", 316).
-spec nil_decoder() -> fun((bitstring()) -> {ok, nil} | {error, decode_error()}).
nil_decoder() ->
fun(_) -> {ok, nil} end.
-file("src/distribute/codec.gleam", 332).
?DOC(
" Encode a `Subject(BitArray)` via `term_to_binary`. The PID\n"
" inside carries node info, so it routes back cross-node.\n"
).
-spec subject_encoder() -> fun((gleam@erlang@process:subject(bitstring())) -> {ok,
bitstring()} |
{error, encode_error()}).
subject_encoder() ->
fun(Sub) ->
Bytes = distribute_ffi_utils:encode_subject(Sub),
Len = erlang:byte_size(Bytes),
{ok, <<Len:32, Bytes/bitstring>>}
end.
-file("src/distribute/codec.gleam", 340).
-spec subject_sized_decoder() -> fun((bitstring()) -> {ok,
{gleam@erlang@process:subject(bitstring()), bitstring()}} |
{error, decode_error()}).
subject_sized_decoder() ->
fun(Data) -> case Data of
<<Len:32, Rest/binary>> ->
Rest_size = erlang:byte_size(Rest),
case Rest_size >= Len of
false ->
{error, {insufficient_data, <<"subject"/utf8>>}};
true ->
case gleam_stdlib:bit_array_slice(Rest, 0, Len) of
{ok, Subject_bytes} ->
case distribute_ffi_utils:decode_subject_safe(
Subject_bytes
) of
{ok, Sub} ->
Remaining = case gleam_stdlib:bit_array_slice(
Rest,
Len,
Rest_size - Len
) of
{ok, R} ->
R;
{error, _} ->
<<>>
end,
{ok, {Sub, Remaining}};
{error, nil} ->
{error,
{decode_failed,
<<"invalid subject binary"/utf8>>}}
end;
{error, _} ->
{error,
{insufficient_data,
<<"subject slice"/utf8>>}}
end
end;
_ ->
{error, {invalid_binary, <<"subject length prefix"/utf8>>}}
end end.
-file("src/distribute/codec.gleam", 372).
-spec subject_decoder() -> fun((bitstring()) -> {ok,
gleam@erlang@process:subject(bitstring())} |
{error, decode_error()}).
subject_decoder() ->
to_decoder(subject_sized_decoder()).
-file("src/distribute/codec.gleam", 388).
-spec int() -> codec(integer()).
int() ->
{codec, int_encoder(), int_decoder(), int_sized_decoder()}.
-file("src/distribute/codec.gleam", 84).
-spec string_encoder() -> fun((binary()) -> {ok, bitstring()} |
{error, encode_error()}).
string_encoder() ->
fun(S) ->
Bytes = gleam_stdlib:identity(S),
Len = erlang:byte_size(Bytes),
case Len > 65535 of
true ->
{error,
{value_too_large,
<<"string length "/utf8,
(erlang:integer_to_binary(Len))/binary>>}};
false ->
{ok, <<Len:16, Bytes/bitstring>>}
end
end.
-file("src/distribute/codec.gleam", 380).
-spec string() -> codec(binary()).
string() ->
{codec, string_encoder(), string_decoder(), string_sized_decoder()}.
-file("src/distribute/codec.gleam", 396).
-spec float() -> codec(float()).
float() ->
{codec, float_encoder(), float_decoder(), float_sized_decoder()}.
-file("src/distribute/codec.gleam", 404).
-spec bool() -> codec(boolean()).
bool() ->
{codec, bool_encoder(), bool_decoder(), bool_sized_decoder()}.
-file("src/distribute/codec.gleam", 412).
-spec bitarray() -> codec(bitstring()).
bitarray() ->
{codec, bitarray_encoder(), bitarray_decoder(), bitarray_sized_decoder()}.
-file("src/distribute/codec.gleam", 420).
-spec nil() -> codec(nil).
nil() ->
{codec, nil_encoder(), nil_decoder(), nil_sized_decoder()}.
-file("src/distribute/codec.gleam", 437).
?DOC(" Subject codec, for the request/response pattern.\n").
-spec subject() -> codec(gleam@erlang@process:subject(bitstring())).
subject() ->
{codec, subject_encoder(), subject_decoder(), subject_sized_decoder()}.
-file("src/distribute/codec.gleam", 455).
?DOC(
" Transform a codec. `wrap` runs after decoding, `unwrap` before encoding.\n"
"\n"
" ```gleam\n"
" type UserId { UserId(Int) }\n"
"\n"
" let user_id = codec.map(codec.int(), UserId, fn(uid) {\n"
" let UserId(n) = uid\n"
" n\n"
" })\n"
" ```\n"
).
-spec map(codec(FPA), fun((FPA) -> FPC), fun((FPC) -> FPA)) -> codec(FPC).
map(C, Wrap, Unwrap) ->
{codec,
fun(Value) -> (erlang:element(2, C))(Unwrap(Value)) end,
fun(Data) -> case (erlang:element(3, C))(Data) of
{ok, Val} ->
{ok, Wrap(Val)};
{error, E} ->
{error, E}
end end,
fun(Data@1) -> case (erlang:element(4, C))(Data@1) of
{ok, {Val@1, Rest}} ->
{ok, {Wrap(Val@1), Rest}};
{error, E@1} ->
{error, E@1}
end end}.
-file("src/distribute/codec.gleam", 477).
-spec decode_error_to_string(decode_error()) -> binary().
decode_error_to_string(Error) ->
case Error of
{invalid_binary, Msg} ->
<<"Invalid binary: "/utf8, Msg/binary>>;
{type_mismatch, Msg@1} ->
<<"Type mismatch: "/utf8, Msg@1/binary>>;
{decode_failed, Msg@2} ->
<<"Decode failed: "/utf8, Msg@2/binary>>;
{insufficient_data, Msg@3} ->
<<"Insufficient data: "/utf8, Msg@3/binary>>;
decode_timeout ->
<<"Decode timeout"/utf8>>;
{tag_mismatch, Expected, Got} ->
<<<<<<<<"Tag mismatch: expected '"/utf8, Expected/binary>>/binary,
"', got '"/utf8>>/binary,
Got/binary>>/binary,
"'"/utf8>>;
{version_mismatch, Expected@1, Got@1} ->
<<<<<<"Version mismatch: expected "/utf8,
(erlang:integer_to_binary(Expected@1))/binary>>/binary,
", got "/utf8>>/binary,
(erlang:integer_to_binary(Got@1))/binary>>
end.
-file("src/distribute/codec.gleam", 494).
-spec encode_error_to_string(encode_error()) -> binary().
encode_error_to_string(Error) ->
case Error of
{invalid_value, Msg} ->
<<"Invalid value: "/utf8, Msg/binary>>;
{encode_failed, Msg@1} ->
<<"Encode failed: "/utf8, Msg@1/binary>>;
{value_too_large, Msg@2} ->
<<"Value too large: "/utf8, Msg@2/binary>>
end.
-file("src/distribute/codec.gleam", 428).
-spec list(codec(FOU)) -> codec(list(FOU)).
list(Element) ->
{codec,
list_encoder(erlang:element(2, Element)),
list_decoder(erlang:element(4, Element)),
list_sized_decoder(erlang:element(4, Element))}.
-file("src/distribute/codec.gleam", 268).
-spec list_decoder(
fun((bitstring()) -> {ok, {FNM, bitstring()}} | {error, decode_error()})
) -> fun((bitstring()) -> {ok, list(FNM)} | {error, decode_error()}).
list_decoder(Element_decoder) ->
to_decoder(list_sized_decoder(Element_decoder)).
-file("src/distribute/codec.gleam", 256).
-spec list_sized_decoder(
fun((bitstring()) -> {ok, {FNI, bitstring()}} | {error, decode_error()})
) -> fun((bitstring()) -> {ok, {list(FNI), bitstring()}} |
{error, decode_error()}).
list_sized_decoder(Element_decoder) ->
fun(Data) -> case Data of
<<Count:16, Rest/binary>> ->
decode_list_elements(Rest, Element_decoder, Count, []);
_ ->
{error, {invalid_binary, <<"list length prefix"/utf8>>}}
end end.
-file("src/distribute/codec.gleam", 286).
-spec decode_list_elements(
bitstring(),
fun((bitstring()) -> {ok, {FNV, bitstring()}} | {error, decode_error()}),
integer(),
list(FNV)
) -> {ok, {list(FNV), bitstring()}} | {error, decode_error()}.
decode_list_elements(Data, Dec, Remaining, Acc) ->
case Remaining of
0 ->
{ok, {lists:reverse(Acc), Data}};
_ ->
case Dec(Data) of
{ok, {Element, Rest}} ->
decode_list_elements(
Rest,
Dec,
Remaining - 1,
[Element | Acc]
);
{error, E} ->
{error, E}
end
end.
-file("src/distribute/codec.gleam", 241).
-spec list_encoder(fun((FNE) -> {ok, bitstring()} | {error, encode_error()})) -> fun((list(FNE)) -> {ok,
bitstring()} |
{error, encode_error()}).
list_encoder(Element_encoder) ->
fun(Items) ->
Len = erlang:length(Items),
case Len > 65535 of
true ->
{error,
{value_too_large,
<<"list length "/utf8,
(erlang:integer_to_binary(Len))/binary>>}};
false ->
gleam@result:'try'(
encode_list_elements(Items, Element_encoder, <<>>),
fun(Body) -> {ok, <<Len:16, Body/bitstring>>} end
)
end
end.