-module(packkit@snappy).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/packkit/snappy.gleam").
-export([codec/0, raw_decode_with_limits/2, raw_decode/1, decode_with_limits/2, decode/1, raw_encode/1, encode/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(
" Snappy raw-block and framed codec.\n"
"\n"
" `snappy.raw_decode` and `snappy.raw_encode` operate on the original\n"
" Snappy block format documented in `snappy-format-description`.\n"
" `snappy.decode` and `snappy.encode` operate on the streaming\n"
" framed form (`sNaPpY` stream identifier and chunked layout). The\n"
" raw encoder runs a greedy 4-byte hash-chain match-finder and\n"
" emits literal + copy-1 / copy-2 / copy-4 sequences in the\n"
" canonical block layout; the framed encoder dispatches each chunk\n"
" through the raw encoder and picks the smaller of the compressed\n"
" (`0x00`) and uncompressed (`0x01`) chunk types.\n"
).
-file("src/packkit/snappy.gleam", 39).
?DOC(" Snappy framed codec smart constructor.\n").
-spec codec() -> packkit@codec:codec().
codec() ->
packkit@codec:snappy().
-file("src/packkit/snappy.gleam", 258).
-spec read_varint(bitstring(), integer(), integer()) -> {ok,
{integer(), bitstring()}} |
{error, packkit@error:codec_error()}.
read_varint(Bytes, Acc, Shift) ->
case Bytes of
<<B, Rest/binary>> ->
Part = erlang:'band'(B, 16#7F),
Acc@1 = erlang:'bor'(Acc, erlang:'bsl'(Part, Shift)),
case erlang:'band'(B, 16#80) of
0 ->
{ok, {Acc@1, Rest}};
_ ->
case Shift > 28 of
true ->
{error,
{codec_invalid_data,
<<"snappy: oversize varint"/utf8>>}};
false ->
read_varint(Rest, Acc@1, Shift + 7)
end
end;
_ ->
{error,
{codec_invalid_data, <<"snappy: truncated varint length"/utf8>>}}
end.
-file("src/packkit/snappy.gleam", 286).
-spec write_varint_loop(integer(), bitstring()) -> bitstring().
write_varint_loop(Value, Acc) ->
case Value < 16#80 of
true ->
gleam_stdlib:bit_array_concat([Acc, <<Value>>]);
false ->
Low = erlang:'band'(Value, 16#7F),
High = erlang:'bsr'(Value, 7),
Byte_value = erlang:'bor'(Low, 16#80),
write_varint_loop(
High,
gleam_stdlib:bit_array_concat([Acc, <<Byte_value>>])
)
end.
-file("src/packkit/snappy.gleam", 282).
-spec write_varint(integer()) -> bitstring().
write_varint(Value) ->
write_varint_loop(Value, <<>>).
-file("src/packkit/snappy.gleam", 369).
-spec read_le(bitstring(), integer()) -> integer().
read_le(Bytes, Width) ->
case {Width, Bytes} of
{1, <<B>>} ->
B;
{2, <<B1, B2>>} ->
B1 + (B2 * 256);
{3, <<B1@1, B2@1, B3>>} ->
(B1@1 + (B2@1 * 256)) + (B3 * 65536);
{4, <<B1@2, B2@2, B3@1, B4>>} ->
((B1@2 + (B2@2 * 256)) + (B3@1 * 65536)) + (B4 * 16777216);
{_, _} ->
0
end.
-file("src/packkit/snappy.gleam", 350).
-spec read_literal_extra(bitstring(), integer()) -> {ok,
{integer(), bitstring()}} |
{error, packkit@error:codec_error()}.
read_literal_extra(Rest, Width) ->
case erlang:byte_size(Rest) < Width of
true ->
{error,
{codec_invalid_data,
<<"snappy: literal length extension truncated"/utf8>>}};
false ->
Prefix@1 = case gleam_stdlib:bit_array_slice(Rest, 0, Width) of
{ok, Prefix} -> Prefix;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/snappy"/utf8>>,
function => <<"read_literal_extra"/utf8>>,
line => 360,
value => _assert_fail,
start => 11132,
'end' => 11187,
pattern_start => 11143,
pattern_end => 11153})
end,
After@1 = case gleam_stdlib:bit_array_slice(
Rest,
Width,
erlang:byte_size(Rest) - Width
) of
{ok, After} -> After;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/snappy"/utf8>>,
function => <<"read_literal_extra"/utf8>>,
line => 361,
value => _assert_fail@1,
start => 11194,
'end' => 11288,
pattern_start => 11205,
pattern_end => 11214})
end,
Value = read_le(Prefix@1, Width),
{ok, {Value + 1, After@1}}
end.
-file("src/packkit/snappy.gleam", 606).
-spec build_snappy_byte_table(
bitstring(),
integer(),
gleam@dict:dict(integer(), integer())
) -> gleam@dict:dict(integer(), integer()).
build_snappy_byte_table(Bytes, Index, Acc) ->
case Bytes of
<<B, Rest/binary>> ->
build_snappy_byte_table(
Rest,
Index + 1,
gleam@dict:insert(Acc, Index, B)
);
_ ->
Acc
end.
-file("src/packkit/snappy.gleam", 618).
-spec snappy_byte_at(gleam@dict:dict(integer(), integer()), integer()) -> integer().
snappy_byte_at(Table, Index) ->
case gleam_stdlib:map_get(Table, Index) of
{ok, B} ->
B;
_ ->
0
end.
-file("src/packkit/snappy.gleam", 625).
-spec snappy_hash4(integer(), integer(), integer(), integer()) -> integer().
snappy_hash4(B0, B1, B2, B3) ->
Combined = erlang:'bor'(
B0,
erlang:'bor'(
erlang:'bsl'(B1, 8),
erlang:'bor'(erlang:'bsl'(B2, 16), erlang:'bsl'(B3, 24))
)
),
erlang:'band'(Combined * 2654435761, 16#FFFF).
-file("src/packkit/snappy.gleam", 640).
-spec snappy_bytes4_equal(
gleam@dict:dict(integer(), integer()),
integer(),
integer()
) -> boolean().
snappy_bytes4_equal(Table, P1, P2) ->
(((snappy_byte_at(Table, P1) =:= snappy_byte_at(Table, P2)) andalso (snappy_byte_at(
Table,
P1 + 1
)
=:= snappy_byte_at(Table, P2 + 1)))
andalso (snappy_byte_at(Table, P1 + 2) =:= snappy_byte_at(Table, P2 + 2)))
andalso (snappy_byte_at(Table, P1 + 3) =:= snappy_byte_at(Table, P2 + 3)).
-file("src/packkit/snappy.gleam", 647).
-spec snappy_match_length(
gleam@dict:dict(integer(), integer()),
integer(),
integer(),
integer(),
integer()
) -> integer().
snappy_match_length(Table, Base, Cursor, Limit_pos, Acc) ->
case (Cursor + Acc) >= Limit_pos of
true ->
Acc;
false ->
case snappy_byte_at(Table, Base + Acc) =:= snappy_byte_at(
Table,
Cursor + Acc
) of
true ->
snappy_match_length(Table, Base, Cursor, Limit_pos, Acc + 1);
false ->
Acc
end
end.
-file("src/packkit/snappy.gleam", 694).
-spec snappy_slice(
gleam@dict:dict(integer(), integer()),
integer(),
integer(),
bitstring()
) -> bitstring().
snappy_slice(Table, Start, Count, Acc) ->
case Count of
0 ->
Acc;
_ ->
snappy_slice(
Table,
Start + 1,
Count - 1,
<<Acc/bitstring, (snappy_byte_at(Table, Start))>>
)
end.
-file("src/packkit/snappy.gleam", 714).
?DOC(
" Emit one or more copy records that together cover a single LZ77\n"
" match. The Snappy 1-byte offset form caps match length at 11; the\n"
" 2- and 4-byte forms cap at 64. Matches longer than 64 are split\n"
" into multiple back-to-back copies sharing the same offset.\n"
).
-spec emit_copy_for(integer(), integer(), bitstring()) -> bitstring().
emit_copy_for(Offset, Length, Acc) ->
case Length of
0 ->
Acc;
_ ->
case ((Offset < 2048) andalso (Length >= 4)) andalso (Length =< 11) of
true ->
Tag = erlang:'bor'(
erlang:'bsl'(Length - 4, 2),
erlang:'bor'(
erlang:'bsl'(erlang:'bsr'(Offset, 8), 5),
1
)
),
<<Acc/bitstring, Tag, (erlang:'band'(Offset, 16#FF))>>;
false ->
Chunk = case Length > 64 of
true ->
64;
false ->
Length
end,
Piece = case Offset < 65536 of
true ->
Tag@1 = erlang:'bor'(erlang:'bsl'(Chunk - 1, 2), 2),
<<Tag@1, Offset:16/little>>;
false ->
Tag@2 = erlang:'bor'(erlang:'bsl'(Chunk - 1, 2), 3),
<<Tag@2, Offset:32/little>>
end,
emit_copy_for(
Offset,
Length - Chunk,
<<Acc/bitstring, Piece/bitstring>>
)
end
end.
-file("src/packkit/snappy.gleam", 772).
-spec literal_extension(integer()) -> {bitstring(), integer()}.
literal_extension(Encoded_len) ->
case Encoded_len < 16#100 of
true ->
{<<Encoded_len>>, 1};
false ->
case Encoded_len < 16#10000 of
true ->
{<<Encoded_len:16/little>>, 2};
false ->
case Encoded_len < 16#1000000 of
true ->
{<<Encoded_len:24/little>>, 3};
false ->
{<<Encoded_len:32/little>>, 4}
end
end
end.
-file("src/packkit/snappy.gleam", 751).
-spec emit_literal(bitstring()) -> bitstring().
emit_literal(Bytes) ->
Length = erlang:byte_size(Bytes),
case Length of
0 ->
<<>>;
_ ->
Encoded_len = Length - 1,
Header = case Encoded_len < 60 of
true ->
<<(erlang:'bsl'(Encoded_len, 2))>>;
false ->
{Extra, Width} = literal_extension(Encoded_len),
gleam_stdlib:bit_array_concat(
[<<(erlang:'bsl'((60 + Width) - 1, 2))>>, Extra]
)
end,
gleam_stdlib:bit_array_concat([Header, Bytes])
end.
-file("src/packkit/snappy.gleam", 787).
-spec append_with_limit(bitstring(), bitstring(), packkit@limit:limits()) -> {ok,
bitstring()} |
{error, packkit@error:codec_error()}.
append_with_limit(Output, Chunk, Limits) ->
Projected = erlang:byte_size(Output) + erlang:byte_size(Chunk),
case Projected > packkit@limit:max_output_bytes(Limits) of
true ->
{error,
{codec_limit_exceeded, <<"max_output_bytes"/utf8>>, Projected}};
false ->
{ok, gleam_stdlib:bit_array_concat([Output, Chunk])}
end.
-file("src/packkit/snappy.gleam", 223).
-spec decode_uncompressed_chunk(
bitstring(),
bitstring(),
packkit@limit:limits()
) -> {ok, bitstring()} | {error, packkit@error:codec_error()}.
decode_uncompressed_chunk(Body, Output, Limits) ->
case Body of
<<_:32/little, Data/binary>> ->
append_with_limit(Output, Data, Limits);
_ ->
{error,
{codec_invalid_data,
<<"snappy: uncompressed chunk too short"/utf8>>}}
end.
-file("src/packkit/snappy.gleam", 455).
-spec copy_byte_by_byte(
bitstring(),
integer(),
integer(),
packkit@limit:limits()
) -> {ok, bitstring()} | {error, packkit@error:codec_error()}.
copy_byte_by_byte(Output, Offset, Length, Limits) ->
case Length of
0 ->
{ok, Output};
_ ->
Size = erlang:byte_size(Output),
Byte_slice@1 = case gleam_stdlib:bit_array_slice(
Output,
Size - Offset,
1
) of
{ok, Byte_slice} -> Byte_slice;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/snappy"/utf8>>,
function => <<"copy_byte_by_byte"/utf8>>,
line => 465,
value => _assert_fail,
start => 13981,
'end' => 14050,
pattern_start => 13992,
pattern_end => 14006})
end,
gleam@result:'try'(
append_with_limit(Output, Byte_slice@1, Limits),
fun(New_output) ->
copy_byte_by_byte(New_output, Offset, Length - 1, Limits)
end
)
end.
-file("src/packkit/snappy.gleam", 666).
-spec snappy_insert_hashes(
gleam@dict:dict(integer(), integer()),
gleam@dict:dict(integer(), integer()),
integer(),
integer(),
integer()
) -> gleam@dict:dict(integer(), integer()).
snappy_insert_hashes(Table, Hashes, From, To, Size) ->
case (From > To) orelse ((From + 4) > Size) of
true ->
Hashes;
false ->
Key = snappy_hash4(
snappy_byte_at(Table, From),
snappy_byte_at(Table, From + 1),
snappy_byte_at(Table, From + 2),
snappy_byte_at(Table, From + 3)
),
snappy_insert_hashes(
Table,
gleam@dict:insert(Hashes, Key, From),
From + 1,
To,
Size
)
end.
-file("src/packkit/snappy.gleam", 318).
-spec handle_literal(
integer(),
bitstring(),
bitstring(),
packkit@limit:limits()
) -> {ok, bitstring()} | {error, packkit@error:codec_error()}.
handle_literal(Tag, Rest, Output, Limits) ->
Header = erlang:'bsr'(Tag, 2),
gleam@result:'try'(case Header of
H when H < 60 ->
{ok, {H + 1, Rest}};
60 ->
read_literal_extra(Rest, 1);
61 ->
read_literal_extra(Rest, 2);
62 ->
read_literal_extra(Rest, 3);
_ ->
read_literal_extra(Rest, 4)
end, fun(_use0) ->
{Length, After_extra} = _use0,
case erlang:byte_size(After_extra) < Length of
true ->
{error,
{codec_invalid_data,
<<"snappy: literal run truncated"/utf8>>}};
false ->
Chunk@1 = case gleam_stdlib:bit_array_slice(
After_extra,
0,
Length
) of
{ok, Chunk} -> Chunk;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/snappy"/utf8>>,
function => <<"handle_literal"/utf8>>,
line => 337,
value => _assert_fail,
start => 10491,
'end' => 10553,
pattern_start => 10502,
pattern_end => 10511})
end,
After@1 = case gleam_stdlib:bit_array_slice(
After_extra,
Length,
erlang:byte_size(After_extra) - Length
) of
{ok, After} -> After;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/snappy"/utf8>>,
function => <<"handle_literal"/utf8>>,
line => 338,
value => _assert_fail@1,
start => 10560,
'end' => 10711,
pattern_start => 10571,
pattern_end => 10580})
end,
gleam@result:'try'(
append_with_limit(Output, Chunk@1, Limits),
fun(Output@1) ->
decode_raw_loop(After@1, Output@1, Limits)
end
)
end
end).
-file("src/packkit/snappy.gleam", 298).
-spec decode_raw_loop(bitstring(), bitstring(), packkit@limit:limits()) -> {ok,
bitstring()} |
{error, packkit@error:codec_error()}.
decode_raw_loop(Bytes, Output, Limits) ->
case Bytes of
<<>> ->
{ok, Output};
<<Tag, Rest/binary>> ->
Kind = erlang:'band'(Tag, 16#03),
case Kind of
0 ->
handle_literal(Tag, Rest, Output, Limits);
1 ->
handle_copy_1(Tag, Rest, Output, Limits);
2 ->
handle_copy_2(Tag, Rest, Output, Limits);
_ ->
handle_copy_4(Tag, Rest, Output, Limits)
end;
_ ->
{error,
{codec_invalid_data, <<"snappy: malformed raw block"/utf8>>}}
end.
-file("src/packkit/snappy.gleam", 82).
?DOC(" Decode a Snappy raw block using explicit resource limits.\n").
-spec raw_decode_with_limits(bitstring(), packkit@limit:limits()) -> {ok,
bitstring()} |
{error, packkit@error:codec_error()}.
raw_decode_with_limits(Bytes, Limits) ->
gleam@result:'try'(
read_varint(Bytes, 0, 0),
fun(_use0) ->
{Uncompressed_length, After_varint} = _use0,
gleam@bool:guard(
Uncompressed_length > packkit@limit:max_output_bytes(Limits),
{error,
{codec_limit_exceeded,
<<"max_output_bytes"/utf8>>,
Uncompressed_length}},
fun() ->
gleam@result:'try'(
decode_raw_loop(After_varint, <<>>, Limits),
fun(Output) ->
case erlang:byte_size(Output) =:= Uncompressed_length of
true ->
{ok, Output};
false ->
{error,
{codec_invalid_data,
<<"snappy: raw output length disagrees with declared length"/utf8>>}}
end
end
)
end
)
end
).
-file("src/packkit/snappy.gleam", 77).
?DOC(" Decode a single Snappy raw block.\n").
-spec raw_decode(bitstring()) -> {ok, bitstring()} |
{error, packkit@error:codec_error()}.
raw_decode(Bytes) ->
raw_decode_with_limits(Bytes, packkit@limit:default()).
-file("src/packkit/snappy.gleam", 238).
-spec decode_compressed_chunk(bitstring(), bitstring(), packkit@limit:limits()) -> {ok,
bitstring()} |
{error, packkit@error:codec_error()}.
decode_compressed_chunk(Body, Output, Limits) ->
case Body of
<<_:32/little, Payload/binary>> ->
gleam@result:'try'(
raw_decode_with_limits(Payload, Limits),
fun(Decoded) -> append_with_limit(Output, Decoded, Limits) end
);
_ ->
{error,
{codec_invalid_data,
<<"snappy: compressed chunk too short"/utf8>>}}
end.
-file("src/packkit/snappy.gleam", 175).
-spec decode_chunks(bitstring(), bitstring(), packkit@limit:limits()) -> {ok,
bitstring()} |
{error, packkit@error:codec_error()}.
decode_chunks(Bytes, Output, Limits) ->
case Bytes of
<<>> ->
{ok, Output};
<<Chunk_type, Length:24/little, Rest/binary>> ->
case erlang:byte_size(Rest) < Length of
true ->
{error,
{codec_invalid_data,
<<"snappy: chunk payload truncated"/utf8>>}};
false ->
Body@1 = case gleam_stdlib:bit_array_slice(Rest, 0, Length) of
{ok, Body} -> Body;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/snappy"/utf8>>,
function => <<"decode_chunks"/utf8>>,
line => 189,
value => _assert_fail,
start => 6189,
'end' => 6243,
pattern_start => 6200,
pattern_end => 6208})
end,
After@1 = case gleam_stdlib:bit_array_slice(
Rest,
Length,
erlang:byte_size(Rest) - Length
) of
{ok, After} -> After;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/snappy"/utf8>>,
function => <<"decode_chunks"/utf8>>,
line => 190,
value => _assert_fail@1,
start => 6254,
'end' => 6354,
pattern_start => 6265,
pattern_end => 6274})
end,
gleam@result:'try'(case Chunk_type of
T when T =:= 16#01 ->
decode_uncompressed_chunk(
Body@1,
Output,
Limits
);
T@1 when T@1 =:= 16#00 ->
decode_compressed_chunk(Body@1, Output, Limits);
T@2 when T@2 =:= 16#FE ->
{ok, Output};
T@3 when T@3 =:= 16#FF ->
case Body@1 =:= <<16#73,
16#4E,
16#61,
16#50,
16#70,
16#59>> of
true ->
{ok, Output};
false ->
{error,
{codec_invalid_data,
<<"snappy: repeated stream identifier mismatched"/utf8>>}}
end;
T@4 when T@4 >= 16#80 ->
{ok, Output};
_ ->
{error,
{codec_invalid_data,
<<"snappy: unsupported reserved chunk type"/utf8>>}}
end, fun(New_output) ->
decode_chunks(After@1, New_output, Limits)
end)
end;
_ ->
{error,
{codec_invalid_data, <<"snappy: chunk header truncated"/utf8>>}}
end.
-file("src/packkit/snappy.gleam", 56).
?DOC(" Decode a framed Snappy stream using explicit resource limits.\n").
-spec decode_with_limits(bitstring(), packkit@limit:limits()) -> {ok,
bitstring()} |
{error, packkit@error:codec_error()}.
decode_with_limits(Bytes, Limits) ->
gleam@bool:guard(
erlang:byte_size(Bytes) > packkit@limit:max_input_bytes(Limits),
{error,
{codec_limit_exceeded,
<<"max_input_bytes"/utf8>>,
erlang:byte_size(Bytes)}},
fun() -> case Bytes of
<<16#FF,
16#06,
16#00,
16#00,
16#73,
16#4E,
16#61,
16#50,
16#70,
16#59,
Rest/binary>> ->
decode_chunks(Rest, <<>>, Limits);
_ ->
{error,
{codec_invalid_data,
<<"snappy: missing stream identifier"/utf8>>}}
end end
).
-file("src/packkit/snappy.gleam", 51).
?DOC(" Decode a framed Snappy stream using the default resource limits.\n").
-spec decode(bitstring()) -> {ok, bitstring()} |
{error, packkit@error:codec_error()}.
decode(Bytes) ->
decode_with_limits(Bytes, packkit@limit:default()).
-file("src/packkit/snappy.gleam", 430).
-spec apply_copy(
bitstring(),
bitstring(),
packkit@limit:limits(),
integer(),
integer()
) -> {ok, bitstring()} | {error, packkit@error:codec_error()}.
apply_copy(Rest, Output, Limits, Offset, Length) ->
Size = erlang:byte_size(Output),
gleam@bool:guard(
(Offset =< 0) orelse (Offset > Size),
{error,
{codec_invalid_data, <<"snappy: copy offset out of bounds"/utf8>>}},
fun() -> gleam@result:'try'(case Offset >= Length of
true ->
Chunk@1 = case gleam_stdlib:bit_array_slice(
Output,
Size - Offset,
Length
) of
{ok, Chunk} -> Chunk;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/snappy"/utf8>>,
function => <<"apply_copy"/utf8>>,
line => 447,
value => _assert_fail,
start => 13507,
'end' => 13576,
pattern_start => 13518,
pattern_end => 13527})
end,
append_with_limit(Output, Chunk@1, Limits);
false ->
copy_byte_by_byte(Output, Offset, Length, Limits)
end, fun(New_output) ->
decode_raw_loop(Rest, New_output, Limits)
end) end
).
-file("src/packkit/snappy.gleam", 379).
-spec handle_copy_1(integer(), bitstring(), bitstring(), packkit@limit:limits()) -> {ok,
bitstring()} |
{error, packkit@error:codec_error()}.
handle_copy_1(Tag, Rest, Output, Limits) ->
case Rest of
<<Offset_low, After_offset/binary>> ->
Length = erlang:'band'(erlang:'bsr'(Tag, 2), 16#07) + 4,
Offset_high = erlang:'band'(erlang:'bsr'(Tag, 5), 16#07),
Offset = erlang:'bor'(erlang:'bsl'(Offset_high, 8), Offset_low),
apply_copy(After_offset, Output, Limits, Offset, Length);
_ ->
{error,
{codec_invalid_data, <<"snappy: copy-1 offset truncated"/utf8>>}}
end.
-file("src/packkit/snappy.gleam", 398).
-spec handle_copy_2(integer(), bitstring(), bitstring(), packkit@limit:limits()) -> {ok,
bitstring()} |
{error, packkit@error:codec_error()}.
handle_copy_2(Tag, Rest, Output, Limits) ->
case Rest of
<<Offset:16/little, After/binary>> ->
Length = erlang:'bsr'(Tag, 2) + 1,
apply_copy(After, Output, Limits, Offset, Length);
_ ->
{error,
{codec_invalid_data, <<"snappy: copy-2 offset truncated"/utf8>>}}
end.
-file("src/packkit/snappy.gleam", 414).
-spec handle_copy_4(integer(), bitstring(), bitstring(), packkit@limit:limits()) -> {ok,
bitstring()} |
{error, packkit@error:codec_error()}.
handle_copy_4(Tag, Rest, Output, Limits) ->
case Rest of
<<Offset:32/little, After/binary>> ->
Length = erlang:'bsr'(Tag, 2) + 1,
apply_copy(After, Output, Limits, Offset, Length);
_ ->
{error,
{codec_invalid_data, <<"snappy: copy-4 offset truncated"/utf8>>}}
end.
-file("src/packkit/snappy.gleam", 517).
-spec snappy_step(
gleam@dict:dict(integer(), integer()),
integer(),
integer(),
integer(),
gleam@dict:dict(integer(), integer()),
list(bitstring())
) -> bitstring().
snappy_step(Table, Size, Pos, Last_lit_start, Hashes, Acc) ->
Key = snappy_hash4(
snappy_byte_at(Table, Pos),
snappy_byte_at(Table, Pos + 1),
snappy_byte_at(Table, Pos + 2),
snappy_byte_at(Table, Pos + 3)
),
case gleam_stdlib:map_get(Hashes, Key) of
{ok, Prev} ->
Offset = Pos - Prev,
Valid = ((Offset >= 1) andalso (Offset =< 65535)) andalso snappy_bytes4_equal(
Table,
Prev,
Pos
),
case Valid of
false ->
snappy_compress_loop(
Table,
Size,
Pos + 1,
Last_lit_start,
gleam@dict:insert(Hashes, Key, Pos),
Acc
);
true ->
Match_len = snappy_match_length(Table, Prev, Pos, Size, 0),
case Match_len < 4 of
true ->
snappy_compress_loop(
Table,
Size,
Pos + 1,
Last_lit_start,
gleam@dict:insert(Hashes, Key, Pos),
Acc
);
false ->
Literals = case Pos > Last_lit_start of
true ->
emit_literal(
snappy_slice(
Table,
Last_lit_start,
Pos - Last_lit_start,
<<>>
)
);
false ->
<<>>
end,
Copy = emit_copy_for(Offset, Match_len, <<>>),
Next_pos = Pos + Match_len,
New_hashes = snappy_insert_hashes(
Table,
gleam@dict:insert(Hashes, Key, Pos),
Pos + 1,
Next_pos - 1,
Size
),
snappy_compress_loop(
Table,
Size,
Next_pos,
Next_pos,
New_hashes,
[Copy, Literals | Acc]
)
end
end;
_ ->
snappy_compress_loop(
Table,
Size,
Pos + 1,
Last_lit_start,
gleam@dict:insert(Hashes, Key, Pos),
Acc
)
end.
-file("src/packkit/snappy.gleam", 496).
-spec snappy_compress_loop(
gleam@dict:dict(integer(), integer()),
integer(),
integer(),
integer(),
gleam@dict:dict(integer(), integer()),
list(bitstring())
) -> bitstring().
snappy_compress_loop(Table, Size, Pos, Last_lit_start, Hashes, Acc) ->
case (Pos + 4) > Size of
true ->
Lit_len = Size - Last_lit_start,
Tail = case Lit_len of
0 ->
<<>>;
_ ->
emit_literal(
snappy_slice(Table, Last_lit_start, Lit_len, <<>>)
)
end,
gleam_stdlib:bit_array_concat(lists:reverse([Tail | Acc]));
false ->
snappy_step(Table, Size, Pos, Last_lit_start, Hashes, Acc)
end.
-file("src/packkit/snappy.gleam", 486).
-spec compress_raw_body(bitstring(), integer()) -> bitstring().
compress_raw_body(Bytes, Size) ->
case Size < 4 of
true ->
emit_literal(Bytes);
false ->
Table = build_snappy_byte_table(Bytes, 0, maps:new()),
snappy_compress_loop(Table, Size, 0, 0, maps:new(), [])
end.
-file("src/packkit/snappy.gleam", 114).
?DOC(
" Encode `bytes` as a Snappy raw block. Runs a greedy LZ77 match-\n"
" finder (4-byte hash table, 16-bit hash) and emits literal +\n"
" copy-1 / copy-2 / copy-4 sequences in the canonical block layout.\n"
" Inputs of fewer than 4 bytes — where no copy can fit the 4-byte\n"
" minimum match — degenerate to a single literal run.\n"
).
-spec raw_encode(bitstring()) -> {ok, bitstring()} |
{error, packkit@error:codec_error()}.
raw_encode(Bytes) ->
Length = erlang:byte_size(Bytes),
Length_varint = write_varint(Length),
Body = compress_raw_body(Bytes, Length),
{ok, gleam_stdlib:bit_array_concat([Length_varint, Body])}.
-file("src/packkit/snappy.gleam", 169).
-spec encode_raw_block(bitstring(), integer()) -> bitstring().
encode_raw_block(Bytes, Size) ->
Varint = write_varint(Size),
Body = compress_raw_body(Bytes, Size),
gleam_stdlib:bit_array_concat([Varint, Body]).
-file("src/packkit/snappy.gleam", 121).
-spec encode_uncompressed_chunks(bitstring(), list(bitstring())) -> bitstring().
encode_uncompressed_chunks(Remaining, Acc) ->
Total = erlang:byte_size(Remaining),
case Total of
0 ->
gleam_stdlib:bit_array_concat(lists:reverse(Acc));
_ ->
Chunk_size = case Total > 65536 of
true ->
65536;
false ->
Total
end,
Chunk@1 = case gleam_stdlib:bit_array_slice(
Remaining,
0,
Chunk_size
) of
{ok, Chunk} -> Chunk;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/snappy"/utf8>>,
function => <<"encode_uncompressed_chunks"/utf8>>,
line => 133,
value => _assert_fail,
start => 4316,
'end' => 4380,
pattern_start => 4327,
pattern_end => 4336})
end,
After@1 = case gleam_stdlib:bit_array_slice(
Remaining,
Chunk_size,
Total - Chunk_size
) of
{ok, After} -> After;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/snappy"/utf8>>,
function => <<"encode_uncompressed_chunks"/utf8>>,
line => 134,
value => _assert_fail@1,
start => 4387,
'end' => 4476,
pattern_start => 4398,
pattern_end => 4407})
end,
Crc = packkit@checksum:snappy_mask(packkit@checksum:crc32c(Chunk@1)),
Raw_body = encode_raw_block(Chunk@1, Chunk_size),
Raw_body_size = erlang:byte_size(Raw_body),
Framed = case Raw_body_size < Chunk_size of
true ->
Payload_size = Raw_body_size + 4,
Header = <<16#00, Payload_size:24/little, Crc:32/little>>,
gleam_stdlib:bit_array_concat([Header, Raw_body]);
false ->
Payload_size@1 = Chunk_size + 4,
Header@1 = <<16#01,
Payload_size@1:24/little,
Crc:32/little>>,
gleam_stdlib:bit_array_concat([Header@1, Chunk@1])
end,
encode_uncompressed_chunks(After@1, [Framed | Acc])
end.
-file("src/packkit/snappy.gleam", 45).
?DOC(
" Encode `bytes` as a framed Snappy stream that stores every chunk\n"
" in the uncompressed form.\n"
).
-spec encode(bitstring()) -> {ok, bitstring()} |
{error, packkit@error:codec_error()}.
encode(Bytes) ->
Chunks = encode_uncompressed_chunks(Bytes, []),
{ok,
gleam_stdlib:bit_array_concat(
[<<16#FF,
16#06,
16#00,
16#00,
16#73,
16#4E,
16#61,
16#50,
16#70,
16#59>>,
Chunks]
)}.