Current section
Files
Jump to
Current section
Files
src/protozoa@encode.erl
-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/integer>>]);
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, <<Byte/integer>>])
)
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) ->
<<Value:32/little>>.
-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) ->
<<Value:64/little>>.
-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) ->
<<Value:32/float-little>>.
-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) ->
<<Value:64/float-little>>.
-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)).