Packages

MessagePack (msgpack) implementation for Gleam

Current section

Files

Jump to
glepack src glepack@encode.erl
Raw

src/glepack@encode.erl

-module(glepack@encode).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([nil/0, boolean/1, integer/1, float/1, string/1, binary/1, extension/2, value/1, array/1, map/1]).
-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(" This module provides functions to encode various data types into MessagePack format.\n").
-file("src/glepack/encode.gleam", 14).
?DOC(" Encode a nil value into MessagePack format\n").
-spec nil() -> {ok, bitstring()} | {error, nil}.
nil() ->
{ok, <<16#c0>>}.
-file("src/glepack/encode.gleam", 19).
?DOC(" Encode a boolean value into MessagePack format\n").
-spec boolean(boolean()) -> {ok, bitstring()} | {error, nil}.
boolean(Value) ->
case Value of
true ->
{ok, <<16#c3>>};
false ->
{ok, <<16#c2>>}
end.
-file("src/glepack/encode.gleam", 28).
?DOC(
" Encode an integer value into MessagePack format\n"
" The function returns a Result containing the encoded BitArray or an error.\n"
).
-spec integer(integer()) -> {ok, bitstring()} | {error, nil}.
integer(Value) ->
case Value of
N when (N >= 0) andalso (N =< 127) ->
{ok, <<N:8>>};
N@1 when (N@1 >= -32) andalso (N@1 =< -1) ->
Unsigned = 256 + N@1,
{ok, <<Unsigned:8>>};
N@2 when (N@2 >= 0) andalso (N@2 =< 255) ->
{ok, <<16#cc, N@2:8>>};
N@3 when (N@3 >= 0) andalso (N@3 =< 65535) ->
High_byte = N@3 div 256,
Low_byte = N@3 rem 256,
{ok, <<16#cd, High_byte:8, Low_byte:8>>};
N@4 when (N@4 >= 0) andalso (N@4 =< 4294967295) ->
B1 = (N@4 div 16777216) rem 256,
B2 = (N@4 div 65536) rem 256,
B3 = (N@4 div 256) rem 256,
B4 = N@4 rem 256,
{ok, <<16#ce, B1:8, B2:8, B3:8, B4:8>>};
N@5 when (N@5 >= -128) andalso (N@5 =< -33) ->
Unsigned@1 = 256 + N@5,
{ok, <<16#d0, Unsigned@1:8>>};
N@6 when (N@6 >= -32768) andalso (N@6 =< -129) ->
Unsigned@2 = 65536 + N@6,
High_byte@1 = Unsigned@2 div 256,
Low_byte@1 = Unsigned@2 rem 256,
{ok, <<16#d1, High_byte@1:8, Low_byte@1:8>>};
N@7 when (N@7 >= -2147483648) andalso (N@7 =< -32769) ->
Unsigned@3 = 4294967296 + N@7,
B1@1 = (Unsigned@3 div 16777216) rem 256,
B2@1 = (Unsigned@3 div 65536) rem 256,
B3@1 = (Unsigned@3 div 256) rem 256,
B4@1 = Unsigned@3 rem 256,
{ok, <<16#d2, B1@1:8, B2@1:8, B3@1:8, B4@1:8>>};
N@8 when N@8 < -2147483648 ->
Unsigned@4 = 18446744073709551616 + N@8,
B1@2 = (Unsigned@4 div 72057594037927936) rem 256,
B2@2 = (Unsigned@4 div 281474976710656) rem 256,
B3@2 = (Unsigned@4 div 1099511627776) rem 256,
B4@2 = (Unsigned@4 div 4294967296) rem 256,
B5 = (Unsigned@4 div 16777216) rem 256,
B6 = (Unsigned@4 div 65536) rem 256,
B7 = (Unsigned@4 div 256) rem 256,
B8 = Unsigned@4 rem 256,
{ok,
<<16#d3,
B1@2:8,
B2@2:8,
B3@2:8,
B4@2:8,
B5:8,
B6:8,
B7:8,
B8:8>>};
N@9 when N@9 > 4294967295 ->
B1@3 = (N@9 div 72057594037927936) rem 256,
B2@3 = (N@9 div 281474976710656) rem 256,
B3@3 = (N@9 div 1099511627776) rem 256,
B4@3 = (N@9 div 4294967296) rem 256,
B5@1 = (N@9 div 16777216) rem 256,
B6@1 = (N@9 div 65536) rem 256,
B7@1 = (N@9 div 256) rem 256,
B8@1 = N@9 rem 256,
{ok,
<<16#d3,
B1@3:8,
B2@3:8,
B3@3:8,
B4@3:8,
B5@1:8,
B6@1:8,
B7@1:8,
B8@1:8>>};
_ ->
{error, nil}
end.
-file("src/glepack/encode.gleam", 111).
?DOC(
" Encode a floating-point value into MessagePack format\n"
" The function returns a Result containing the encoded BitArray or an error.\n"
).
-spec float(float()) -> {ok, bitstring()} | {error, nil}.
float(Value) ->
{ok, float:encode_float64(Value)}.
-file("src/glepack/encode.gleam", 118).
?DOC(
" Encode a string value into MessagePack format\n"
" The function returns a Result containing the encoded BitArray or an error.\n"
" The string is encoded as UTF-8.\n"
).
-spec string(binary()) -> {ok, bitstring()} | {error, nil}.
string(Value) ->
Bytes = gleam_stdlib:identity(Value),
Size = erlang:byte_size(Value),
case Size of
N when N =< 31 ->
Format = 16#a0 + N,
{ok, gleam@bit_array:append(<<Format:8>>, Bytes)};
N@1 when N@1 =< 255 ->
{ok, gleam@bit_array:append(<<16#d9, N@1:8>>, Bytes)};
N@2 when N@2 =< 65535 ->
High_byte = N@2 div 256,
Low_byte = N@2 rem 256,
{ok,
gleam@bit_array:append(
<<16#da, High_byte:8, Low_byte:8>>,
Bytes
)};
N@3 ->
B1 = (N@3 div 16777216) rem 256,
B2 = (N@3 div 65536) rem 256,
B3 = (N@3 div 256) rem 256,
B4 = N@3 rem 256,
{ok,
gleam@bit_array:append(<<16#db, B1:8, B2:8, B3:8, B4:8>>, Bytes)}
end.
-file("src/glepack/encode.gleam", 151).
?DOC(
" Encode a binary value into MessagePack format\n"
" The function returns a Result containing the encoded BitArray or an error.\n"
).
-spec binary(bitstring()) -> {ok, bitstring()} | {error, nil}.
binary(Value) ->
Size = erlang:byte_size(Value),
case Size of
N when N =< 255 ->
{ok, gleam@bit_array:append(<<16#c4, N:8>>, Value)};
N@1 when N@1 =< 65535 ->
High_byte = N@1 div 256,
Low_byte = N@1 rem 256,
{ok,
gleam@bit_array:append(
<<16#c5, High_byte:8, Low_byte:8>>,
Value
)};
N@2 ->
B1 = (N@2 div 16777216) rem 256,
B2 = (N@2 div 65536) rem 256,
B3 = (N@2 div 256) rem 256,
B4 = N@2 rem 256,
{ok,
gleam@bit_array:append(<<16#c6, B1:8, B2:8, B3:8, B4:8>>, Value)}
end.
-file("src/glepack/encode.gleam", 314).
?DOC(
" Encode a MessagePack extension value\n"
" The function takes a type ID and a BitArray of data, and returns a Result\n"
" containing the encoded BitArray or an error.\n"
" The type ID is an integer that identifies the type of extension data.\n"
" The data is a BitArray representing the extension data.\n"
).
-spec extension(integer(), bitstring()) -> {ok, bitstring()} | {error, nil}.
extension(Type_id, Data) ->
Size = erlang:byte_size(Data),
case Size of
1 ->
{ok, gleam@bit_array:append(<<16#d4, Type_id:8>>, Data)};
2 ->
{ok, gleam@bit_array:append(<<16#d5, Type_id:8>>, Data)};
4 ->
{ok, gleam@bit_array:append(<<16#d6, Type_id:8>>, Data)};
8 ->
{ok, gleam@bit_array:append(<<16#d7, Type_id:8>>, Data)};
16 ->
{ok, gleam@bit_array:append(<<16#d8, Type_id:8>>, Data)};
N when N =< 255 ->
{ok, gleam@bit_array:append(<<16#c7, N:8, Type_id:8>>, Data)};
N@1 when N@1 =< 65535 ->
High_byte = N@1 div 256,
Low_byte = N@1 rem 256,
{ok,
gleam@bit_array:append(
<<16#c8, High_byte:8, Low_byte:8, Type_id:8>>,
Data
)};
N@2 ->
B1 = (N@2 div 16777216) rem 256,
B2 = (N@2 div 65536) rem 256,
B3 = (N@2 div 256) rem 256,
B4 = N@2 rem 256,
{ok,
gleam@bit_array:append(
<<16#c9, B1:8, B2:8, B3:8, B4:8, Type_id:8>>,
Data
)}
end.
-file("src/glepack/encode.gleam", 295).
?DOC(" Helper function to encode a single value based on its type\n").
-spec value(glepack@data:value()) -> {ok, bitstring()} | {error, nil}.
value(Value) ->
case Value of
nil ->
nil();
{boolean, B} ->
boolean(B);
{integer, I} ->
integer(I);
{float, F} ->
float(F);
{string, S} ->
string(S);
{binary, B@1} ->
binary(B@1);
{array, A} ->
array(A);
{map, M} ->
map(M);
{extension, Type_id, Data} ->
extension(Type_id, Data)
end.
-file("src/glepack/encode.gleam", 177).
?DOC(
" Encode an array of values into MessagePack format\n"
" The function returns a Result containing the encoded BitArray or an error.\n"
).
-spec array(list(glepack@data:value())) -> {ok, bitstring()} | {error, nil}.
array(Values) ->
Size = erlang:length(Values),
Header = case Size of
N when N =< 15 ->
Format = 16#90 + N,
{ok, <<Format:8>>};
N@1 when N@1 =< 65535 ->
High_byte = N@1 div 256,
Low_byte = N@1 rem 256,
{ok, <<16#dc, High_byte:8, Low_byte:8>>};
N@2 ->
B1 = (N@2 div 16777216) rem 256,
B2 = (N@2 div 65536) rem 256,
B3 = (N@2 div 256) rem 256,
B4 = N@2 rem 256,
{ok, <<16#dd, B1:8, B2:8, B3:8, B4:8>>}
end,
case Header of
{error, E} ->
{error, E};
{ok, Header_bytes} ->
encode_array_elements(Values, Header_bytes)
end.
-file("src/glepack/encode.gleam", 210).
-spec encode_array_elements(list(glepack@data:value()), bitstring()) -> {ok,
bitstring()} |
{error, nil}.
encode_array_elements(Elements, Acc) ->
case Elements of
[] ->
{ok, Acc};
[Elem | Rest] ->
case value(Elem) of
{error, E} ->
{error, E};
{ok, Encoded_elem} ->
New_acc = gleam@bit_array:append(Acc, Encoded_elem),
encode_array_elements(Rest, New_acc)
end
end.
-file("src/glepack/encode.gleam", 267).
-spec encode_key_value_pairs(
list({glepack@data:value(), glepack@data:value()}),
bitstring()
) -> {ok, bitstring()} | {error, nil}.
encode_key_value_pairs(Pairs, Acc) ->
case Pairs of
[] ->
{ok, Acc};
[{Key, Val} | Rest] ->
case value(Key) of
{error, E} ->
{error, E};
{ok, Encoded_key} ->
case value(Val) of
{error, E@1} ->
{error, E@1};
{ok, Encoded_val} ->
New_acc = gleam@bit_array:append(Acc, Encoded_key),
New_acc@1 = gleam@bit_array:append(
New_acc,
Encoded_val
),
encode_key_value_pairs(Rest, New_acc@1)
end
end
end.
-file("src/glepack/encode.gleam", 232).
?DOC(
" Encode a map of key-value pairs into MessagePack format\n"
" The function returns a Result containing the encoded BitArray or an error.\n"
).
-spec map(gleam@dict:dict(glepack@data:value(), glepack@data:value())) -> {ok,
bitstring()} |
{error, nil}.
map(Value) ->
Size = maps:size(Value),
Header = case Size of
M when M =< 15 ->
Format = 16#80 + M,
{ok, <<Format:8>>};
M@1 when M@1 =< 65535 ->
High_byte = M@1 div 256,
Low_byte = M@1 rem 256,
{ok, <<16#de, High_byte:8, Low_byte:8>>};
M@2 ->
B1 = (M@2 div 16777216) rem 256,
B2 = (M@2 div 65536) rem 256,
B3 = (M@2 div 256) rem 256,
B4 = M@2 rem 256,
{ok, <<16#df, B1:8, B2:8, B3:8, B4:8>>}
end,
case Header of
{error, E} ->
{error, E};
{ok, Header_bytes} ->
_pipe = maps:to_list(Value),
encode_key_value_pairs(_pipe, Header_bytes)
end.