Packages

A Protocol Buffers library for Gleam, providing encoding and decoding of protobuf messages.

Current section

Files

Jump to
protozoa src protozoa@decode.erl
Raw

src/protozoa@decode.erl

-module(protozoa@decode).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/protozoa/decode.gleam").
-export([success/1, from_field_dict/1, fail/3, field/2, optional_field/2, field_with_default/3, repeated_field/2, varint_field/1, string_field/1, bytes_field/1, float_field/1, double_field/1, bool_field/1, int32_field/1, int64_field/1, uint32_field/1, uint64_field/1, fixed32_int_field/1, fixed64_int_field/1, sfixed32_field/1, sfixed64_field/1, int32/1, int32_with_default/2, int64_with_default/2, int64/1, uint32/1, uint32_with_default/2, uint64/1, uint64_with_default/2, string/1, string_with_default/2, bool/1, bool_with_default/2, bytes/1, float/1, double/1, fixed32/1, fixed64/1, sfixed32/1, sfixed64/1, repeated_int32/1, repeated_string/1, then/2, map/2, run/2, message_field/2, nested_message/2, optional_nested_message/2, decode_zigzag/1, sint32/1, sint64/1]).
-export_type([decode_error/0, field/0, proto_value/0, decoder/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.
?MODULEDOC(
" Protocol Buffer Decode Module \n"
"\n"
" This module provides a composable, type-safe API for decoding Protocol Buffer binary data\n"
" into Gleam values. It follows the gleam/dynamic/decode pattern for familiar composability\n"
" and error handling, making it easy to work with protobuf data in Gleam applications.\n"
"\n"
" ## Design Philosophy\n"
"\n"
" - **Composable decoders**: Small, focused decoder functions that can be combined\n"
" - **Type safety**: Compile-time guarantees about decoded data structure\n"
" - **Error handling**: Clear error messages for debugging decode failures\n"
" - **Performance**: Efficient binary parsing with minimal allocations\n"
" - **Gleam idioms**: Follows Result and Option patterns familiar to Gleam developers\n"
"\n"
" ## Capabilities\n"
"\n"
" - **All proto3 types**: Scalars (int32, string, bool), messages, enums, repeated fields\n"
" - **Advanced features**: Oneofs, maps, optional fields, nested messages \n"
" - **Wire format parsing**: Handles protobuf binary wire format correctly\n"
" - **Field-level decoding**: Individual field decoders for fine-grained control\n"
" - **Message-level decoding**: Complete message decoders with field validation\n"
" - **Default values**: Proper proto3 default value handling\n"
"\n"
" ## Usage Pattern\n"
"\n"
" Generated code uses this module to create message-specific decoder functions:\n"
" ```gleam\n"
" pub fn decode_user(data: BitArray) -> Result(User, DecodeError) {\n"
" decode.message(data, user_decoder())\n"
" }\n"
"\n"
" fn user_decoder() -> decode.Decoder(User) {\n"
" decode.into({\n"
" use name <- decode.field(\"name\", decode.string_field(1))\n"
" use age <- decode.field(\"age\", decode.int32_field(2)) \n"
" User(name: name, age: age)\n"
" })\n"
" }\n"
" ```\n"
"\n"
" ## Error Handling \n"
"\n"
" All decode functions return `Result(T, DecodeError)` with descriptive error messages\n"
" for debugging binary format issues, missing required fields, or type mismatches.\n"
).
-type decode_error() :: {decode_error, binary(), binary(), list(binary())} |
{field_not_found, integer()}.
-type field() :: {field, integer(), protozoa@wire:wire_type(), bitstring()}.
-type proto_value() :: {proto_message, list(field())} |
{proto_varint, integer()} |
{proto_fixed32, bitstring()} |
{proto_fixed64, bitstring()} |
{proto_length_delimited, bitstring()}.
-opaque decoder(NWT) :: {decoder,
fun((gleam@dict:dict(integer(), list(field()))) -> {ok, NWT} |
{error, list(decode_error())})}.
-file("src/protozoa/decode.gleam", 119).
?DOC(
" Create a decoder that always succeeds with a value.\n"
" Useful for providing default values or building complex decoders.\n"
" \n"
" ## Examples\n"
" \n"
" ```gleam\n"
" success(42) // Always returns Ok(42)\n"
" ```\n"
).
-spec success(NWZ) -> decoder(NWZ).
success(Value) ->
{decoder, fun(_) -> {ok, Value} end}.
-file("src/protozoa/decode.gleam", 134).
?DOC(
" Create a decoder from a function that takes a dict of fields.\n"
" This is useful for creating custom decoders for complex types like oneofs.\n"
" \n"
" ## Examples\n"
" \n"
" ```gleam\n"
" from_field_dict(fn(fields) {\n"
" // Custom decoding logic using dict.get\n"
" Ok(value)\n"
" })\n"
" ```\n"
).
-spec from_field_dict(
fun((gleam@dict:dict(integer(), list(field()))) -> {ok, NXE} |
{error, list(decode_error())})
) -> decoder(NXE).
from_field_dict(F) ->
{decoder, F}.
-file("src/protozoa/decode.gleam", 148).
?DOC(
" Create a decoder that always fails with an error message.\n"
" Useful for handling unsupported fields or validation errors.\n"
" \n"
" ## Examples\n"
" \n"
" ```gleam\n"
" fail(\"Unsupported field type\") // Always returns Error\n"
" ```\n"
).
-spec fail(binary(), binary(), list(binary())) -> decoder(any()).
fail(Expected, Found, Path) ->
{decoder, fun(_) -> {error, [{decode_error, Expected, Found, Path}]} end}.
-file("src/protozoa/decode.gleam", 161).
?DOC(
" Decode a required field with a specific decoder.\n"
" Returns an error if the field is not present.\n"
" \n"
" ## Examples\n"
" \n"
" ```gleam\n"
" field(1, varint_field) // Decodes field 1 as a varint\n"
" field(2, string_field) // Decodes field 2 as a string\n"
" ```\n"
).
-spec field(integer(), fun((field()) -> {ok, NXM} | {error, decode_error()})) -> decoder(NXM).
field(Number, Decoder) ->
{decoder, fun(Fields) -> case gleam_stdlib:map_get(Fields, Number) of
{ok, [Field | _]} ->
_pipe = Decoder(Field),
gleam@result:map_error(_pipe, fun(Err) -> [Err] end);
{ok, []} ->
{error, [{field_not_found, Number}]};
{error, _} ->
{error, [{field_not_found, Number}]}
end end}.
-file("src/protozoa/decode.gleam", 185).
?DOC(
" Decode an optional field.\n"
" Returns Ok(Ok(value)) if the field is present and valid,\n"
" Ok(Error(Nil)) if the field is missing or invalid.\n"
" \n"
" ## Examples\n"
" \n"
" ```gleam\n"
" optional_field(1, varint_field) // Decodes optional field 1\n"
" ```\n"
).
-spec optional_field(
integer(),
fun((field()) -> {ok, NXQ} | {error, decode_error()})
) -> decoder({ok, NXQ} | {error, nil}).
optional_field(Number, Decoder) ->
{decoder, fun(Fields) -> case gleam_stdlib:map_get(Fields, Number) of
{ok, [Field | _]} ->
case Decoder(Field) of
{ok, Value} ->
{ok, {ok, Value}};
{error, _} ->
{ok, {error, nil}}
end;
{ok, []} ->
{ok, {error, nil}};
{error, _} ->
{ok, {error, nil}}
end end}.
-file("src/protozoa/decode.gleam", 211).
?DOC(
" Decode a field with a default value.\n"
" Returns the decoded value if present, otherwise returns the default.\n"
" \n"
" ## Examples\n"
" \n"
" ```gleam\n"
" field_with_default(1, varint_field, 0) // Returns 0 if field 1 is missing\n"
" ```\n"
).
-spec field_with_default(
integer(),
fun((field()) -> {ok, NXW} | {error, decode_error()}),
NXW
) -> decoder(NXW).
field_with_default(Number, Decoder, Default) ->
{decoder, fun(Fields) -> case gleam_stdlib:map_get(Fields, Number) of
{ok, [Field | _]} ->
case Decoder(Field) of
{ok, Value} ->
{ok, Value};
{error, _} ->
{ok, Default}
end;
{ok, []} ->
{ok, Default};
{error, _} ->
{ok, Default}
end end}.
-file("src/protozoa/decode.gleam", 239).
?DOC(
" Decode all fields with a given number (for repeated fields).\n"
" Returns a list of all decoded values for the field number.\n"
" Collects all errors encountered during decoding.\n"
" \n"
" ## Examples\n"
" \n"
" ```gleam\n"
" repeated_field(1, varint_field) // Decodes all field 1 occurrences\n"
" ```\n"
).
-spec repeated_field(
integer(),
fun((field()) -> {ok, NYA} | {error, decode_error()})
) -> decoder(list(NYA)).
repeated_field(Number, Decoder) ->
{decoder, fun(Fields) -> case gleam_stdlib:map_get(Fields, Number) of
{ok, Field_list} ->
Results = gleam@list:map(Field_list, Decoder),
Errors = gleam@list:filter_map(
Results,
fun(Result) -> case Result of
{error, Err} ->
{ok, Err};
{ok, _} ->
{error, nil}
end end
),
case Errors of
[] ->
Values = gleam@list:filter_map(
Results,
fun(Result@1) -> case Result@1 of
{ok, Value} ->
{ok, Value};
{error, _} ->
{error, nil}
end end
),
{ok, Values};
_ ->
{error, Errors}
end;
{error, _} ->
{ok, []}
end end}.
-file("src/protozoa/decode.gleam", 278).
?DOC(false).
-spec varint_field(field()) -> {ok, integer()} | {error, decode_error()}.
varint_field(Field) ->
case erlang:element(3, Field) of
varint ->
case erlang:element(4, Field) of
<<Value:64>> ->
{ok, Value};
_ ->
{error,
{decode_error,
<<"valid varint data"/utf8>>,
<<"invalid varint data"/utf8>>,
[]}}
end;
_ ->
{error,
{decode_error,
<<"varint wire type"/utf8>>,
<<"non-varint wire type"/utf8>>,
[]}}
end.
-file("src/protozoa/decode.gleam", 292).
?DOC(false).
-spec string_field(field()) -> {ok, binary()} | {error, decode_error()}.
string_field(Field) ->
case erlang:element(3, Field) of
length_delimited ->
_pipe = gleam@bit_array:to_string(erlang:element(4, Field)),
gleam@result:map_error(
_pipe,
fun(_) ->
{decode_error,
<<"valid UTF-8 string"/utf8>>,
<<"invalid UTF-8 bytes"/utf8>>,
[]}
end
);
_ ->
{error,
{decode_error,
<<"length-delimited wire type"/utf8>>,
<<"non-length-delimited wire type"/utf8>>,
[]}}
end.
-file("src/protozoa/decode.gleam", 313).
?DOC(false).
-spec bytes_field(field()) -> {ok, bitstring()} | {error, decode_error()}.
bytes_field(Field) ->
case erlang:element(3, Field) of
length_delimited ->
{ok, erlang:element(4, Field)};
_ ->
{error,
{decode_error,
<<"length-delimited wire type"/utf8>>,
<<"non-length-delimited wire type"/utf8>>,
[]}}
end.
-file("src/protozoa/decode.gleam", 329).
?DOC(false).
-spec float_field(field()) -> {ok, float()} | {error, decode_error()}.
float_field(Field) ->
case erlang:element(3, Field) of
fixed32 ->
case erlang:element(4, Field) of
<<Value:32/float-little>> ->
{ok, Value};
_ ->
{error,
{decode_error,
<<"valid 32-bit float data"/utf8>>,
<<"invalid float data"/utf8>>,
[]}}
end;
_ ->
{error,
{decode_error,
<<"fixed32 wire type"/utf8>>,
<<"non-fixed32 wire type"/utf8>>,
[]}}
end.
-file("src/protozoa/decode.gleam", 346).
?DOC(false).
-spec double_field(field()) -> {ok, float()} | {error, decode_error()}.
double_field(Field) ->
case erlang:element(3, Field) of
fixed64 ->
case erlang:element(4, Field) of
<<Value:64/float-little>> ->
{ok, Value};
_ ->
{error,
{decode_error,
<<"valid 64-bit double data"/utf8>>,
<<"invalid double data"/utf8>>,
[]}}
end;
_ ->
{error,
{decode_error,
<<"fixed64 wire type"/utf8>>,
<<"non-fixed64 wire type"/utf8>>,
[]}}
end.
-file("src/protozoa/decode.gleam", 363).
?DOC(false).
-spec bool_field(field()) -> {ok, boolean()} | {error, decode_error()}.
bool_field(Field) ->
gleam@result:'try'(varint_field(Field), fun(Value) -> {ok, Value /= 0} end).
-file("src/protozoa/decode.gleam", 370).
?DOC(false).
-spec int32_field(field()) -> {ok, integer()} | {error, decode_error()}.
int32_field(Field) ->
varint_field(Field).
-file("src/protozoa/decode.gleam", 376).
?DOC(false).
-spec int64_field(field()) -> {ok, integer()} | {error, decode_error()}.
int64_field(Field) ->
varint_field(Field).
-file("src/protozoa/decode.gleam", 382).
?DOC(false).
-spec uint32_field(field()) -> {ok, integer()} | {error, decode_error()}.
uint32_field(Field) ->
varint_field(Field).
-file("src/protozoa/decode.gleam", 388).
?DOC(false).
-spec uint64_field(field()) -> {ok, integer()} | {error, decode_error()}.
uint64_field(Field) ->
varint_field(Field).
-file("src/protozoa/decode.gleam", 394).
?DOC(false).
-spec fixed32_int_field(field()) -> {ok, integer()} | {error, decode_error()}.
fixed32_int_field(Field) ->
case erlang:element(3, Field) of
fixed32 ->
case erlang:element(4, Field) of
<<Value:32/little>> ->
{ok, Value};
_ ->
{error,
{decode_error,
<<"valid 32-bit integer data"/utf8>>,
<<"invalid fixed32 data"/utf8>>,
[]}}
end;
_ ->
{error,
{decode_error,
<<"fixed32 wire type"/utf8>>,
<<"non-fixed32 wire type"/utf8>>,
[]}}
end.
-file("src/protozoa/decode.gleam", 411).
?DOC(false).
-spec fixed64_int_field(field()) -> {ok, integer()} | {error, decode_error()}.
fixed64_int_field(Field) ->
case erlang:element(3, Field) of
fixed64 ->
case erlang:element(4, Field) of
<<Value:64/little>> ->
{ok, Value};
_ ->
{error,
{decode_error,
<<"valid 64-bit integer data"/utf8>>,
<<"invalid fixed64 data"/utf8>>,
[]}}
end;
_ ->
{error,
{decode_error,
<<"fixed64 wire type"/utf8>>,
<<"non-fixed64 wire type"/utf8>>,
[]}}
end.
-file("src/protozoa/decode.gleam", 428).
?DOC(false).
-spec sfixed32_field(field()) -> {ok, integer()} | {error, decode_error()}.
sfixed32_field(Field) ->
case erlang:element(3, Field) of
fixed32 ->
case erlang:element(4, Field) of
<<Value:32/signed-little>> ->
{ok, Value};
_ ->
{error,
{decode_error,
<<"valid signed 32-bit integer data"/utf8>>,
<<"invalid sfixed32 data"/utf8>>,
[]}}
end;
_ ->
{error,
{decode_error,
<<"fixed32 wire type"/utf8>>,
<<"non-fixed32 wire type"/utf8>>,
[]}}
end.
-file("src/protozoa/decode.gleam", 449).
?DOC(false).
-spec sfixed64_field(field()) -> {ok, integer()} | {error, decode_error()}.
sfixed64_field(Field) ->
case erlang:element(3, Field) of
fixed64 ->
case erlang:element(4, Field) of
<<Value:64/signed-little>> ->
{ok, Value};
_ ->
{error,
{decode_error,
<<"valid signed 64-bit integer data"/utf8>>,
<<"invalid sfixed64 data"/utf8>>,
[]}}
end;
_ ->
{error,
{decode_error,
<<"fixed64 wire type"/utf8>>,
<<"non-fixed64 wire type"/utf8>>,
[]}}
end.
-file("src/protozoa/decode.gleam", 492).
?DOC(" Decoder for int32 fields.\n").
-spec int32(integer()) -> decoder(integer()).
int32(Number) ->
field(Number, fun varint_field/1).
-file("src/protozoa/decode.gleam", 497).
?DOC(" Decoder for int32 fields with a default value.\n").
-spec int32_with_default(integer(), integer()) -> decoder(integer()).
int32_with_default(Number, Default) ->
field_with_default(Number, fun varint_field/1, Default).
-file("src/protozoa/decode.gleam", 501).
-spec int64_with_default(integer(), integer()) -> decoder(integer()).
int64_with_default(Number, Default) ->
field_with_default(Number, fun varint_field/1, Default).
-file("src/protozoa/decode.gleam", 506).
?DOC(" Decoder for int64 fields.\n").
-spec int64(integer()) -> decoder(integer()).
int64(Number) ->
field(Number, fun varint_field/1).
-file("src/protozoa/decode.gleam", 511).
?DOC(" Decoder for uint32 fields.\n").
-spec uint32(integer()) -> decoder(integer()).
uint32(Number) ->
field(Number, fun varint_field/1).
-file("src/protozoa/decode.gleam", 516).
?DOC(" Decoder for uint32 fields with a default value.\n").
-spec uint32_with_default(integer(), integer()) -> decoder(integer()).
uint32_with_default(Number, Default) ->
field_with_default(Number, fun varint_field/1, Default).
-file("src/protozoa/decode.gleam", 521).
?DOC(" Decoder for uint64 fields.\n").
-spec uint64(integer()) -> decoder(integer()).
uint64(Number) ->
field(Number, fun varint_field/1).
-file("src/protozoa/decode.gleam", 526).
?DOC(" Decoder for uint64 fields with a default value.\n").
-spec uint64_with_default(integer(), integer()) -> decoder(integer()).
uint64_with_default(Number, Default) ->
field_with_default(Number, fun varint_field/1, Default).
-file("src/protozoa/decode.gleam", 531).
?DOC(" Decoder for string fields.\n").
-spec string(integer()) -> decoder(binary()).
string(Number) ->
field(Number, fun string_field/1).
-file("src/protozoa/decode.gleam", 536).
?DOC(" Decoder for string fields with a default value.\n").
-spec string_with_default(integer(), binary()) -> decoder(binary()).
string_with_default(Number, Default) ->
field_with_default(Number, fun string_field/1, Default).
-file("src/protozoa/decode.gleam", 541).
?DOC(" Decoder for boolean fields.\n").
-spec bool(integer()) -> decoder(boolean()).
bool(Number) ->
field(Number, fun bool_field/1).
-file("src/protozoa/decode.gleam", 546).
?DOC(" Decoder for boolean fields with a default value.\n").
-spec bool_with_default(integer(), boolean()) -> decoder(boolean()).
bool_with_default(Number, Default) ->
field_with_default(Number, fun bool_field/1, Default).
-file("src/protozoa/decode.gleam", 551).
?DOC(" Decoder for bytes fields.\n").
-spec bytes(integer()) -> decoder(bitstring()).
bytes(Number) ->
field(Number, fun bytes_field/1).
-file("src/protozoa/decode.gleam", 556).
?DOC(" Decoder for float fields.\n").
-spec float(integer()) -> decoder(float()).
float(Number) ->
field(Number, fun float_field/1).
-file("src/protozoa/decode.gleam", 561).
?DOC(" Decoder for double fields.\n").
-spec double(integer()) -> decoder(float()).
double(Number) ->
field(Number, fun double_field/1).
-file("src/protozoa/decode.gleam", 566).
?DOC(" Decoder for fixed32 fields (unsigned 32-bit integers).\n").
-spec fixed32(integer()) -> decoder(integer()).
fixed32(Number) ->
field(Number, fun fixed32_int_field/1).
-file("src/protozoa/decode.gleam", 571).
?DOC(" Decoder for fixed64 fields (unsigned 64-bit integers).\n").
-spec fixed64(integer()) -> decoder(integer()).
fixed64(Number) ->
field(Number, fun fixed64_int_field/1).
-file("src/protozoa/decode.gleam", 576).
?DOC(" Decoder for sfixed32 fields (signed 32-bit integers).\n").
-spec sfixed32(integer()) -> decoder(integer()).
sfixed32(Number) ->
field(Number, fun sfixed32_field/1).
-file("src/protozoa/decode.gleam", 581).
?DOC(" Decoder for sfixed64 fields (signed 64-bit integers).\n").
-spec sfixed64(integer()) -> decoder(integer()).
sfixed64(Number) ->
field(Number, fun sfixed64_field/1).
-file("src/protozoa/decode.gleam", 586).
?DOC(" Decoder for repeated int32 fields.\n").
-spec repeated_int32(integer()) -> decoder(list(integer())).
repeated_int32(Number) ->
repeated_field(Number, fun varint_field/1).
-file("src/protozoa/decode.gleam", 591).
?DOC(" Decoder for repeated string fields.\n").
-spec repeated_string(integer()) -> decoder(list(binary())).
repeated_string(Number) ->
repeated_field(Number, fun string_field/1).
-file("src/protozoa/decode.gleam", 625).
?DOC(
" Build a decoder using Gleam's use syntax.\n"
" This allows for composing multiple field decoders into a single decoder.\n"
" Collects all errors from both decoder stages.\n"
" \n"
" ## Examples\n"
" \n"
" ```gleam\n"
" use name <- decode.then(decode.string(1))\n"
" use age <- decode.then(decode.int32(2))\n"
" decode.success(Person(name: name, age: age))\n"
" ```\n"
).
-spec then(decoder(OAQ), fun((OAQ) -> decoder(OAS))) -> decoder(OAS).
then(Decoder, Next) ->
{decoder,
fun(Fields) ->
{decoder, F} = Decoder,
case F(Fields) of
{ok, Value} ->
{decoder, G} = Next(Value),
G(Fields);
{error, Errors} ->
{error, Errors}
end
end}.
-file("src/protozoa/decode.gleam", 646).
?DOC(
" Transform the result of a decoder using a mapping function.\n"
" \n"
" ## Examples\n"
" \n"
" ```gleam\n"
" decode.int32(1)\n"
" |> decode.map(fn(x) { x * 2 })\n"
" ```\n"
).
-spec map(decoder(OAV), fun((OAV) -> OAX)) -> decoder(OAX).
map(Decoder, F) ->
{decoder,
fun(Fields) ->
{decoder, G} = Decoder,
gleam@result:'try'(G(Fields), fun(Value) -> {ok, F(Value)} end)
end}.
-file("src/protozoa/decode.gleam", 662).
?DOC(
" Build a dictionary from a list of fields for O(1) lookup performance.\n"
" Fields with the same number are grouped together in a list.\n"
).
-spec build_field_dict(list(field())) -> gleam@dict:dict(integer(), list(field())).
build_field_dict(Fields) ->
gleam@list:fold(
Fields,
maps:new(),
fun(Acc, Field) ->
gleam@dict:upsert(
Acc,
erlang:element(2, Field),
fun(Existing) -> case Existing of
{some, Fields@1} ->
lists:append(Fields@1, [Field]);
none ->
[Field]
end end
)
end
).
-file("src/protozoa/decode.gleam", 722).
-spec decode_varint_helper(bitstring(), integer(), integer()) -> {ok,
{integer(), bitstring()}} |
{error, decode_error()}.
decode_varint_helper(Data, Value, Shift) ->
case Data of
<<>> ->
{error,
{decode_error,
<<"more varint data"/utf8>>,
<<"unexpected end of data"/utf8>>,
[]}};
<<Byte/integer, Rest/bitstring>> ->
New_value = begin
_pipe = Value,
erlang:'bor'(
_pipe,
begin
_pipe@1 = erlang:'band'(Byte, 16#7F),
erlang:'bsl'(_pipe@1, Shift)
end
)
end,
case erlang:'band'(Byte, 16#80) of
0 ->
{ok, {New_value, Rest}};
_ ->
decode_varint_helper(Rest, New_value, Shift + 7)
end;
_ ->
{error,
{decode_error,
<<"valid varint data"/utf8>>,
<<"invalid varint data"/utf8>>,
[]}}
end.
-file("src/protozoa/decode.gleam", 718).
-spec decode_varint_raw(bitstring()) -> {ok, {integer(), bitstring()}} |
{error, decode_error()}.
decode_varint_raw(Data) ->
decode_varint_helper(Data, 0, 0).
-file("src/protozoa/decode.gleam", 745).
-spec decode_fixed32_raw(bitstring()) -> {ok, {bitstring(), bitstring()}} |
{error, decode_error()}.
decode_fixed32_raw(Data) ->
case Data of
<<Value:32/bitstring, Rest/bitstring>> ->
{ok, {Value, Rest}};
_ ->
{error,
{decode_error,
<<"4 bytes for fixed32"/utf8>>,
<<"insufficient data"/utf8>>,
[]}}
end.
-file("src/protozoa/decode.gleam", 754).
-spec decode_fixed64_raw(bitstring()) -> {ok, {bitstring(), bitstring()}} |
{error, decode_error()}.
decode_fixed64_raw(Data) ->
case Data of
<<Value:64/bitstring, Rest/bitstring>> ->
{ok, {Value, Rest}};
_ ->
{error,
{decode_error,
<<"8 bytes for fixed64"/utf8>>,
<<"insufficient data"/utf8>>,
[]}}
end.
-file("src/protozoa/decode.gleam", 763).
-spec decode_length_delimited_raw(bitstring()) -> {ok,
{bitstring(), bitstring()}} |
{error, decode_error()}.
decode_length_delimited_raw(Data) ->
gleam@result:'try'(
decode_varint_raw(Data),
fun(_use0) ->
{Length, Rest} = _use0,
case erlang:byte_size(Rest) >= Length of
true ->
Bytes_to_take = Length * 8,
case Rest of
<<Value:Bytes_to_take/bitstring, Rest@1/bitstring>> ->
{ok, {Value, Rest@1}};
_ ->
{error,
{decode_error,
<<"sufficient bytes for length-delimited field"/utf8>>,
<<"insufficient data"/utf8>>,
[]}}
end;
false ->
{error,
{decode_error,
<<"sufficient bytes for length-delimited field"/utf8>>,
<<"insufficient data"/utf8>>,
[]}}
end
end
).
-file("src/protozoa/decode.gleam", 686).
-spec decode_field(bitstring()) -> {ok, {field(), bitstring()}} |
{error, decode_error()}.
decode_field(Data) ->
gleam@result:'try'(
decode_varint_raw(Data),
fun(_use0) ->
{Tag, Rest1} = _use0,
Field_number = protozoa@wire:get_field_number(Tag),
gleam@result:'try'(
begin
_pipe = protozoa@wire:get_wire_type(Tag),
gleam@result:map_error(
_pipe,
fun(_) ->
{decode_error,
<<"valid wire type"/utf8>>,
<<"invalid wire type"/utf8>>,
[]}
end
)
end,
fun(Wire_type) -> case Wire_type of
varint ->
gleam@result:'try'(
decode_varint_raw(Rest1),
fun(_use0@1) ->
{Value, Rest2} = _use0@1,
{ok,
{{field,
Field_number,
Wire_type,
<<Value:64>>},
Rest2}}
end
);
fixed64 ->
gleam@result:'try'(
decode_fixed64_raw(Rest1),
fun(_use0@2) ->
{Value@1, Rest2@1} = _use0@2,
{ok,
{{field,
Field_number,
Wire_type,
Value@1},
Rest2@1}}
end
);
length_delimited ->
gleam@result:'try'(
decode_length_delimited_raw(Rest1),
fun(_use0@3) ->
{Value@2, Rest2@2} = _use0@3,
{ok,
{{field,
Field_number,
Wire_type,
Value@2},
Rest2@2}}
end
);
fixed32 ->
gleam@result:'try'(
decode_fixed32_raw(Rest1),
fun(_use0@4) ->
{Value@3, Rest2@3} = _use0@4,
{ok,
{{field,
Field_number,
Wire_type,
Value@3},
Rest2@3}}
end
);
_ ->
{error,
{decode_error,
<<"supported wire type"/utf8>>,
<<"unsupported wire type"/utf8>>,
[]}}
end end
)
end
).
-file("src/protozoa/decode.gleam", 673).
-spec decode_fields(bitstring(), list(field())) -> {ok, list(field())} |
{error, decode_error()}.
decode_fields(Data, Acc) ->
case Data of
<<>> ->
{ok, lists:reverse(Acc)};
_ ->
gleam@result:'try'(
decode_field(Data),
fun(_use0) ->
{Field, Rest} = _use0,
decode_fields(Rest, [Field | Acc])
end
)
end.
-file("src/protozoa/decode.gleam", 656).
-spec decode_message(bitstring()) -> {ok, list(field())} |
{error, decode_error()}.
decode_message(Data) ->
decode_fields(Data, []).
-file("src/protozoa/decode.gleam", 98).
?DOC(
" Run a decoder on a BitArray containing Protocol Buffer data.\n"
" Returns either the decoded value or a list of all errors encountered.\n"
" \n"
" ## Examples\n"
" \n"
" ```gleam\n"
" let decoder = field(1, varint_field)\n"
" run(<<8, 42>>, decoder) // Decodes field 1 with value 42\n"
" ```\n"
).
-spec run(bitstring(), decoder(NWU)) -> {ok, NWU} |
{error, list(decode_error())}.
run(Data, Decoder) ->
gleam@result:'try'(
begin
_pipe = decode_message(Data),
gleam@result:map_error(_pipe, fun(Err) -> [Err] end)
end,
fun(Fields) ->
Field_dict = build_field_dict(Fields),
{decoder, F} = Decoder,
F(Field_dict)
end
).
-file("src/protozoa/decode.gleam", 470).
?DOC(false).
-spec message_field(field(), decoder(NZH)) -> {ok, NZH} |
{error, decode_error()}.
message_field(Field, Decoder) ->
gleam@result:'try'(
bytes_field(Field),
fun(Bytes) ->
gleam@result:'try'(
begin
_pipe = decode_message(Bytes),
gleam@result:map_error(_pipe, fun(Err) -> Err end)
end,
fun(Inner_fields) ->
Field_dict = build_field_dict(Inner_fields),
{decoder, F} = Decoder,
case F(Field_dict) of
{ok, Value} ->
{ok, Value};
{error, [First_error | _]} ->
{error, First_error};
{error, []} ->
{error,
{decode_error,
<<"valid message data"/utf8>>,
<<"empty error list"/utf8>>,
[]}}
end
end
)
end
).
-file("src/protozoa/decode.gleam", 596).
?DOC(" Decoder for nested message fields.\n").
-spec nested_message(integer(), decoder(OAI)) -> decoder(OAI).
nested_message(Number, Decoder) ->
field(Number, fun(F) -> message_field(F, Decoder) end).
-file("src/protozoa/decode.gleam", 601).
?DOC(" Decoder for optional nested message fields.\n").
-spec optional_nested_message(integer(), decoder(OAL)) -> decoder({ok, OAL} |
{error, nil}).
optional_nested_message(Number, Decoder) ->
optional_field(Number, fun(F) -> message_field(F, Decoder) end).
-file("src/protozoa/decode.gleam", 804).
?DOC(
" Decodes a zigzag-encoded integer back to its signed value.\n"
" Zigzag encoding is used for sint32 and sint64 fields to efficiently\n"
" encode negative numbers.\n"
" \n"
" ## Examples\n"
" \n"
" ```gleam\n"
" decode_zigzag(0) // Returns 0\n"
" decode_zigzag(1) // Returns -1\n"
" decode_zigzag(2) // Returns 1\n"
" ```\n"
).
-spec decode_zigzag(integer()) -> integer().
decode_zigzag(Value) ->
case erlang:'band'(Value, 1) of
0 ->
erlang:'bsr'(Value, 1);
_ ->
- erlang:'bsr'(Value + 1, 1)
end.
-file("src/protozoa/decode.gleam", 818).
?DOC(
" Decoder for sint32 fields (signed 32-bit integers with zigzag encoding).\n"
" \n"
" ## Examples\n"
" \n"
" ```gleam\n"
" sint32(1) // Decodes field 1 as a zigzag-encoded int32\n"
" ```\n"
).
-spec sint32(integer()) -> decoder(integer()).
sint32(Number) ->
{decoder,
fun(Fields) ->
{decoder, F@1} = field(
Number,
fun(F) ->
gleam@result:'try'(
varint_field(F),
fun(Value) -> {ok, decode_zigzag(Value)} end
)
end
),
F@1(Fields)
end}.
-file("src/protozoa/decode.gleam", 836).
?DOC(
" Decoder for sint64 fields (signed 64-bit integers with zigzag encoding).\n"
" \n"
" ## Examples\n"
" \n"
" ```gleam\n"
" sint64(1) // Decodes field 1 as a zigzag-encoded int64\n"
" ```\n"
).
-spec sint64(integer()) -> decoder(integer()).
sint64(Number) ->
{decoder,
fun(Fields) ->
{decoder, F@1} = field(
Number,
fun(F) ->
gleam@result:'try'(
varint_field(F),
fun(Value) -> {ok, decode_zigzag(Value)} end
)
end
),
F@1(Fields)
end}.