Packages

Pure Gleam implementation of the Apache Thrift Compact Protocol

Current section

Files

Jump to
thrifty src thrifty@field.erl
Raw

src/thrifty@field.erl

-module(thrifty@field).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/thrifty/field.gleam").
-export([read_field_header/2, encode_field_header/3]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-file("src/thrifty/field.gleam", 208).
?DOC(
" Return a new `types.Reader` with updated byte position and options.\n"
"\n"
" Inputs\n"
" - `reader`: existing `types.Reader`.\n"
" - `byte_pos`: new byte offset.\n"
" - `options`: reader options to attach.\n"
"\n"
" Outputs\n"
" - `types.Reader` referencing the same `data` with updated state.\n"
).
-spec set_position(
thrifty@types:reader(),
integer(),
thrifty@types:reader_options()
) -> thrifty@types:reader().
set_position(Reader, Byte_pos, Options) ->
{reader, Data, _, _} = Reader,
{reader, Data, Byte_pos, Options}.
-file("src/thrifty/field.gleam", 180).
?DOC(
" Convert an integer nibble to `types.FieldType`.\n"
"\n"
" Inputs\n"
" - `n`: integer nibble from a header byte.\n"
"\n"
" Outputs\n"
" - `Ok(FieldType)` when the nibble maps to a known type.\n"
" - `Error(types.UnsupportedType(n))` for unknown nibble values.\n"
).
-spec int_to_field_type(integer()) -> {ok, thrifty@types:field_type()} |
{error, thrifty@types:decode_error()}.
int_to_field_type(N) ->
case N of
0 ->
{ok, stop};
1 ->
{ok, bool_true};
2 ->
{ok, bool_false};
3 ->
{ok, byte};
4 ->
{ok, i16};
5 ->
{ok, i32};
6 ->
{ok, i64};
7 ->
{ok, double};
8 ->
{ok, binary};
9 ->
{ok, list};
10 ->
{ok, set};
11 ->
{ok, map};
12 ->
{ok, struct};
_ ->
{error, {unsupported_type, N}}
end.
-file("src/thrifty/field.gleam", 36).
?DOC(
" Read a field header from the reader and advance the reader.\n"
"\n"
" Inputs\n"
" - `reader`: a `types.Reader` positioned at the start of a field header.\n"
" - `last_field_id`: the previous field id used to decode delta-encoded ids.\n"
"\n"
" Outputs\n"
" - `Ok(#(types.FieldHeader, types.Reader))` on success where the returned\n"
" `types.Reader` is advanced past the header.\n"
" - `Error(types.DecodeError)` for truncated input or invalid header bytes.\n"
"\n"
" Semantics\n"
" - Supports the compact protocol short and long forms: short form encodes\n"
" small deltas in the header byte; long form encodes an absolute field id\n"
" as a following varint.\n"
).
-spec read_field_header(thrifty@types:reader(), integer()) -> {ok,
{thrifty@types:field_header(), thrifty@types:reader()}} |
{error, thrifty@types:decode_error()}.
read_field_header(Reader, Last_field_id) ->
{reader, Data, Byte_pos, Options} = Reader,
case gleam_stdlib:bit_array_slice(Data, Byte_pos, 1) of
{error, _} ->
{error, unexpected_end_of_input};
{ok, <<Header_byte:8/integer>>} ->
case Header_byte =:= 0 of
true ->
{ok,
{{field_header, 0, stop},
set_position(Reader, Byte_pos + 1, Options)}};
false ->
Type_value = Header_byte rem 16,
Delta = Header_byte div 16,
case Delta =:= 0 of
true ->
case thrifty@varint:decode_varint(
Data,
Byte_pos + 1
) of
{error, E} ->
{error, E};
{ok, {Field_id_raw, Next_pos}} ->
Field_id = thrifty@zigzag:decode_i32(
Field_id_raw
),
case int_to_field_type(Type_value) of
{error, E@1} ->
{error, E@1};
{ok, Field_type} ->
{ok,
{{field_header,
Field_id,
Field_type},
set_position(
Reader,
Next_pos,
Options
)}}
end
end;
false ->
Field_id@1 = Last_field_id + Delta,
case int_to_field_type(Type_value) of
{error, E@2} ->
{error, E@2};
{ok, Field_type@1} ->
{ok,
{{field_header,
Field_id@1,
Field_type@1},
set_position(
Reader,
Byte_pos + 1,
Options
)}}
end
end
end;
{ok, _} ->
{error, {invalid_wire_format, <<"Invalid header byte"/utf8>>}}
end.
-file("src/thrifty/field.gleam", 154).
?DOC(
" Convert a `types.FieldType` to its compact protocol integer nibble.\n"
"\n"
" Inputs\n"
" - `ft`: field type to convert.\n"
"\n"
" Outputs\n"
" - Integer value per Compact Protocol mapping used in header bytes.\n"
).
-spec field_type_to_int(thrifty@types:field_type()) -> integer().
field_type_to_int(Ft) ->
case Ft of
stop ->
0;
bool_true ->
1;
bool_false ->
2;
byte ->
3;
i16 ->
4;
i32 ->
5;
i64 ->
6;
double ->
7;
binary ->
8;
list ->
9;
set ->
10;
map ->
11;
struct ->
12
end.
-file("src/thrifty/field.gleam", 104).
?DOC(
" Encode a field header into a `BitArray` using compact delta encoding.\n"
"\n"
" Inputs\n"
" - `field_id`: absolute field identifier.\n"
" - `field_type`: the `types.FieldType` describing the field payload.\n"
" - `last_field_id`: previous field id for delta calculation.\n"
"\n"
" Outputs\n"
" - Returns a `BitArray` containing either a single header byte (short form)\n"
" or a header byte followed by a varint-encoded absolute field id (long form).\n"
"\n"
" Semantics\n"
" - Short form is used when `1 <= delta <= 15` where `delta = field_id - last_field_id`.\n"
" - Boolean fields use inline header encodings and follow the same delta rules.\n"
).
-spec encode_field_header(integer(), thrifty@types:field_type(), integer()) -> bitstring().
encode_field_header(Field_id, Field_type, Last_field_id) ->
Delta = Field_id - Last_field_id,
case Field_type of
stop ->
<<0:8/integer>>;
bool_true ->
case (Delta > 0) andalso (Delta =< 15) of
true ->
Type_nibble = field_type_to_int(Field_type),
Header_byte = (Delta * 16) + Type_nibble,
<<Header_byte:8/integer>>;
false ->
Varint_bytes = thrifty@varint:encode_varint(
thrifty@zigzag:encode_i32(Field_id)
),
Type_nibble@1 = field_type_to_int(Field_type),
Header_byte@1 = Type_nibble@1,
gleam_stdlib:bit_array_concat(
[<<Header_byte@1:8/integer>>, Varint_bytes]
)
end;
bool_false ->
case (Delta > 0) andalso (Delta =< 15) of
true ->
Type_nibble = field_type_to_int(Field_type),
Header_byte = (Delta * 16) + Type_nibble,
<<Header_byte:8/integer>>;
false ->
Varint_bytes = thrifty@varint:encode_varint(
thrifty@zigzag:encode_i32(Field_id)
),
Type_nibble@1 = field_type_to_int(Field_type),
Header_byte@1 = Type_nibble@1,
gleam_stdlib:bit_array_concat(
[<<Header_byte@1:8/integer>>, Varint_bytes]
)
end;
_ ->
case (Delta > 0) andalso (Delta =< 15) of
true ->
Type_nibble@2 = field_type_to_int(Field_type),
Header_byte@2 = (Delta * 16) + Type_nibble@2,
<<Header_byte@2:8/integer>>;
false ->
Varint_bytes@1 = thrifty@varint:encode_varint(
thrifty@zigzag:encode_i32(Field_id)
),
Type_nibble@3 = field_type_to_int(Field_type),
Header_byte@3 = Type_nibble@3,
gleam_stdlib:bit_array_concat(
[<<Header_byte@3:8/integer>>, Varint_bytes@1]
)
end
end.