-module(gleeth@encoding@rlp). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/gleeth/encoding/rlp.gleam"). -export([encode_string/1, encode_int/1, encode_hex_field/1, decode/1, encode/1]). -export_type([rlp_item/0, rlp_error/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 rlp_item() :: {rlp_bytes, bitstring()} | {rlp_list, list(rlp_item())}. -type rlp_error() :: {invalid_prefix, integer()} | unexpected_end | extra_data | invalid_length. -file("src/gleeth/encoding/rlp.gleam", 186). ?DOC(" Convert a UTF-8 string to an RLP item\n"). -spec encode_string(binary()) -> rlp_item(). encode_string(Value) -> {rlp_bytes, gleam_stdlib:identity(Value)}. -file("src/gleeth/encoding/rlp.gleam", 221). -spec do_to_binary_be(integer(), bitstring()) -> bitstring(). do_to_binary_be(Value, Acc) -> case Value of 0 -> Acc; _ -> Byte = erlang:'band'(Value, 16#ff), Rest = erlang:'bsr'(Value, 8), do_to_binary_be(Rest, <>) end. -file("src/gleeth/encoding/rlp.gleam", 214). ?DOC(" Convert a non-negative integer to minimal big-endian bytes\n"). -spec to_binary_be(integer()) -> bitstring(). to_binary_be(Value) -> case Value of 0 -> <<>>; _ -> do_to_binary_be(Value, <<>>) end. -file("src/gleeth/encoding/rlp.gleam", 67). -spec encode_length(integer(), integer()) -> bitstring(). encode_length(Len, Offset) -> case Len =< 55 of true -> Prefix_byte = Offset + Len, <>; false -> Len_bytes = to_binary_be(Len), Len_of_len = erlang:byte_size(Len_bytes), Prefix_byte@1 = (Offset + 55) + Len_of_len, <> end. -file("src/gleeth/encoding/rlp.gleam", 35). -spec encode_bytes(bitstring()) -> bitstring(). encode_bytes(Data) -> case Data of <> -> case Byte < 16#80 of true -> Data; false -> Prefix = encode_length(1, 16#80), <> end; _ -> Len = erlang:byte_size(Data), Prefix@1 = encode_length(Len, 16#80), <> end. -file("src/gleeth/encoding/rlp.gleam", 178). ?DOC( " Convert an integer to an RLP item.\n" " Uses big-endian minimal encoding: 0 becomes empty bytes.\n" ). -spec encode_int(integer()) -> rlp_item(). encode_int(Value) -> case Value of 0 -> {rlp_bytes, <<>>}; _ -> {rlp_bytes, to_binary_be(Value)} end. -file("src/gleeth/encoding/rlp.gleam", 237). -spec do_bytes_to_int(bitstring(), integer()) -> integer(). do_bytes_to_int(Data, Acc) -> case Data of <> -> do_bytes_to_int(Rest, (Acc * 256) + Byte); _ -> Acc end. -file("src/gleeth/encoding/rlp.gleam", 233). ?DOC(" Convert big-endian bytes to an integer\n"). -spec bytes_to_int(bitstring()) -> integer(). bytes_to_int(Data) -> do_bytes_to_int(Data, 0). -file("src/gleeth/encoding/rlp.gleam", 245). ?DOC(" Take n bytes from the front of a BitArray\n"). -spec take_bytes(bitstring(), integer()) -> {ok, {bitstring(), bitstring()}} | {error, rlp_error()}. take_bytes(Data, N) -> case N =:= 0 of true -> {ok, {<<>>, Data}}; false -> Available = erlang:byte_size(Data), case Available >= N of true -> Taken@1 = case gleam_stdlib:bit_array_slice(Data, 0, N) of {ok, Taken} -> Taken; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"gleeth/encoding/rlp"/utf8>>, function => <<"take_bytes"/utf8>>, line => 252, value => _assert_fail, start => 7217, 'end' => 7267, pattern_start => 7228, pattern_end => 7237}) end, Rest@1 = case gleam_stdlib:bit_array_slice( Data, N, Available - N ) of {ok, Rest} -> Rest; _assert_fail@1 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"gleeth/encoding/rlp"/utf8>>, function => <<"take_bytes"/utf8>>, line => 253, value => _assert_fail@1, start => 7278, 'end' => 7339, pattern_start => 7289, pattern_end => 7297}) end, {ok, {Taken@1, Rest@1}}; false -> {error, unexpected_end} end end. -file("src/gleeth/encoding/rlp.gleam", 263). ?DOC(" Strip leading zero bytes from a BitArray\n"). -spec strip_leading_zeros(bitstring()) -> bitstring(). strip_leading_zeros(Data) -> case Data of <<0:8, Rest/bitstring>> -> strip_leading_zeros(Rest); _ -> Data end. -file("src/gleeth/encoding/rlp.gleam", 192). ?DOC( " Convert a \"0x...\" hex string to an RLP item with minimal encoding.\n" " Strips the 0x prefix, decodes hex to bytes, and removes leading zero bytes.\n" ). -spec encode_hex_field(binary()) -> rlp_item(). encode_hex_field(Hex_string) -> Stripped = gleeth@utils@hex:strip_prefix(Hex_string), case Stripped of <<""/utf8>> -> {rlp_bytes, <<>>}; _ -> Padded = case string:length(Stripped) rem 2 of 0 -> Stripped; _ -> <<"0"/utf8, Stripped/binary>> end, case gleeth@utils@hex:decode(Padded) of {ok, Bytes} -> {rlp_bytes, strip_leading_zeros(Bytes)}; {error, _} -> {rlp_bytes, <<>>} end end. -file("src/gleeth/encoding/rlp.gleam", 161). -spec decode_list_payload(bitstring()) -> {ok, list(rlp_item())} | {error, rlp_error()}. decode_list_payload(Data) -> case erlang:byte_size(Data) of 0 -> {ok, []}; _ -> gleam@result:'try'( decode_item(Data), fun(_use0) -> {Item, Rest} = _use0, gleam@result:'try'( decode_list_payload(Rest), fun(Items) -> {ok, [Item | Items]} end ) end ) end. -file("src/gleeth/encoding/rlp.gleam", 95). -spec decode_item(bitstring()) -> {ok, {rlp_item(), bitstring()}} | {error, rlp_error()}. decode_item(Data) -> case Data of <<>> -> {error, unexpected_end}; <> -> decode_with_prefix(Prefix, Rest); _ -> {error, unexpected_end} end. -file("src/gleeth/encoding/rlp.gleam", 103). -spec decode_with_prefix(integer(), bitstring()) -> {ok, {rlp_item(), bitstring()}} | {error, rlp_error()}. decode_with_prefix(Prefix, Rest) -> case Prefix < 16#80 of true -> {ok, {{rlp_bytes, <>}, Rest}}; false -> case Prefix < 16#b8 of true -> Len = Prefix - 16#80, gleam@result:'try'( take_bytes(Rest, Len), fun(_use0) -> {Bytes, Remaining} = _use0, {ok, {{rlp_bytes, Bytes}, Remaining}} end ); false -> case Prefix < 16#c0 of true -> Len_of_len = Prefix - 16#b7, gleam@result:'try'( take_bytes(Rest, Len_of_len), fun(_use0@1) -> {Len_bytes, After_len} = _use0@1, Len@1 = bytes_to_int(Len_bytes), gleam@result:'try'( take_bytes(After_len, Len@1), fun(_use0@2) -> {Bytes@1, Remaining@1} = _use0@2, {ok, {{rlp_bytes, Bytes@1}, Remaining@1}} end ) end ); false -> case Prefix < 16#f8 of true -> Len@2 = Prefix - 16#c0, gleam@result:'try'( take_bytes(Rest, Len@2), fun(_use0@3) -> {Payload, Remaining@2} = _use0@3, gleam@result:'try'( decode_list_payload(Payload), fun(Items) -> {ok, {{rlp_list, Items}, Remaining@2}} end ) end ); false -> Len_of_len@1 = Prefix - 16#f7, gleam@result:'try'( take_bytes(Rest, Len_of_len@1), fun(_use0@4) -> {Len_bytes@1, After_len@1} = _use0@4, Len@3 = bytes_to_int(Len_bytes@1), gleam@result:'try'( take_bytes(After_len@1, Len@3), fun(_use0@5) -> {Payload@1, Remaining@3} = _use0@5, gleam@result:'try'( decode_list_payload( Payload@1 ), fun(Items@1) -> {ok, {{rlp_list, Items@1}, Remaining@3}} end ) end ) end ) end end end end. -file("src/gleeth/encoding/rlp.gleam", 87). ?DOC(" Decode bytes into an RLP item\n"). -spec decode(bitstring()) -> {ok, rlp_item()} | {error, rlp_error()}. decode(Data) -> gleam@result:'try'( decode_item(Data), fun(_use0) -> {Item, Rest} = _use0, case erlang:byte_size(Rest) of 0 -> {ok, Item}; _ -> {error, extra_data} end end ). -file("src/gleeth/encoding/rlp.gleam", 56). -spec encode_list(list(rlp_item())) -> bitstring(). encode_list(Items) -> Payload = gleam@list:fold( Items, <<>>, fun(Acc, Item) -> Encoded = encode(Item), <> end ), Len = erlang:byte_size(Payload), Prefix = encode_length(Len, 16#c0), <>. -file("src/gleeth/encoding/rlp.gleam", 28). ?DOC(" Encode an RLP item to bytes\n"). -spec encode(rlp_item()) -> bitstring(). encode(Item) -> case Item of {rlp_bytes, Data} -> encode_bytes(Data); {rlp_list, Items} -> encode_list(Items) end.