-module(protobin). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/protobin.gleam"). -export([read_varint/2, parse_varint/2, read_fixed/1, parse_with_config/3, decode_multiple/2, decode_bytes/0, decode_uint/0, decode_fixed/1, decode_bool/0, decode_string/0, parse/2, decode_protobuf/3]). -export_type([parse_error/0, parsed/1, field/0, config/0]). -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 parse_error() :: {unknown_wire_type, integer(), integer()} | {invalid_var_int, bitstring(), bitstring(), integer()} | {invalid_fixed, integer(), bitstring(), integer()} | {invalid_len, integer(), bitstring(), integer()} | {unable_to_decode, list(gleam@dynamic@decode:decode_error())} | {unexpected_group, protobin@internal@wire_type:wire_type(), integer()}. -type parsed(EDB) :: {parsed, EDB, bitstring(), integer()}. -type field() :: {field, gleam@dynamic:dynamic_(), gleam@dynamic:dynamic_()}. -type config() :: {config, boolean()}. -file("src/protobin.gleam", 32). -spec parsed_map(parsed(EDH), fun((EDH) -> EDJ)) -> parsed(EDJ). parsed_map(Parsed, Fun) -> {parsed, Value, Rest, Pos} = Parsed, {parsed, Fun(Value), Rest, Pos}. -file("src/protobin.gleam", 108). -spec repeated_to_list(list(field())) -> gleam@dict:dict(gleam@dynamic:dynamic_(), gleam@dynamic:dynamic_()). repeated_to_list(Reversed_fields) -> Fields@1 = begin Acc = maps:new(), gleam@list:fold( Reversed_fields, Acc, fun(Fields, _use1) -> {field, Key, Value} = _use1, gleam@dict:upsert( Fields, Key, fun(Existing_values) -> Existing_values@1 = gleam@option:unwrap( Existing_values, [] ), [Value | Existing_values@1] end ) end ) end, gleam@dict:map_values(Fields@1, fun(_, Field) -> _pipe = Field, gleam_stdlib:identity(_pipe) end). -file("src/protobin.gleam", 190). -spec read_varint_acc(bitstring(), bitstring(), integer()) -> {ok, parsed(bitstring())} | {error, parse_error()}. read_varint_acc(Bits, Acc, Pos) -> case Bits of <<0:1, N:7/bitstring, Rest/binary>> -> Bit = <<0:1, N/bitstring>>, Acc@1 = gleam_stdlib:bit_array_concat([Acc, Bit]), {ok, {parsed, Acc@1, Rest, Pos + 1}}; <<1:1, N@1:7/bitstring, Rest@1/binary>> -> Bit@1 = <<1:1, N@1/bitstring>>, read_varint_acc( Rest@1, gleam_stdlib:bit_array_concat([Acc, Bit@1]), Pos + 1 ); Bits@1 -> {error, {invalid_var_int, Bits@1, Acc, Pos}} end. -file("src/protobin.gleam", 186). ?DOC( " Reads the bits from a varint and returns *all* of them. They cannot be\n" " parsed as a uint.\n" "\n" " Specifically, the continuation bits are included, so the value's bit size\n" " will be a multiple of 8.\n" ). -spec read_varint(bitstring(), integer()) -> {ok, parsed(bitstring())} | {error, parse_error()}. read_varint(Bits, Pos) -> read_varint_acc(Bits, <<>>, Pos). -file("src/protobin.gleam", 216). -spec parse_varint_acc(bitstring(), bitstring(), integer()) -> {ok, parsed(bitstring())} | {error, parse_error()}. parse_varint_acc(Bits, Acc, Pos) -> case Bits of <<0:1, N:7/bitstring, Rest/binary>> -> Acc@1 = gleam_stdlib:bit_array_concat([N, Acc]), {ok, {parsed, Acc@1, Rest, Pos + 1}}; <<1:1, N@1:7/bitstring, Rest@1/binary>> -> parse_varint_acc( Rest@1, gleam_stdlib:bit_array_concat([N@1, Acc]), Pos + 1 ); Bits@1 -> {error, {invalid_var_int, Bits@1, Acc, Pos}} end. -file("src/protobin.gleam", 212). ?DOC( " Reads the bits from a varint and parses them a `BitArray`. The returned bits\n" " can be parsed as a uint.\n" "\n" " For a decoder that does this, use `decoders.uint()`.\n" "\n" " The continuation bits are not included, so the value's bit size will be a\n" " multiple of 7.\n" ). -spec parse_varint(bitstring(), integer()) -> {ok, parsed(bitstring())} | {error, parse_error()}. parse_varint(Bits, Pos) -> parse_varint_acc(Bits, <<>>, Pos). -file("src/protobin.gleam", 233). ?DOC( " Size is in bits, usually either 32 or 64.\n" "\n" " Size must be a multiple of 8, or the returned position will be incorrect.\n" ). -spec read_fixed(integer()) -> fun((bitstring(), integer()) -> {ok, parsed(bitstring())} | {error, parse_error()}). read_fixed(Size) -> fun(Bits, Pos) -> case Bits of <> -> {ok, {parsed, Num, Rest, Pos + (Size div 8)}}; Bits@1 -> {error, {invalid_fixed, Size, Bits@1, Pos}} end end. -file("src/protobin.gleam", 243). -spec read_len(bitstring(), integer()) -> {ok, parsed(bitstring())} | {error, parse_error()}. read_len(Bits, Len_pos) -> gleam@result:'try'( parse_varint(Bits, Len_pos), fun(_use0) -> {parsed, Len, Bits@1, Pos} = _use0, Len@1 = protobin@internal@util:bit_array_to_uint(Len), gleam@result:'try'( begin _pipe = gleam_stdlib:bit_array_slice(Bits@1, 0, Len@1), gleam@result:map_error( _pipe, fun(_) -> {invalid_len, Len@1, Bits@1, Len_pos} end ) end, fun(Value) -> Rest@1 = case gleam_stdlib:bit_array_slice( Bits@1, Len@1, erlang:byte_size(Bits@1) - Len@1 ) of {ok, Rest} -> Rest; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"protobin"/utf8>>, function => <<"read_len"/utf8>>, line => 259, value => _assert_fail, start => 7423, 'end' => 7524, pattern_start => 7434, pattern_end => 7442}) end, {ok, {parsed, Value, Rest@1, Pos + Len@1}} end ) end ). -file("src/protobin.gleam", 266). ?DOC(" Currently just does nothing.\n"). -spec read_group(bitstring(), integer()) -> {ok, parsed(bitstring())} | {error, parse_error()}. read_group(Bits, Pos) -> {ok, {parsed, <<>>, Bits, Pos}}. -file("src/protobin.gleam", 171). -spec wire_type_read_fn(protobin@internal@wire_type:wire_type()) -> fun((bitstring(), integer()) -> {ok, parsed(bitstring())} | {error, parse_error()}). wire_type_read_fn(Ty) -> case Ty of var_int -> fun read_varint/2; i64 -> read_fixed(64); len -> fun read_len/2; i32 -> read_fixed(32); s_group -> fun read_group/2; e_group -> fun read_group/2 end. -file("src/protobin.gleam", 131). -spec read_field(bitstring(), integer(), config()) -> {ok, parsed(field())} | {error, parse_error()}. read_field(Bits, Tag_pos, Config) -> gleam@result:'try'( parse_varint(Bits, Tag_pos), fun(_use0) -> {parsed, Tag, Bits@1, Pos} = _use0, Tag@1 = protobin@internal@util:bit_array_to_uint(Tag), Field_id = begin _pipe = Tag@1, erlang:'bsr'(_pipe, 3) end, Wire_type = begin _pipe@1 = Tag@1, erlang:'band'(_pipe@1, 2#111) end, gleam@result:'try'( gleam@option:to_result( protobin@internal@wire_type:parse(Wire_type), {unknown_wire_type, Wire_type, Tag_pos} ), fun(Wire_type@1) -> gleam@result:'try'((case {Wire_type@1, Config} of {s_group, {config, false}} -> {error, {unexpected_group, Wire_type@1, Tag_pos}}; {e_group, {config, false}} -> {error, {unexpected_group, Wire_type@1, Tag_pos}}; {_, _} -> {ok, Wire_type@1} end), fun(Wire_type@2) -> Read = wire_type_read_fn(Wire_type@2), gleam@result:'try'( begin _pipe@2 = Read(Bits@1, Pos), gleam@result:map( _pipe@2, fun(_capture) -> parsed_map( _capture, fun gleam_stdlib:identity/1 ) end ) end, fun(Value) -> Field = parsed_map( Value, fun(Value@1) -> {field, gleam_stdlib:identity(Field_id), Value@1} end ), {ok, Field} end ) end) end ) end ). -file("src/protobin.gleam", 83). -spec read_fields(bitstring(), list(field()), integer(), config()) -> {ok, parsed(gleam@dynamic:dynamic_())} | {error, parse_error()}. read_fields(Bits, Acc, Pos, Config) -> case Bits of <<>> -> _pipe = Acc, _pipe@1 = repeated_to_list(_pipe), _pipe@2 = maps:to_list(_pipe@1), _pipe@3 = gleam@dynamic:properties(_pipe@2), _pipe@4 = {parsed, _pipe@3, Bits, Pos}, {ok, _pipe@4}; Bits@1 -> gleam@result:'try'( read_field(Bits@1, Pos, Config), fun(_use0) -> {parsed, Prop, Bits@2, Pos@1} = _use0, read_fields(Bits@2, [Prop | Acc], Pos@1, Config) end ) end. -file("src/protobin.gleam", 67). -spec parse_with_config( bitstring(), gleam@dynamic@decode:decoder(EDP), config() ) -> {ok, parsed(EDP)} | {error, parse_error()}. parse_with_config(Bits, Decoder, Config) -> gleam@result:'try'( read_fields(Bits, [], 0, Config), fun(_use0) -> {parsed, Data, Rest, Pos} = _use0, _pipe = gleam@dynamic@decode:run(Data, Decoder), _pipe@1 = gleam@result:map( _pipe, fun(Value) -> {parsed, Value, Rest, Pos} end ), gleam@result:map_error( _pipe@1, fun(Field@0) -> {unable_to_decode, Field@0} end ) end ). -file("src/protobin.gleam", 305). -spec unpack_bits( bitstring(), list(bitstring()), integer(), fun((bitstring(), integer()) -> {ok, parsed(bitstring())} | {error, parse_error()}) ) -> {ok, list(bitstring())} | {error, parse_error()}. unpack_bits(Bits, Acc, Pos, Parser) -> case Bits of <<>> -> _pipe = Acc, _pipe@1 = lists:reverse(_pipe), {ok, _pipe@1}; Bits@1 -> gleam@result:'try'( Parser(Bits@1, Pos), fun(_use0) -> {parsed, Value, Rest, Pos@1} = _use0, unpack_bits(Rest, [Value | Acc], Pos@1, Parser) end ) end. -file("src/protobin.gleam", 283). -spec packed_values( gleam@dynamic@decode:decoder(EEF), fun((bitstring(), integer()) -> {ok, parsed(bitstring())} | {error, parse_error()}) ) -> gleam@dynamic@decode:decoder(list(EEF)). packed_values(Decoder, Parser) -> gleam@dynamic@decode:then( gleam@dynamic@decode:list( {decoder, fun gleam@dynamic@decode:decode_bit_array/1} ), fun(Bits) -> Bits@1 = gleam@list:fold( Bits, <<>>, fun(Acc, Elem) -> gleam_stdlib:bit_array_concat([Acc, Elem]) end ), Values@1 = begin gleam@result:'try'( unpack_bits(Bits@1, [], 0, Parser), fun(Values) -> _pipe = Values, _pipe@1 = gleam@list:map( _pipe, fun gleam_stdlib:identity/1 ), _pipe@2 = gleam@list:try_map( _pipe@1, fun(Value) -> gleam@dynamic@decode:run(Value, Decoder) end ), gleam@result:map_error( _pipe@2, fun(Field@0) -> {unable_to_decode, Field@0} end ) end ) end, case Values@1 of {ok, Values@2} -> gleam@dynamic@decode:success(Values@2); {error, _} -> gleam@dynamic@decode:failure([], <<"Packed values"/utf8>>) end end ). -file("src/protobin.gleam", 275). ?DOC( " Decode a repeated field that may be either packed or expanded.\n" " \n" " If it is impossible for a field to be packed (ie because it is encoded as\n" " a `LEN`) and therefore there is no `ValueParser` for it, then use the\n" " stdlib's `decode.list()` instead.\n" ). -spec decode_multiple( gleam@dynamic@decode:decoder(EEB), fun((bitstring(), integer()) -> {ok, parsed(bitstring())} | {error, parse_error()}) ) -> gleam@dynamic@decode:decoder(list(EEB)). decode_multiple(Decoder, Parser) -> gleam@dynamic@decode:then( packed_values(Decoder, Parser), fun(Values) -> _pipe = Values, gleam@dynamic@decode:success(_pipe) end ). -file("src/protobin.gleam", 321). ?DOC(" Takes the last value from the list.\n"). -spec single(gleam@dynamic@decode:decoder(EEM), binary(), EEM) -> gleam@dynamic@decode:decoder(EEM). single(Decoder, Name, Default) -> gleam@dynamic@decode:then( gleam@dynamic@decode:list(Decoder), fun(Values) -> case gleam@list:last(Values) of {ok, Value} -> gleam@dynamic@decode:success(Value); {error, nil} -> gleam@dynamic@decode:failure(Default, Name) end end ). -file("src/protobin.gleam", 335). -spec single_or_raw(gleam@dynamic@decode:decoder(EEP), binary(), EEP) -> gleam@dynamic@decode:decoder(EEP). single_or_raw(Decoder, Name, Default) -> gleam@dynamic@decode:one_of(Decoder, [single(Decoder, Name, Default)]). -file("src/protobin.gleam", 345). -spec single_or_raw_bit_array() -> gleam@dynamic@decode:decoder(bitstring()). single_or_raw_bit_array() -> single_or_raw( {decoder, fun gleam@dynamic@decode:decode_bit_array/1}, <<"BitArray"/utf8>>, <<>> ). -file("src/protobin.gleam", 350). ?DOC(" Decode a `bytes` field. The result is guaranteed to be byte-aligned.\n"). -spec decode_bytes() -> gleam@dynamic@decode:decoder(bitstring()). decode_bytes() -> gleam@dynamic@decode:then( single_or_raw_bit_array(), fun(Bits) -> case Bits of <<_/binary>> -> gleam@dynamic@decode:success(Bits); _ -> gleam@dynamic@decode:failure(<<>>, <<"Bytes"/utf8>>) end end ). -file("src/protobin.gleam", 373). -spec decode_uint() -> gleam@dynamic@decode:decoder(integer()). decode_uint() -> gleam@dynamic@decode:then( single_or_raw_bit_array(), fun(Bits) -> gleam@dynamic@decode:then(case parse_varint(Bits, 0) of {ok, {parsed, Value, <<>>, _}} -> gleam@dynamic@decode:success(Value); _ -> gleam@dynamic@decode:failure(<<>>, <<"uint"/utf8>>) end, fun(Bits@1) -> _pipe = Bits@1, _pipe@1 = protobin@internal@util:bit_array_to_uint(_pipe), gleam@dynamic@decode:success(_pipe@1) end) end ). -file("src/protobin.gleam", 382). -spec decode_fixed(integer()) -> gleam@dynamic@decode:decoder(integer()). decode_fixed(Size) -> gleam@dynamic@decode:then( single_or_raw_bit_array(), fun(Bits) -> case Bits of <> -> gleam@dynamic@decode:success(Num); _ -> gleam@dynamic@decode:failure( 0, <<<<"Fixed("/utf8, (erlang:integer_to_binary(Size))/binary>>/binary, ")"/utf8>> ) end end ). -file("src/protobin.gleam", 390). -spec decode_bool() -> gleam@dynamic@decode:decoder(boolean()). decode_bool() -> gleam@dynamic@decode:then(decode_uint(), fun(Bool) -> case Bool of 0 -> _pipe = false, gleam@dynamic@decode:success(_pipe); 1 -> _pipe@1 = true, gleam@dynamic@decode:success(_pipe@1); _ -> gleam@dynamic@decode:failure(false, <<"Bool"/utf8>>) end end). -file("src/protobin.gleam", 399). -spec decode_string() -> gleam@dynamic@decode:decoder(binary()). decode_string() -> gleam@dynamic@decode:then( single_or_raw_bit_array(), fun(Bits) -> Str = gleam@bit_array:to_string(Bits), case Str of {ok, Str@1} -> gleam@dynamic@decode:success(Str@1); {error, _} -> gleam@dynamic@decode:failure(<<""/utf8>>, <<"String"/utf8>>) end end ). -file("src/protobin.gleam", 60). -spec parse(bitstring(), gleam@dynamic@decode:decoder(EDL)) -> {ok, parsed(EDL)} | {error, parse_error()}. parse(Bits, Decoder) -> parse_with_config(Bits, Decoder, {config, false}). -file("src/protobin.gleam", 358). -spec decode_protobuf( fun(() -> gleam@dynamic@decode:decoder(EEU)), binary(), EEU ) -> gleam@dynamic@decode:decoder(EEU). decode_protobuf(Decoder, Name, Default) -> gleam@dynamic@decode:then( single_or_raw_bit_array(), fun(Bits) -> Value = parse(Bits, Decoder()), case Value of {ok, {parsed, Value@1, <<>>, _}} -> gleam@dynamic@decode:success(Value@1); _ -> gleam@dynamic@decode:failure(Default, Name) end end ).