-module(protozoa@encode). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/protozoa/encode.gleam"). -export([varint/1, fixed32/1, fixed64/1, length_delimited/1, string/1, tag/2, field/3, int32_field/2, int64_field/2, uint32_field/2, uint64_field/2, string_field/2, bool_field/2, float/1, double/1, float_field/2, double_field/2, zigzag/1, sint32_field/2, sint64_field/2, message/1, varint_size/1, message_size/1, bytes/2, message_field/2, fixed32_field/2, fixed64_field/2, sfixed32_field/2, sfixed64_field/2, repeated_int32_field/2, repeated_int64_field/2, repeated_float_field/2, repeated_double_field/2, repeated_bool_field/2, repeated_sint32_field/2, repeated_sint64_field/2, tag_size/1, fixed32s/2, fixed64s/2]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC( " Protocol Buffer Encode Module\n" "\n" " This module provides functions for encoding Gleam values into Protocol Buffer binary format.\n" " It handles the conversion from typed Gleam data structures to the compact binary wire format\n" " used by Protocol Buffers for efficient storage and network transmission.\n" "\n" " ## Design Philosophy\n" "\n" " - **Correctness**: Produces valid Protocol Buffer binary data compatible with other implementations\n" " - **Efficiency**: Optimized encoding with minimal memory allocations and copies\n" " - **Composability**: Field-level encoders that can be combined for message encoding\n" " - **Type safety**: Compile-time guarantees about the structure of encoded data\n" " - **Deterministic output**: Consistent binary output for the same input data\n" "\n" " ## Capabilities \n" "\n" " - **All proto3 types**: Scalars (int32, int64, string, bool, bytes), messages, enums\n" " - **Advanced features**: Repeated fields, maps, oneofs, nested messages\n" " - **Wire format compliance**: Correct tag encoding, varint encoding, length-delimited data\n" " - **Field-level encoding**: Individual field encoders for fine-grained control \n" " - **Message-level encoding**: Complete message encoders with proper field ordering\n" " - **Size calculation**: Efficient pre-calculation of encoded message sizes\n" "\n" " ## Usage Pattern\n" "\n" " Generated code uses this module to create message-specific encoder functions:\n" " ```gleam\n" " pub fn encode_user(user: User) -> BitArray {\n" " encode.message([\n" " encode.string_field(1, user.name),\n" " encode.int32_field(2, user.age),\n" " ])\n" " }\n" " ```\n" "\n" " ## Wire Format\n" "\n" " The module correctly implements the Protocol Buffer wire format:\n" " - Varint encoding for integers and field tags\n" " - Length-delimited encoding for strings, bytes, and messages \n" " - Fixed-width encoding for fixed32/fixed64 types\n" " - Proper field tag calculation with field numbers and wire types\n" "\n" " ## Performance\n" "\n" " Encoding is optimized for performance with:\n" " - Pre-calculated message sizes to avoid buffer reallocations\n" " - Efficient bit array operations for binary data construction\n" " - Minimal intermediate allocations during encoding\n" ). -file("src/protozoa/encode.gleam", 70). -spec do_varint(integer(), bitstring()) -> bitstring(). do_varint(Value, Acc) -> case Value of V when V < 128 -> gleam_stdlib:bit_array_concat([Acc, <>]); V@1 -> Byte = erlang:'bor'(erlang:'band'(V@1, 16#7F), 16#80), Next_value = erlang:'bsr'(V@1, 7), do_varint( Next_value, gleam_stdlib:bit_array_concat([Acc, <>]) ) end. -file("src/protozoa/encode.gleam", 66). ?DOC( " Encodes an integer as a varint (variable-length integer).\n" " Varints are used for int32, int64, uint32, uint64, bool, and enum fields.\n" " \n" " ## Examples\n" " \n" " ```gleam\n" " varint(0) // <<0>>\n" " varint(127) // <<127>>\n" " varint(128) // <<128, 1>>\n" " ```\n" ). -spec varint(integer()) -> bitstring(). varint(Value) -> do_varint(Value, <<>>). -file("src/protozoa/encode.gleam", 83). ?DOC( " Encodes an integer as a fixed 32-bit value in little-endian format.\n" " Used for fixed32 and sfixed32 fields.\n" ). -spec fixed32(integer()) -> bitstring(). fixed32(Value) -> <>. -file("src/protozoa/encode.gleam", 89). ?DOC( " Encodes an integer as a fixed 64-bit value in little-endian format.\n" " Used for fixed64 and sfixed64 fields.\n" ). -spec fixed64(integer()) -> bitstring(). fixed64(Value) -> <>. -file("src/protozoa/encode.gleam", 96). ?DOC( " Encodes data with a length prefix.\n" " The length is encoded as a varint followed by the data.\n" " Used for strings, bytes, and nested messages.\n" ). -spec length_delimited(bitstring()) -> bitstring(). length_delimited(Data) -> Length = erlang:byte_size(Data), gleam_stdlib:bit_array_concat([varint(Length), Data]). -file("src/protozoa/encode.gleam", 102). ?DOC(" Encodes a string as length-delimited UTF-8 bytes.\n"). -spec string(binary()) -> bitstring(). string(Value) -> Data = gleam_stdlib:identity(Value), length_delimited(Data). -file("src/protozoa/encode.gleam", 109). ?DOC( " Creates a Protocol Buffer tag from a field number and wire type.\n" " The tag is encoded as a varint.\n" ). -spec tag(integer(), protozoa@wire:wire_type()) -> bitstring(). tag(Field_number, Wire_type) -> Tag = protozoa@wire:make_tag(Field_number, Wire_type), varint(Tag). -file("src/protozoa/encode.gleam", 116). ?DOC( " Encodes a complete field with tag and value.\n" " Combines the tag (field number and wire type) with the encoded value.\n" ). -spec field(integer(), protozoa@wire:wire_type(), bitstring()) -> bitstring(). field(Field_number, Wire_type, Value_encoder) -> gleam_stdlib:bit_array_concat([tag(Field_number, Wire_type), Value_encoder]). -file("src/protozoa/encode.gleam", 125). ?DOC(" Encodes an int32 field with tag and value.\n"). -spec int32_field(integer(), integer()) -> bitstring(). int32_field(Field_number, Value) -> field(Field_number, varint, varint(Value)). -file("src/protozoa/encode.gleam", 130). ?DOC(" Encodes an int64 field with tag and value.\n"). -spec int64_field(integer(), integer()) -> bitstring(). int64_field(Field_number, Value) -> field(Field_number, varint, varint(Value)). -file("src/protozoa/encode.gleam", 135). ?DOC(" Encodes a uint32 field with tag and value.\n"). -spec uint32_field(integer(), integer()) -> bitstring(). uint32_field(Field_number, Value) -> field(Field_number, varint, varint(Value)). -file("src/protozoa/encode.gleam", 140). ?DOC(" Encodes a uint64 field with tag and value.\n"). -spec uint64_field(integer(), integer()) -> bitstring(). uint64_field(Field_number, Value) -> field(Field_number, varint, varint(Value)). -file("src/protozoa/encode.gleam", 145). ?DOC(" Encodes a string field with tag and value.\n"). -spec string_field(integer(), binary()) -> bitstring(). string_field(Field_number, Value) -> field(Field_number, length_delimited, string(Value)). -file("src/protozoa/encode.gleam", 151). ?DOC( " Encodes a boolean field with tag and value.\n" " True is encoded as 1, False as 0.\n" ). -spec bool_field(integer(), boolean()) -> bitstring(). bool_field(Field_number, Value) -> Int_value = case Value of true -> 1; false -> 0 end, field(Field_number, varint, varint(Int_value)). -file("src/protozoa/encode.gleam", 160). ?DOC(" Encodes a float as a 32-bit IEEE 754 value in little-endian format.\n"). -spec float(float()) -> bitstring(). float(Value) -> <>. -file("src/protozoa/encode.gleam", 165). ?DOC(" Encodes a double as a 64-bit IEEE 754 value in little-endian format.\n"). -spec double(float()) -> bitstring(). double(Value) -> <>. -file("src/protozoa/encode.gleam", 170). ?DOC(" Encodes a float field with tag and value.\n"). -spec float_field(integer(), float()) -> bitstring(). float_field(Field_number, Value) -> field(Field_number, fixed32, float(Value)). -file("src/protozoa/encode.gleam", 175). ?DOC(" Encodes a double field with tag and value.\n"). -spec double_field(integer(), float()) -> bitstring(). double_field(Field_number, Value) -> field(Field_number, fixed64, double(Value)). -file("src/protozoa/encode.gleam", 192). ?DOC(false). -spec zigzag(integer()) -> integer(). zigzag(Value) -> case Value >= 0 of true -> Value * 2; false -> ((0 - Value) * 2) - 1 end. -file("src/protozoa/encode.gleam", 200). ?DOC(" Encodes a sint32 field (signed int32 with zigzag encoding).\n"). -spec sint32_field(integer(), integer()) -> bitstring(). sint32_field(Field_number, Value) -> field(Field_number, varint, varint(zigzag(Value))). -file("src/protozoa/encode.gleam", 205). ?DOC(" Encodes a sint64 field (signed int64 with zigzag encoding).\n"). -spec sint64_field(integer(), integer()) -> bitstring(). sint64_field(Field_number, Value) -> field(Field_number, varint, varint(zigzag(Value))). -file("src/protozoa/encode.gleam", 210). ?DOC(" Combines multiple encoded fields into a complete Protocol Buffer message.\n"). -spec message(list(bitstring())) -> bitstring(). message(Fields) -> gleam_stdlib:bit_array_concat(Fields). -file("src/protozoa/encode.gleam", 217). ?DOC(false). -spec varint_size(integer()) -> integer(). varint_size(Value) -> case Value of V when V < 0 -> 10; V@1 when V@1 < 128 -> 1; V@2 when V@2 < 16384 -> 2; V@3 when V@3 < 2097152 -> 3; V@4 when V@4 < 268435456 -> 4; V@5 when V@5 < 34359738368 -> 5; V@6 when V@6 < 4398046511104 -> 6; V@7 when V@7 < 562949953421312 -> 7; V@8 when V@8 < 72057594037927936 -> 8; V@9 when V@9 < 9223372036854775808 -> 9; _ -> 10 end. -file("src/protozoa/encode.gleam", 236). ?DOC(false). -spec message_size(list(bitstring())) -> integer(). message_size(Fields) -> gleam@list:fold( Fields, 0, fun(Acc, Field) -> Acc + erlang:byte_size(Field) end ). -file("src/protozoa/encode.gleam", 241). ?DOC(" Encodes a bytes field with tag and length-delimited data.\n"). -spec bytes(integer(), bitstring()) -> bitstring(). bytes(Field_number, Data) -> field(Field_number, length_delimited, length_delimited(Data)). -file("src/protozoa/encode.gleam", 246). ?DOC(" Encodes a nested message field with tag and length-delimited message data.\n"). -spec message_field(integer(), bitstring()) -> bitstring(). message_field(Field_number, Message) -> bytes(Field_number, Message). -file("src/protozoa/encode.gleam", 251). ?DOC(" Encodes a fixed32 field with tag and value.\n"). -spec fixed32_field(integer(), integer()) -> bitstring(). fixed32_field(Field_number, Value) -> field(Field_number, fixed32, fixed32(Value)). -file("src/protozoa/encode.gleam", 256). ?DOC(" Encodes a fixed64 field with tag and value.\n"). -spec fixed64_field(integer(), integer()) -> bitstring(). fixed64_field(Field_number, Value) -> field(Field_number, fixed64, fixed64(Value)). -file("src/protozoa/encode.gleam", 261). ?DOC(" Encodes an sfixed32 field (signed fixed32) with tag and value.\n"). -spec sfixed32_field(integer(), integer()) -> bitstring(). sfixed32_field(Field_number, Value) -> field(Field_number, fixed32, fixed32(Value)). -file("src/protozoa/encode.gleam", 266). ?DOC(" Encodes an sfixed64 field (signed fixed64) with tag and value.\n"). -spec sfixed64_field(integer(), integer()) -> bitstring(). sfixed64_field(Field_number, Value) -> field(Field_number, fixed64, fixed64(Value)). -file("src/protozoa/encode.gleam", 272). ?DOC( " Encodes a packed repeated int32 field.\n" " All values are encoded together and length-delimited.\n" ). -spec repeated_int32_field(integer(), list(integer())) -> bitstring(). repeated_int32_field(Field_number, Values) -> Encoded_values = gleam@list:map(Values, fun(V) -> varint(V) end), Concatenated = gleam_stdlib:bit_array_concat(Encoded_values), field(Field_number, length_delimited, length_delimited(Concatenated)). -file("src/protozoa/encode.gleam", 280). ?DOC( " Encodes a packed repeated int64 field.\n" " All values are encoded together and length-delimited.\n" ). -spec repeated_int64_field(integer(), list(integer())) -> bitstring(). repeated_int64_field(Field_number, Values) -> Encoded_values = gleam@list:map(Values, fun(V) -> varint(V) end), Concatenated = gleam_stdlib:bit_array_concat(Encoded_values), field(Field_number, length_delimited, length_delimited(Concatenated)). -file("src/protozoa/encode.gleam", 288). ?DOC( " Encodes a packed repeated float field.\n" " All values are encoded together and length-delimited.\n" ). -spec repeated_float_field(integer(), list(float())) -> bitstring(). repeated_float_field(Field_number, Values) -> Encoded_values = gleam@list:map(Values, fun(V) -> float(V) end), Concatenated = gleam_stdlib:bit_array_concat(Encoded_values), field(Field_number, length_delimited, length_delimited(Concatenated)). -file("src/protozoa/encode.gleam", 296). ?DOC( " Encodes a packed repeated double field.\n" " All values are encoded together and length-delimited.\n" ). -spec repeated_double_field(integer(), list(float())) -> bitstring(). repeated_double_field(Field_number, Values) -> Encoded_values = gleam@list:map(Values, fun(V) -> double(V) end), Concatenated = gleam_stdlib:bit_array_concat(Encoded_values), field(Field_number, length_delimited, length_delimited(Concatenated)). -file("src/protozoa/encode.gleam", 304). ?DOC( " Encodes a packed repeated boolean field.\n" " All values are encoded together and length-delimited.\n" ). -spec repeated_bool_field(integer(), list(boolean())) -> bitstring(). repeated_bool_field(Field_number, Values) -> Int_values = gleam@list:map(Values, fun(V) -> case V of true -> 1; false -> 0 end end), Encoded_values = gleam@list:map(Int_values, fun(V@1) -> varint(V@1) end), Concatenated = gleam_stdlib:bit_array_concat(Encoded_values), field(Field_number, length_delimited, length_delimited(Concatenated)). -file("src/protozoa/encode.gleam", 319). ?DOC( " Encodes a packed repeated sint32 field with zigzag encoding.\n" " All values are encoded together and length-delimited.\n" ). -spec repeated_sint32_field(integer(), list(integer())) -> bitstring(). repeated_sint32_field(Field_number, Values) -> Zigzagged = gleam@list:map(Values, fun(V) -> zigzag(V) end), Encoded_values = gleam@list:map(Zigzagged, fun(V@1) -> varint(V@1) end), Concatenated = gleam_stdlib:bit_array_concat(Encoded_values), field(Field_number, length_delimited, length_delimited(Concatenated)). -file("src/protozoa/encode.gleam", 328). ?DOC( " Encodes a packed repeated sint64 field with zigzag encoding.\n" " All values are encoded together and length-delimited.\n" ). -spec repeated_sint64_field(integer(), list(integer())) -> bitstring(). repeated_sint64_field(Field_number, Values) -> Zigzagged = gleam@list:map(Values, fun(V) -> zigzag(V) end), Encoded_values = gleam@list:map(Zigzagged, fun(V@1) -> varint(V@1) end), Concatenated = gleam_stdlib:bit_array_concat(Encoded_values), field(Field_number, length_delimited, length_delimited(Concatenated)). -file("src/protozoa/encode.gleam", 337). ?DOC(false). -spec tag_size(integer()) -> integer(). tag_size(Field_number) -> varint_size(protozoa@wire:make_tag(Field_number, varint)). -file("src/protozoa/encode.gleam", 343). ?DOC( " Encodes a packed repeated fixed32 field.\n" " All values are encoded together and length-delimited.\n" ). -spec fixed32s(integer(), list(integer())) -> bitstring(). fixed32s(Field_number, Values) -> Encoded_values = gleam@list:map(Values, fun(V) -> fixed32(V) end), Concatenated = gleam_stdlib:bit_array_concat(Encoded_values), field(Field_number, length_delimited, length_delimited(Concatenated)). -file("src/protozoa/encode.gleam", 351). ?DOC( " Encodes a packed repeated fixed64 field.\n" " All values are encoded together and length-delimited.\n" ). -spec fixed64s(integer(), list(integer())) -> bitstring(). fixed64s(Field_number, Values) -> Encoded_values = gleam@list:map(Values, fun(V) -> fixed64(V) end), Concatenated = gleam_stdlib:bit_array_concat(Encoded_values), field(Field_number, length_delimited, length_delimited(Concatenated)).