-module(thrifty@container). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/thrifty/container.gleam"). -export([element_type_to_code/1, code_to_element_type/1, encode_list_header/2, decode_list_header/2, encode_map_header/3, decode_map_header/2]). -export_type([element_type/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 element_type() :: bool_type | i8_type | i16_type | i32_type | i64_type | double_type | binary_type | list_type | set_type | map_type | struct_type. -file("src/thrifty/container.gleam", 83). ?DOC( " Convert ElementType to compact protocol type code (4 bits).\n" "\n" " Inputs\n" " - `t`: the `ElementType` to convert.\n" "\n" " Outputs\n" " - Returns the 4-bit integer code used in Compact Protocol headers.\n" "\n" " Complexity\n" " - O(1)\n" ). -spec element_type_to_code(element_type()) -> integer(). element_type_to_code(T) -> case T of bool_type -> 2; i8_type -> 3; i16_type -> 4; i32_type -> 5; i64_type -> 6; double_type -> 7; binary_type -> 8; list_type -> 9; set_type -> 10; map_type -> 11; struct_type -> 12 end. -file("src/thrifty/container.gleam", 112). ?DOC( " Convert a compact protocol 4-bit type code to `ElementType`.\n" "\n" " Inputs\n" " - `code`: integer value extracted from a header nibble (0-15).\n" "\n" " Outputs\n" " - `Ok(ElementType)` when the code is recognized.\n" " - `Error(types.UnsupportedType(code))` when the code is unknown.\n" "\n" " Error modes\n" " - Returns `types.UnsupportedType` for unknown codes.\n" ). -spec code_to_element_type(integer()) -> {ok, element_type()} | {error, thrifty@types:decode_error()}. code_to_element_type(Code) -> case Code of 1 -> {ok, bool_type}; 2 -> {ok, bool_type}; 3 -> {ok, i8_type}; 4 -> {ok, i16_type}; 5 -> {ok, i32_type}; 6 -> {ok, i64_type}; 7 -> {ok, double_type}; 8 -> {ok, binary_type}; 9 -> {ok, list_type}; 10 -> {ok, set_type}; 11 -> {ok, map_type}; 12 -> {ok, struct_type}; _ -> {error, {unsupported_type, Code}} end. -file("src/thrifty/container.gleam", 143). ?DOC( " Encode a list/set header consisting of size and element type.\n" "\n" " Inputs\n" " - `size`: number of elements in the list/set (non-negative).\n" " - `elem_type`: the `ElementType` of elements.\n" "\n" " Outputs\n" " - Returns a `BitArray` containing either the short-form header (1 byte)\n" " when `size < 15` or the long-form header (1 byte + varint) otherwise.\n" "\n" " Complexity\n" " - O(1) (plus cost of varint encoding when required).\n" ). -spec encode_list_header(integer(), element_type()) -> bitstring(). encode_list_header(Size, Elem_type) -> Type_code = element_type_to_code(Elem_type), case Size < 15 of true -> Header_byte = (Size * 16) + Type_code, <>; false -> Header_byte@1 = (15 * 16) + Type_code, Size_varint = thrifty@varint:encode_varint(Size), <> end. -file("src/thrifty/container.gleam", 171). ?DOC( " Decode a list/set header from a `BitArray` at `byte_position`.\n" "\n" " Inputs\n" " - `data`: the `BitArray` containing the encoded header and payload.\n" " - `byte_position`: byte offset where the header begins.\n" "\n" " Outputs\n" " - `Ok(#(size, element_type, next_byte_position))` on success where\n" " `next_byte_position` is the byte index immediately after the header.\n" " - `Error(types.DecodeError)` on malformed input or unexpected end.\n" ). -spec decode_list_header(bitstring(), integer()) -> {ok, {integer(), element_type(), integer()}} | {error, thrifty@types:decode_error()}. decode_list_header(Data, Byte_position) -> case gleam_stdlib:bit_array_slice(Data, Byte_position, 1) of {error, _} -> {error, unexpected_end_of_input}; {ok, Header_bits} -> case Header_bits of <> -> Size_nibble = Header_byte div 16, Type_nibble = Header_byte rem 16, case code_to_element_type(Type_nibble) of {error, E} -> {error, E}; {ok, Elem_type} -> case Size_nibble =:= 15 of true -> case thrifty@varint:decode_varint( Data, Byte_position + 1 ) of {error, E@1} -> {error, E@1}; {ok, {Size, Next_pos}} -> {ok, {Size, Elem_type, Next_pos}} end; false -> {ok, {Size_nibble, Elem_type, Byte_position + 1}} end end; _ -> {error, {invalid_wire_format, <<"Invalid list header byte"/utf8>>}} end end. -file("src/thrifty/container.gleam", 219). ?DOC( " Encode a map header (size + key type + value type).\n" "\n" " Inputs\n" " - `size`: number of entries in the map (non-negative).\n" " - `key_type`: the `ElementType` used for keys.\n" " - `value_type`: the `ElementType` used for values.\n" "\n" " Outputs\n" " - For empty maps returns a single zero byte.\n" " - For non-empty maps returns varint(size) followed by a single types byte\n" " where the high nibble is key type and the low nibble is value type.\n" ). -spec encode_map_header(integer(), element_type(), element_type()) -> bitstring(). encode_map_header(Size, Key_type, Value_type) -> case Size =:= 0 of true -> <<0:8/integer>>; false -> Size_varint = thrifty@varint:encode_varint(Size), Key_code = element_type_to_code(Key_type), Value_code = element_type_to_code(Value_type), Types_byte = (Key_code * 16) + Value_code, <> end. -file("src/thrifty/container.gleam", 246). ?DOC( " Decode a map header from `data` at `byte_position`.\n" "\n" " Inputs\n" " - `data`: the `BitArray` containing the encoded header and payload.\n" " - `byte_position`: byte offset where the header begins.\n" "\n" " Outputs\n" " - `Ok(#(size, key_type, value_type, next_byte_position))` where `next_byte_position`\n" " points after the types byte (or after the varint for empty maps).\n" " - `Error(types.DecodeError)` on malformed input or unexpected end.\n" ). -spec decode_map_header(bitstring(), integer()) -> {ok, {integer(), element_type(), element_type(), integer()}} | {error, thrifty@types:decode_error()}. decode_map_header(Data, Byte_position) -> case thrifty@varint:decode_varint(Data, Byte_position) of {error, E} -> {error, E}; {ok, {Size, Next_pos}} -> case Size =:= 0 of true -> {ok, {0, i32_type, i32_type, Next_pos}}; false -> case gleam_stdlib:bit_array_slice(Data, Next_pos, 1) of {error, _} -> {error, unexpected_end_of_input}; {ok, Types_bits} -> case Types_bits of <> -> Key_code = Types_byte div 16, Value_code = Types_byte rem 16, case code_to_element_type(Key_code) of {error, E@1} -> {error, E@1}; {ok, Key_type} -> case code_to_element_type( Value_code ) of {error, E@2} -> {error, E@2}; {ok, Value_type} -> {ok, {Size, Key_type, Value_type, Next_pos + 1}} end end; _ -> {error, {invalid_wire_format, <<"Invalid map types byte"/utf8>>}} end end end end.