Packages

Pure Gleam implementation of the Apache Thrift Compact Protocol

Current section

Files

Jump to
thrifty src thrifty@zigzag.erl
Raw

src/thrifty@zigzag.erl

-module(thrifty@zigzag).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/thrifty/zigzag.gleam").
-export([encode_i32_checked/1, encode_i32/1, decode_i32/1, encode_i64_checked/1, encode_i64/1, decode_i64/1]).
-export_type([zigzag_range_error/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 zigzag_range_error() :: {zigzag_range_error, integer(), integer()}.
-file("src/thrifty/zigzag.gleam", 180).
?DOC(
" Format a `ZigzagRangeError` for logging or panic messages.\n"
"\n"
" Inputs\n"
" - `err`: the error to format.\n"
"\n"
" Outputs\n"
" - Human-readable string describing the out-of-range value and bit width.\n"
).
-spec zigzag_range_error_to_string(zigzag_range_error()) -> binary().
zigzag_range_error_to_string(Err) ->
case Err of
{zigzag_range_error, Value, Bits} ->
<<<<<<<<"Value "/utf8, (erlang:integer_to_binary(Value))/binary>>/binary,
" is outside the supported i"/utf8>>/binary,
(erlang:integer_to_binary(Bits))/binary>>/binary,
" range"/utf8>>
end.
-file("src/thrifty/zigzag.gleam", 166).
?DOC(
" Core zigzag mapping formula: maps signed integers to unsigned integers\n"
" such that small-magnitude signed values map to small unsigned values.\n"
"\n"
" Inputs\n"
" - `n`: signed integer.\n"
"\n"
" Outputs\n"
" - ZigZag-mapped integer (unsigned representation prior to masking).\n"
).
-spec zigzag_encode_formula(integer()) -> integer().
zigzag_encode_formula(N) ->
case N >= 0 of
true ->
N * 2;
false ->
(N * -2) - 1
end.
-file("src/thrifty/zigzag.gleam", 150).
?DOC(
" Ensure an integer is represented as a non-negative residue modulo `modulus`.\n"
"\n"
" Inputs\n"
" - `value`: integer to reduce.\n"
" - `modulus`: modulus used for reduction (e.g., 2^32, 2^64).\n"
"\n"
" Outputs\n"
" - Non-negative integer in 0..modulus-1 representing `value mod modulus`.\n"
).
-spec mask_uint(integer(), integer()) -> integer().
mask_uint(Value, Modulus) ->
Remainder = case Modulus of
0 -> 0;
Gleam@denominator -> Value rem Gleam@denominator
end,
case Remainder < 0 of
true ->
Remainder + Modulus;
false ->
Remainder
end.
-file("src/thrifty/zigzag.gleam", 130).
?DOC(
" Validate that `value` falls within `[min, max]` inclusive and return an\n"
" explicit `ZigzagRangeError` when it does not.\n"
"\n"
" Inputs\n"
" - `value`: integer to validate.\n"
" - `min`, `max`: inclusive bounds.\n"
" - `bits`: bit-width used for error reporting.\n"
"\n"
" Outputs\n"
" - `Ok(value)` when within range.\n"
" - `Error(ZigzagRangeError)` when out of range.\n"
).
-spec check_range(integer(), integer(), integer(), integer()) -> {ok, integer()} |
{error, zigzag_range_error()}.
check_range(Value, Min, Max, Bits) ->
case (Value < Min) orelse (Value > Max) of
true ->
{error, {zigzag_range_error, Value, Bits}};
false ->
{ok, Value}
end.
-file("src/thrifty/zigzag.gleam", 51).
?DOC(
" Checked version of `encode_i32/1` returning an explicit error for out-of-range inputs.\n"
"\n"
" Inputs\n"
" - `n`: signed integer to encode.\n"
"\n"
" Outputs\n"
" - `Ok(Int)` with the ZigZag-encoded unsigned integer when `n` fits in i32.\n"
" - `Error(ZigzagRangeError)` when `n` is outside the i32 representable range.\n"
).
-spec encode_i32_checked(integer()) -> {ok, integer()} |
{error, zigzag_range_error()}.
encode_i32_checked(N) ->
case check_range(N, -2147483648, 2147483647, 32) of
{error, E} ->
{error, E};
{ok, Value} ->
{ok, mask_uint(zigzag_encode_formula(Value), 4294967296)}
end.
-file("src/thrifty/zigzag.gleam", 36).
?DOC(
" Encode a signed 32-bit integer into an unsigned integer using ZigZag.\n"
"\n"
" Inputs\n"
" - `n`: signed integer expected to fit in 32-bit signed range.\n"
"\n"
" Outputs\n"
" - Returns the ZigZag-encoded unsigned integer.\n"
"\n"
" Error modes\n"
" - Panics when `n` is outside the supported i32 range. Use\n"
" `encode_i32_checked/1` to receive an explicit error instead of panicking.\n"
).
-spec encode_i32(integer()) -> integer().
encode_i32(N) ->
case encode_i32_checked(N) of
{ok, Value} ->
Value;
{error, Err} ->
erlang:error(#{gleam_error => panic,
message => zigzag_range_error_to_string(Err),
file => <<?FILEPATH/utf8>>,
module => <<"thrifty/zigzag"/utf8>>,
function => <<"encode_i32"/utf8>>,
line => 39})
end.
-file("src/thrifty/zigzag.gleam", 65).
?DOC(
" Decode a ZigZag-encoded unsigned integer back to signed i32.\n"
"\n"
" Inputs\n"
" - `z`: ZigZag-encoded unsigned integer.\n"
"\n"
" Outputs\n"
" - Returns the decoded signed integer.\n"
).
-spec decode_i32(integer()) -> integer().
decode_i32(Z) ->
case (Z rem 2) =:= 0 of
true ->
Z div 2;
false ->
(0 - (Z div 2)) - 1
end.
-file("src/thrifty/zigzag.gleam", 98).
?DOC(
" Checked version of `encode_i64/1` returning an explicit error for out-of-range inputs.\n"
"\n"
" Inputs\n"
" - `n`: signed integer to encode.\n"
"\n"
" Outputs\n"
" - `Ok(Int)` with the ZigZag-encoded unsigned integer when `n` fits in i64.\n"
" - `Error(ZigzagRangeError)` when `n` is outside the i64 representable range.\n"
).
-spec encode_i64_checked(integer()) -> {ok, integer()} |
{error, zigzag_range_error()}.
encode_i64_checked(N) ->
case check_range(N, -9223372036854775808, 9223372036854775807, 64) of
{error, E} ->
{error, E};
{ok, Value} ->
{ok, mask_uint(zigzag_encode_formula(Value), 18446744073709551616)}
end.
-file("src/thrifty/zigzag.gleam", 83).
?DOC(
" Encode a signed 64-bit integer into an unsigned integer using ZigZag.\n"
"\n"
" Inputs\n"
" - `n`: signed integer expected to fit in 64-bit signed range.\n"
"\n"
" Outputs\n"
" - Returns the ZigZag-encoded unsigned integer.\n"
"\n"
" Error modes\n"
" - Panics when `n` is outside the supported i64 range. Use\n"
" `encode_i64_checked/1` to receive an explicit error instead of panicking.\n"
).
-spec encode_i64(integer()) -> integer().
encode_i64(N) ->
case encode_i64_checked(N) of
{ok, Value} ->
Value;
{error, Err} ->
erlang:error(#{gleam_error => panic,
message => zigzag_range_error_to_string(Err),
file => <<?FILEPATH/utf8>>,
module => <<"thrifty/zigzag"/utf8>>,
function => <<"encode_i64"/utf8>>,
line => 86})
end.
-file("src/thrifty/zigzag.gleam", 112).
?DOC(
" Decode a ZigZag-encoded unsigned integer back to signed i64.\n"
"\n"
" Inputs\n"
" - `z`: ZigZag-encoded unsigned integer.\n"
"\n"
" Outputs\n"
" - Returns the decoded signed integer.\n"
).
-spec decode_i64(integer()) -> integer().
decode_i64(Z) ->
case (Z rem 2) =:= 0 of
true ->
Z div 2;
false ->
(0 - (Z div 2)) - 1
end.