-module(thrifty@message). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/thrifty/message.gleam"). -export([encode_message_header/1, decode_message_header/2]). -export_type([message_type/0, message_header/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 message_type() :: call | reply | exception | oneway. -type message_header() :: {message_header, binary(), message_type(), integer()}. -file("src/thrifty/message.gleam", 181). ?DOC( " Convert a `MessageType` to the protocol numeric value used in the\n" " version/type byte.\n" "\n" " Inputs\n" " - `mt`: message type enum.\n" "\n" " Outputs\n" " - Integer value used in encoding the version/type byte.\n" ). -spec message_type_to_int(message_type()) -> integer(). message_type_to_int(Mt) -> case Mt of call -> 1; reply -> 2; exception -> 3; oneway -> 4 end. -file("src/thrifty/message.gleam", 50). ?DOC( " Encode a Thrift message header to a `BitArray` using Compact Protocol\n" " framing.\n" "\n" " Inputs\n" " - `header`: a `MessageHeader` record with name, message_type and sequence id.\n" "\n" " Outputs\n" " - Returns a `BitArray` containing the protocol id, version/type byte,\n" " varint-encoded sequence id, varint length of method name and UTF-8\n" " bytes for the method name.\n" "\n" " Format\n" " - Protocol ID: 0x82 (1 byte)\n" " - Version & Type: (version << 5) | type (1 byte, version=1)\n" " - Sequence ID: varint i32\n" " - Method name: length (varint) + UTF-8 bytes\n" ). -spec encode_message_header(message_header()) -> bitstring(). encode_message_header(Header) -> Protocol_id = 16#82, Version = 1, Type_value = message_type_to_int(erlang:element(3, Header)), Version_and_type = (Version * 32) + Type_value, Seq_id_u32 = ((erlang:element(4, Header) rem 4294967296) + 4294967296) rem 4294967296, Seq_id_varint = thrifty@varint:encode_varint(Seq_id_u32), Name_bytes = begin _pipe = gleam@string:to_utf_codepoints(erlang:element(2, Header)), _pipe@1 = gleam_stdlib:utf_codepoint_list_to_string(_pipe), gleam_stdlib:identity(_pipe@1) end, Name_length = erlang:byte_size(Name_bytes), Name_length_varint = thrifty@varint:encode_varint(Name_length), <>. -file("src/thrifty/message.gleam", 198). ?DOC( " Convert a numeric message type to `MessageType`.\n" "\n" " Inputs\n" " - `n`: numeric type extracted from the version/type byte.\n" "\n" " Outputs\n" " - `Ok(MessageType)` when recognized.\n" " - `Error(types.UnsupportedType(n))` when unknown.\n" ). -spec int_to_message_type(integer()) -> {ok, message_type()} | {error, thrifty@types:decode_error()}. int_to_message_type(N) -> case N of 1 -> {ok, call}; 2 -> {ok, reply}; 3 -> {ok, exception}; 4 -> {ok, oneway}; _ -> {error, {unsupported_type, N}} end. -file("src/thrifty/message.gleam", 89). ?DOC( " Decode a Thrift message header from `data` starting at `byte_pos`.\n" "\n" " Inputs\n" " - `data`: the `BitArray` containing the encoded message header and payload.\n" " - `byte_pos`: byte offset where the header begins.\n" "\n" " Outputs\n" " - `Ok(#(MessageHeader, next_byte_position))` on success where\n" " `next_byte_position` points after the method name bytes.\n" " - `Error(types.DecodeError)` on protocol mismatch, unsupported version,\n" " invalid varint encodings, or invalid UTF-8 in the method name.\n" ). -spec decode_message_header(bitstring(), integer()) -> {ok, {message_header(), integer()}} | {error, thrifty@types:decode_error()}. decode_message_header(Data, Byte_pos) -> case gleam_stdlib:bit_array_slice(Data, Byte_pos, 1) of {error, _} -> {error, unexpected_end_of_input}; {ok, <>} -> case Protocol_id =:= 16#82 of false -> {error, {invalid_wire_format, <<"Invalid protocol ID"/utf8>>}}; true -> case gleam_stdlib:bit_array_slice(Data, Byte_pos + 1, 1) of {error, _} -> {error, unexpected_end_of_input}; {ok, <>} -> Version = Version_and_type div 32, Type_value = Version_and_type rem 32, case Version =:= 1 of false -> {error, {invalid_wire_format, <<"Unsupported version"/utf8>>}}; true -> case int_to_message_type(Type_value) of {error, E} -> {error, E}; {ok, Msg_type} -> case thrifty@varint:decode_varint( Data, Byte_pos + 2 ) of {error, E@1} -> {error, E@1}; {ok, {Seq_id_raw, Pos_after_seq}} -> Seq_id = case Seq_id_raw > 2147483647 of true -> Seq_id_raw - 4294967296; false -> Seq_id_raw end, case thrifty@varint:decode_varint( Data, Pos_after_seq ) of {error, E@2} -> {error, E@2}; {ok, {Name_length, Name_bytes_start}} -> case gleam_stdlib:bit_array_slice( Data, Name_bytes_start, Name_length ) of {error, _} -> {error, unexpected_end_of_input}; {ok, Name_bytes} -> case gleam@bit_array:to_string( Name_bytes ) of {error, _} -> {error, {invalid_wire_format, <<"Invalid UTF-8 in method name"/utf8>>}}; {ok, Name} -> Next_pos = Name_bytes_start + Name_length, Header = {message_header, Name, Msg_type, Seq_id}, {ok, {Header, Next_pos}} end end end end end end; {ok, _} -> {error, {invalid_wire_format, <<"Invalid version/type byte"/utf8>>}} end end; {ok, _} -> {error, {invalid_wire_format, <<"Invalid protocol ID byte"/utf8>>}} end.