-module(packkit@zstd).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/packkit/zstd.gleam").
-export([codec/0, frame_header_for_size/1, encode/1, decode_with_limits/2, decode/1]).
-export_type([huff_node/0, fse_enc_slot/0, zstd_sequence/0, block_state/0, seq_tables_state/0, compressed_literals_header/0, seq_alphabet/0, seq_context/0, fwd_bit_reader/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.
?MODULEDOC(
" Zstandard codec — pure-Gleam decoder.\n"
"\n"
" The module parses the Zstandard frame envelope (magic, frame\n"
" header descriptor, window descriptor, optional dictionary id,\n"
" optional frame content size, optional trailing content checksum)\n"
" and walks the block stream. Raw and RLE blocks decode directly;\n"
" compressed blocks (type 2) decode through the FSE tables in\n"
" `packkit/internal/fse`. Sequences with `Predefined_Mode`,\n"
" `RLE_Mode`, and `FSE_Compressed_Mode` symbol descriptions all\n"
" decode (LL, OF, ML independently). All four literal block\n"
" types decode: `Raw_Literals_Block`, `RLE_Literals_Block`,\n"
" `Compressed_Literals_Block` (Huffman-coded with direct-weight\n"
" or FSE-weight tree descriptions, 1-stream or 4-stream form),\n"
" and `Treeless_Literals_Block` (which reuses the prior block's\n"
" Huffman tree via the cross-block tree state threaded through\n"
" the block loop). A treeless block in the first position of a\n"
" frame surfaces as a typed `CodecInvalidData`. `Repeat_Mode`\n"
" for sequence-symbol descriptions also threads its FSE tables\n"
" across blocks (per RFC 8478 §3.1.1.4 the LL / OF / ML tables\n"
" survive across blocks within a frame), and a Repeat_Mode in the\n"
" first block of a frame surfaces as a typed `CodecInvalidData`.\n"
).
-type huff_node() :: {huff_leaf, integer()} |
{huff_internal, huff_node(), huff_node()}.
-type fse_enc_slot() :: {fse_enc_slot,
integer(),
integer(),
integer(),
integer()}.
-type zstd_sequence() :: {zstd_sequence, integer(), integer(), integer()}.
-type block_state() :: {block_state,
gleam@option:option(packkit@internal@huf:tree()),
seq_tables_state(),
list(integer()),
{integer(), integer(), integer()}}.
-type seq_tables_state() :: {seq_tables_state,
gleam@option:option({gleam@dict:dict(integer(), packkit@internal@fse:state_entry()),
integer()}),
gleam@option:option({gleam@dict:dict(integer(), packkit@internal@fse:state_entry()),
integer()}),
gleam@option:option({gleam@dict:dict(integer(), packkit@internal@fse:state_entry()),
integer()})}.
-type compressed_literals_header() :: {compressed_literals_header,
integer(),
integer(),
integer(),
integer()}.
-type seq_alphabet() :: seq_alphabet_ll | seq_alphabet_of | seq_alphabet_ml.
-type seq_context() :: {seq_context,
bitstring(),
integer(),
list(integer()),
integer(),
integer(),
integer(),
integer(),
integer(),
integer(),
integer(),
gleam@dict:dict(integer(), packkit@internal@fse:state_entry()),
gleam@dict:dict(integer(), packkit@internal@fse:state_entry()),
gleam@dict:dict(integer(), packkit@internal@fse:state_entry())}.
-type fwd_bit_reader() :: {fwd_bit_reader,
bitstring(),
integer(),
integer(),
boolean(),
integer()}.
-file("src/packkit/zstd.gleam", 40).
?DOC(" Zstandard codec smart constructor.\n").
-spec codec() -> packkit@codec:codec().
codec() ->
packkit@codec:zstd().
-file("src/packkit/zstd.gleam", 87).
?DOC(
" Build the Zstandard frame header for a payload of `size` bytes.\n"
" Exposed for tests that need to assert on the FCS layout for sizes\n"
" too large to materialise in memory (e.g. 4 GiB+ frames where the\n"
" header used to silently truncate the FCS field to its low 32 bits).\n"
).
-spec frame_header_for_size(integer()) -> {ok, bitstring()} |
{error, packkit@error:codec_error()}.
frame_header_for_size(Size) ->
case Size of
N when N < 256 ->
{ok, <<16#28, 16#B5, 16#2F, 16#FD, 16#20, N>>};
N@1 when N@1 < 16#10000 ->
{ok, <<16#28, 16#B5, 16#2F, 16#FD, 16#60, ((N@1 - 256)):16/little>>};
N@2 when N@2 < 16#100000000 ->
{ok, <<16#28, 16#B5, 16#2F, 16#FD, 16#A0, N@2:32/little>>};
N@3 ->
Lo = erlang:'band'(N@3, 16#FFFFFFFF),
High_half = erlang:'bsr'(N@3, 32),
gleam@bool:guard(
High_half > 16#FFFFFFFF,
{error,
{codec_limit_exceeded,
<<"zstd frame_content_size"/utf8>>,
N@3}},
fun() ->
Hi = erlang:'band'(High_half, 16#FFFFFFFF),
{ok,
<<16#28,
16#B5,
16#2F,
16#FD,
16#E0,
Lo:32/little,
Hi:32/little>>}
end
)
end.
-file("src/packkit/zstd.gleam", 250).
-spec pick_smallest_block(list({integer(), bitstring()})) -> bitstring().
pick_smallest_block(Candidates) ->
case Candidates of
[{_, Only}] ->
Only;
[First | Rest] ->
erlang:element(
2,
gleam@list:fold(
Rest,
First,
fun(Acc, Item) ->
case erlang:element(1, Item) < erlang:element(1, Acc) of
true ->
Item;
false ->
Acc
end
end
)
);
[] ->
<<>>
end.
-file("src/packkit/zstd.gleam", 422).
-spec split_chunk_4(bitstring(), integer()) -> {bitstring(),
bitstring(),
bitstring(),
bitstring()}.
split_chunk_4(Chunk, Chunk_size) ->
Per_stream = (Chunk_size + 3) div 4,
S4_len = Chunk_size - (Per_stream * 3),
P1@1 = case gleam_stdlib:bit_array_slice(Chunk, 0, Per_stream) of
{ok, P1} -> P1;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/zstd"/utf8>>,
function => <<"split_chunk_4"/utf8>>,
line => 434,
value => _assert_fail,
start => 16277,
'end' => 16334,
pattern_start => 16288,
pattern_end => 16294})
end,
P2@1 = case gleam_stdlib:bit_array_slice(Chunk, Per_stream, Per_stream) of
{ok, P2} -> P2;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/zstd"/utf8>>,
function => <<"split_chunk_4"/utf8>>,
line => 435,
value => _assert_fail@1,
start => 16337,
'end' => 16403,
pattern_start => 16348,
pattern_end => 16354})
end,
P3@1 = case gleam_stdlib:bit_array_slice(Chunk, Per_stream * 2, Per_stream) of
{ok, P3} -> P3;
_assert_fail@2 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/zstd"/utf8>>,
function => <<"split_chunk_4"/utf8>>,
line => 436,
value => _assert_fail@2,
start => 16406,
'end' => 16476,
pattern_start => 16417,
pattern_end => 16423})
end,
P4@1 = case gleam_stdlib:bit_array_slice(Chunk, Per_stream * 3, S4_len) of
{ok, P4} -> P4;
_assert_fail@3 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/zstd"/utf8>>,
function => <<"split_chunk_4"/utf8>>,
line => 437,
value => _assert_fail@3,
start => 16479,
'end' => 16545,
pattern_start => 16490,
pattern_end => 16496})
end,
{P1@1, P2@1, P3@1, P4@1}.
-file("src/packkit/zstd.gleam", 446).
?DOC(
" Build the 4-stream literals section: 4-byte header (size_format = 2,\n"
" 14-bit regen / 14-bit compressed) followed by the Huffman tree,\n"
" the 6-byte jump table (`stream1_size`, `stream2_size`,\n"
" `stream3_size` each as LE u16; stream 4's size is derived by the\n"
" decoder from `total - 6 - sum`), and the four sub-bitstreams.\n"
).
-spec build_compressed_literals_section_4stream(
integer(),
integer(),
bitstring(),
bitstring(),
bitstring(),
bitstring(),
bitstring(),
bitstring()
) -> bitstring().
build_compressed_literals_section_4stream(
Regen_size,
Comp_size,
Tree_bytes,
Jump_table,
S1,
S2,
S3,
S4
) ->
B0 = erlang:'band'(
erlang:'bor'(
erlang:'bor'(2, erlang:'bsl'(2, 2)),
erlang:'bsl'(erlang:'band'(Regen_size, 16#F), 4)
),
16#FF
),
B1 = erlang:'band'(erlang:'bsr'(Regen_size, 4), 16#FF),
Regen_high_2 = erlang:'band'(erlang:'bsr'(Regen_size, 12), 16#3),
Comp_low_6 = erlang:'band'(Comp_size, 16#3F),
B2 = erlang:'band'(
erlang:'bor'(Regen_high_2, erlang:'bsl'(Comp_low_6, 2)),
16#FF
),
B3 = erlang:'band'(erlang:'bsr'(Comp_size, 6), 16#FF),
gleam_stdlib:bit_array_concat(
[<<B0, B1, B2, B3>>, Tree_bytes, Jump_table, S1, S2, S3, S4]
).
-file("src/packkit/zstd.gleam", 496).
-spec empty_freq_dict(integer(), gleam@dict:dict(integer(), integer())) -> gleam@dict:dict(integer(), integer()).
empty_freq_dict(Symbol, Acc) ->
case Symbol of
256 ->
Acc;
_ ->
empty_freq_dict(Symbol + 1, gleam@dict:insert(Acc, Symbol, 0))
end.
-file("src/packkit/zstd.gleam", 503).
-spec collect_frequencies(bitstring(), gleam@dict:dict(integer(), integer())) -> gleam@dict:dict(integer(), integer()).
collect_frequencies(Chunk, Acc) ->
case Chunk of
<<Byte, Rest/binary>> ->
Current = case gleam_stdlib:map_get(Acc, Byte) of
{ok, V} ->
V;
{error, _} ->
0
end,
collect_frequencies(Rest, gleam@dict:insert(Acc, Byte, Current + 1));
_ ->
Acc
end.
-file("src/packkit/zstd.gleam", 519).
-spec count_freqs_to_list(
gleam@dict:dict(integer(), integer()),
integer(),
list({integer(), integer()})
) -> list({integer(), integer()}).
count_freqs_to_list(Table, Symbol, Acc) ->
case Symbol of
256 ->
lists:reverse(Acc);
_ ->
Count = case gleam_stdlib:map_get(Table, Symbol) of
{ok, V} ->
V;
{error, _} ->
0
end,
count_freqs_to_list(Table, Symbol + 1, [{Symbol, Count} | Acc])
end.
-file("src/packkit/zstd.gleam", 490).
?DOC(
" Count `chunk`'s byte frequencies as a list of `#(symbol, count)`\n"
" pairs for symbols 0..255 in ascending order. Symbols with zero\n"
" occurrences are kept (they're filtered before tree building) so the\n"
" caller can iterate the full 0..255 range without separate handling.\n"
).
-spec count_byte_frequencies(bitstring()) -> list({integer(), integer()}).
count_byte_frequencies(Chunk) ->
Initial = empty_freq_dict(0, maps:new()),
Table = collect_frequencies(Chunk, Initial),
count_freqs_to_list(Table, 0, []).
-file("src/packkit/zstd.gleam", 590).
-spec insert_node_sorted(
{integer(), huff_node()},
list({integer(), huff_node()})
) -> list({integer(), huff_node()}).
insert_node_sorted(Item, Nodes) ->
case Nodes of
[] ->
[Item];
[Head | Rest] ->
case erlang:element(1, Item) =< erlang:element(1, Head) of
true ->
[Item, Head | Rest];
false ->
[Head | insert_node_sorted(Item, Rest)]
end
end.
-file("src/packkit/zstd.gleam", 579).
-spec huffman_merge(list({integer(), huff_node()})) -> huff_node().
huffman_merge(Nodes) ->
case Nodes of
[{_, Single}] ->
Single;
[A, B | Rest] ->
Combined = {erlang:element(1, A) + erlang:element(1, B),
{huff_internal, erlang:element(2, A), erlang:element(2, B)}},
huffman_merge(insert_node_sorted(Combined, Rest));
_ ->
{huff_leaf, 0}
end.
-file("src/packkit/zstd.gleam", 604).
-spec extract_lengths(
huff_node(),
integer(),
gleam@dict:dict(integer(), integer())
) -> gleam@dict:dict(integer(), integer()).
extract_lengths(Node, Depth, Acc) ->
case Node of
{huff_leaf, Sym} ->
D = case Depth of
0 ->
1;
_ ->
Depth
end,
gleam@dict:insert(Acc, Sym, D);
{huff_internal, L, R} ->
Acc@1 = extract_lengths(L, Depth + 1, Acc),
extract_lengths(R, Depth + 1, Acc@1)
end.
-file("src/packkit/zstd.gleam", 624).
-spec max_length_in_dict(gleam@dict:dict(integer(), integer())) -> integer().
max_length_in_dict(Lengths) ->
gleam@dict:fold(Lengths, 0, fun(Acc, _, Value) -> case Value > Acc of
true ->
Value;
false ->
Acc
end end).
-file("src/packkit/zstd.gleam", 633).
-spec build_length_list(
gleam@dict:dict(integer(), integer()),
integer(),
list(integer())
) -> list(integer()).
build_length_list(Lengths, Symbol, Acc) ->
case Symbol of
256 ->
lists:reverse(Acc);
_ ->
Len = case gleam_stdlib:map_get(Lengths, Symbol) of
{ok, V} ->
V;
{error, _} ->
0
end,
build_length_list(Lengths, Symbol + 1, [Len | Acc])
end.
-file("src/packkit/zstd.gleam", 546).
?DOC(
" Build canonical Huffman code lengths for `freqs`, returning a list\n"
" of 256 lengths (0 for unused symbols). Standard Huffman tree\n"
" construction via insertion-sort; bails out with `Error(Nil)` when\n"
" the resulting tree exceeds the 11-bit depth limit so the caller\n"
" can fall back to Raw / RLE.\n"
).
-spec build_canonical_lengths(list({integer(), integer()})) -> {ok,
{list(integer()), integer()}} |
{error, nil}.
build_canonical_lengths(Freqs) ->
Active = gleam@list:filter_map(
Freqs,
fun(P) -> case erlang:element(2, P) > 0 of
true ->
{ok,
{erlang:element(2, P),
{huff_leaf, erlang:element(1, P)}}};
false ->
{error, nil}
end end
),
Sorted = gleam@list:sort(
Active,
fun(A, B) ->
gleam@int:compare(erlang:element(1, A), erlang:element(1, B))
end
),
case Sorted of
[] ->
{error, nil};
[{_, Single_node}] ->
Single = case Single_node of
{huff_leaf, S} ->
S;
_ ->
0
end,
Lengths = build_length_list(
gleam@dict:insert(maps:new(), Single, 1),
0,
[]
),
{ok, {Lengths, 1}};
_ ->
Root = huffman_merge(Sorted),
Lengths_dict = extract_lengths(Root, 0, maps:new()),
Max_bits = max_length_in_dict(Lengths_dict),
Lengths@1 = build_length_list(Lengths_dict, 0, []),
{ok, {Lengths@1, Max_bits}}
end.
-file("src/packkit/zstd.gleam", 674).
-spec assign_codes_loop(
list({integer(), integer()}),
integer(),
integer(),
gleam@dict:dict(integer(), {integer(), integer()})
) -> gleam@dict:dict(integer(), {integer(), integer()}).
assign_codes_loop(Sorted, Max_bits, Slot, Acc) ->
case Sorted of
[] ->
Acc;
[{Sym, Len} | Rest] ->
Span = erlang:'bsl'(1, Max_bits - Len),
Code = erlang:'bsr'(Slot, Max_bits - Len),
assign_codes_loop(
Rest,
Max_bits,
Slot + Span,
gleam@dict:insert(Acc, Sym, {Code, Len})
)
end.
-file("src/packkit/zstd.gleam", 656).
?DOC(
" Build the encoder's `symbol → #(code_value, num_bits)` table from\n"
" the canonical lengths. zstd's lookup table is filled in order\n"
" (length DESC, symbol ASC), so the encoder's code values are simply\n"
" the table slot indices, right-shifted by `max_bits - num_bits` to\n"
" drop the table's low-order bits (which the decoder treats as\n"
" \"don't care\" once it has consumed `num_bits` bits).\n"
).
-spec assign_canonical_codes(list(integer()), integer()) -> gleam@dict:dict(integer(), {integer(),
integer()}).
assign_canonical_codes(Lengths, Max_bits) ->
With_index = begin
_pipe = gleam@list:index_map(Lengths, fun(Len, Sym) -> {Sym, Len} end),
gleam@list:filter(_pipe, fun(P) -> erlang:element(2, P) > 0 end)
end,
Sorted = gleam@list:sort(
With_index,
fun(A, B) ->
case gleam@int:compare(erlang:element(2, B), erlang:element(2, A)) of
eq ->
gleam@int:compare(
erlang:element(1, A),
erlang:element(1, B)
);
Ord ->
Ord
end
end
),
assign_codes_loop(Sorted, Max_bits, 0, maps:new()).
-file("src/packkit/zstd.gleam", 695).
-spec max_length_in_list(list(integer()), integer()) -> integer().
max_length_in_list(Lengths, Acc) ->
case Lengths of
[] ->
Acc;
[Head | Rest] ->
case Head > Acc of
true ->
max_length_in_list(Rest, Head);
false ->
max_length_in_list(Rest, Acc)
end
end.
-file("src/packkit/zstd.gleam", 706).
-spec trim_trailing_zero_weights(list(integer()), list(integer())) -> list(integer()).
trim_trailing_zero_weights(Reversed, Acc) ->
case {Reversed, Acc} of
{[], _} ->
Acc;
{[0 | Rest], []} ->
trim_trailing_zero_weights(Rest, []);
{[Head | Rest@1], _} ->
trim_trailing_zero_weights(Rest@1, [Head | Acc])
end.
-file("src/packkit/zstd.gleam", 714).
-spec drop_last_weight(list(integer()), list(integer())) -> list(integer()).
drop_last_weight(Weights, Acc) ->
case Weights of
[] ->
lists:reverse(Acc);
[_] ->
lists:reverse(Acc);
[Head | Rest] ->
drop_last_weight(Rest, [Head | Acc])
end.
-file("src/packkit/zstd.gleam", 722).
-spec pack_weights_4bit(list(integer()), bitstring()) -> bitstring().
pack_weights_4bit(Weights, Acc) ->
case Weights of
[] ->
Acc;
[Single] ->
Byte = erlang:'bsl'(Single, 4),
<<Acc/bitstring, Byte>>;
[High, Low | Rest] ->
Byte@1 = erlang:'bor'(erlang:'bsl'(High, 4), Low),
pack_weights_4bit(Rest, <<Acc/bitstring, Byte@1>>)
end.
-file("src/packkit/zstd.gleam", 755).
-spec bit_array_to_list_forward(bitstring(), list(integer())) -> list(integer()).
bit_array_to_list_forward(Bytes, Acc) ->
case Bytes of
<<Byte, Rest/binary>> ->
bit_array_to_list_forward(Rest, [Byte | Acc]);
_ ->
lists:reverse(Acc)
end.
-file("src/packkit/zstd.gleam", 785).
-spec flush_full_bytes(integer(), integer(), bitstring()) -> {integer(),
integer(),
bitstring()}.
flush_full_bytes(Buf, Bits, Out) ->
case Bits >= 8 of
true ->
Byte = erlang:'band'(Buf, 16#FF),
New_buf = erlang:'bsr'(Buf, 8),
flush_full_bytes(New_buf, Bits - 8, <<Out/bitstring, Byte>>);
false ->
{Buf, Bits, Out}
end.
-file("src/packkit/zstd.gleam", 762).
-spec emit_codes_reverse(
list(integer()),
gleam@dict:dict(integer(), {integer(), integer()}),
integer(),
integer(),
bitstring()
) -> {integer(), integer(), bitstring()}.
emit_codes_reverse(Bytes_rev, Codes, Buf, Bits, Out) ->
case Bytes_rev of
[] ->
{Buf, Bits, Out};
[Byte | Rest] ->
{Code, Len} = case gleam_stdlib:map_get(Codes, Byte) of
{ok, V} ->
V;
{error, _} ->
{0, 0}
end,
New_buf = erlang:'bor'(Buf, erlang:'bsl'(Code, Bits)),
New_bits = Bits + Len,
{Flushed_buf, Flushed_bits, Flushed_out} = flush_full_bytes(
New_buf,
New_bits,
Out
),
emit_codes_reverse(
Rest,
Codes,
Flushed_buf,
Flushed_bits,
Flushed_out
)
end.
-file("src/packkit/zstd.gleam", 796).
-spec flush_final_bits(integer(), integer(), bitstring()) -> bitstring().
flush_final_bits(Buf, Bits, Out) ->
case Bits of
0 ->
Out;
_ ->
Byte = erlang:'band'(Buf, 16#FF),
New_buf = erlang:'bsr'(Buf, 8),
New_bits = case Bits > 8 of
true ->
Bits - 8;
false ->
0
end,
flush_final_bits(New_buf, New_bits, <<Out/bitstring, Byte>>)
end.
-file("src/packkit/zstd.gleam", 742).
?DOC(
" Build the bitstream a zstd Huffman decoder reads from the END\n"
" backward. We iterate input in REVERSE order, push each code into a\n"
" shift register from the LOW end, flush low bytes when full, and\n"
" finally append a 1-bit terminator that the decoder finds via\n"
" \"highest set bit of the last byte\".\n"
).
-spec encode_huffman_bitstream(
bitstring(),
gleam@dict:dict(integer(), {integer(), integer()})
) -> bitstring().
encode_huffman_bitstream(Chunk, Codes) ->
Bytes = bit_array_to_list_forward(Chunk, []),
Reversed = lists:reverse(Bytes),
{Buf, Bits, Out} = emit_codes_reverse(Reversed, Codes, 0, 0, <<>>),
Buf2 = erlang:'bor'(Buf, erlang:'bsl'(1, Bits)),
Bits2 = Bits + 1,
flush_final_bits(Buf2, Bits2, Out).
-file("src/packkit/zstd.gleam", 881).
-spec tally_fse_weights(list(integer()), gleam@dict:dict(integer(), integer())) -> gleam@dict:dict(integer(), integer()).
tally_fse_weights(Weights, Acc) ->
case Weights of
[] ->
Acc;
[W | Rest] ->
Curr = case gleam_stdlib:map_get(Acc, W) of
{ok, V} ->
V;
{error, _} ->
0
end,
tally_fse_weights(Rest, gleam@dict:insert(Acc, W, Curr + 1))
end.
-file("src/packkit/zstd.gleam", 897).
-spec highest_used_fse_weight(gleam@dict:dict(integer(), integer())) -> integer().
highest_used_fse_weight(Counts) ->
gleam@dict:fold(
Counts,
-1,
fun(Acc, Sym, Count) -> case (Count > 0) andalso (Sym > Acc) of
true ->
Sym;
false ->
Acc
end end
).
-file("src/packkit/zstd.gleam", 967).
-spec sum_int_list(list(integer()), integer()) -> integer().
sum_int_list(List, Acc) ->
case List of
[] ->
Acc;
[Head | Rest] ->
sum_int_list(Rest, Acc + Head)
end.
-file("src/packkit/zstd.gleam", 978).
-spec find_largest_loop(
gleam@dict:dict(integer(), integer()),
integer(),
integer(),
integer(),
integer()
) -> integer().
find_largest_loop(Counts, Sym, Max_used, Best_idx, Best_count) ->
case Sym > Max_used of
true ->
Best_idx;
false ->
Count = case gleam_stdlib:map_get(Counts, Sym) of
{ok, V} ->
V;
{error, _} ->
0
end,
case Count > Best_count of
true ->
find_largest_loop(Counts, Sym + 1, Max_used, Sym, Count);
false ->
find_largest_loop(
Counts,
Sym + 1,
Max_used,
Best_idx,
Best_count
)
end
end.
-file("src/packkit/zstd.gleam", 974).
-spec find_largest_count_index(gleam@dict:dict(integer(), integer()), integer()) -> integer().
find_largest_count_index(Counts, Max_used) ->
find_largest_loop(Counts, 0, Max_used, -1, -1).
-file("src/packkit/zstd.gleam", 1001).
-spec adjust_normalized_at(
list(integer()),
integer(),
integer(),
integer(),
list(integer())
) -> list(integer()).
adjust_normalized_at(Normalized, Target_idx, Diff, Cur_idx, Acc) ->
case Normalized of
[] ->
lists:reverse(Acc);
[Head | Rest] ->
New_head = case Cur_idx =:= Target_idx of
true ->
Head + Diff;
false ->
Head
end,
adjust_normalized_at(
Rest,
Target_idx,
Diff,
Cur_idx + 1,
[New_head | Acc]
)
end.
-file("src/packkit/zstd.gleam", 1060).
-spec list_to_indexed_dict(
list(integer()),
integer(),
gleam@dict:dict(integer(), integer())
) -> gleam@dict:dict(integer(), integer()).
list_to_indexed_dict(List, Idx, Acc) ->
case List of
[] ->
Acc;
[Head | Rest] ->
list_to_indexed_dict(
Rest,
Idx + 1,
gleam@dict:insert(Acc, Idx, Head)
)
end.
-file("src/packkit/zstd.gleam", 1145).
-spec count_zero_run_from(
gleam@dict:dict(integer(), integer()),
integer(),
integer(),
integer()
) -> integer().
count_zero_run_from(Normalized, Pos, Max_used, Acc) ->
case Pos > Max_used of
true ->
Acc;
false ->
V = case gleam_stdlib:map_get(Normalized, Pos) of
{ok, X} ->
X;
{error, _} ->
0
end,
case V =:= 0 of
true ->
count_zero_run_from(Normalized, Pos + 1, Max_used, Acc + 1);
false ->
Acc
end
end.
-file("src/packkit/zstd.gleam", 1201).
-spec fse_shrink_threshold(integer(), integer(), integer()) -> {integer(),
integer()}.
fse_shrink_threshold(Threshold, Bit_count, Remaining) ->
case Remaining >= Threshold of
true ->
{Threshold, Bit_count};
false ->
case Threshold =< 1 of
true ->
{Threshold, Bit_count};
false ->
fse_shrink_threshold(
Threshold div 2,
Bit_count - 1,
Remaining
)
end
end.
-file("src/packkit/zstd.gleam", 1218).
-spec push_bits_unchecked(
integer(),
integer(),
bitstring(),
integer(),
integer()
) -> {integer(), integer(), bitstring()}.
push_bits_unchecked(Buf, Bits, Out, Value, N) ->
New_buf = erlang:'bor'(Buf, erlang:'bsl'(Value, Bits)),
flush_full_bytes(New_buf, Bits + N, Out).
-file("src/packkit/zstd.gleam", 1166).
-spec emit_zero_run(integer(), integer(), integer(), bitstring()) -> {integer(),
integer(),
bitstring()}.
emit_zero_run(Run, Buf, Bits, Out) ->
case Run >= 3 of
true ->
{Buf@1, Bits@1, Out@1} = push_bits_unchecked(Buf, Bits, Out, 3, 2),
emit_zero_run(Run - 3, Buf@1, Bits@1, Out@1);
false ->
push_bits_unchecked(Buf, Bits, Out, Run, 2)
end.
-file("src/packkit/zstd.gleam", 1181).
-spec push_count_bits(
integer(),
integer(),
bitstring(),
integer(),
integer(),
integer(),
integer()
) -> {integer(), integer(), bitstring()}.
push_count_bits(Buf, Bits, Out, Count_wire, Max_val, Threshold, Bit_count) ->
case Count_wire < Max_val of
true ->
push_bits_unchecked(Buf, Bits, Out, Count_wire, Bit_count - 1);
false ->
case Count_wire < Threshold of
true ->
push_bits_unchecked(Buf, Bits, Out, Count_wire, Bit_count);
false ->
push_bits_unchecked(
Buf,
Bits,
Out,
Count_wire + Max_val,
Bit_count
)
end
end.
-file("src/packkit/zstd.gleam", 1072).
-spec write_dist_loop(
gleam@dict:dict(integer(), integer()),
integer(),
integer(),
integer(),
integer(),
integer(),
boolean(),
integer(),
integer(),
bitstring()
) -> {integer(), integer(), bitstring()}.
write_dist_loop(
Normalized,
Curr,
Max_used,
Remaining,
Threshold,
Bit_count,
Prev_is_zero,
Buf,
Bits,
Out
) ->
case (Remaining =< 1) orelse (Curr > Max_used) of
true ->
{Buf, Bits, Out};
false ->
case Prev_is_zero of
true ->
Run = count_zero_run_from(Normalized, Curr, Max_used, 0),
{Buf@1, Bits@1, Out@1} = emit_zero_run(Run, Buf, Bits, Out),
write_dist_loop(
Normalized,
Curr + Run,
Max_used,
Remaining,
Threshold,
Bit_count,
false,
Buf@1,
Bits@1,
Out@1
);
false ->
Probability = case gleam_stdlib:map_get(Normalized, Curr) of
{ok, V} ->
V;
{error, _} ->
0
end,
Count_wire = Probability + 1,
Max_val = ((2 * Threshold) - 1) - Remaining,
{Buf@2, Bits@2, Out@2} = push_count_bits(
Buf,
Bits,
Out,
Count_wire,
Max_val,
Threshold,
Bit_count
),
Abs_prob = case Probability < 0 of
true ->
- Probability;
false ->
Probability
end,
New_remaining = Remaining - Abs_prob,
{New_threshold, New_bit_count} = fse_shrink_threshold(
Threshold,
Bit_count,
New_remaining
),
write_dist_loop(
Normalized,
Curr + 1,
Max_used,
New_remaining,
New_threshold,
New_bit_count,
Probability =:= 0,
Buf@2,
Bits@2,
Out@2
)
end
end.
-file("src/packkit/zstd.gleam", 1229).
-spec pad_to_byte_boundary(integer(), integer(), bitstring()) -> bitstring().
pad_to_byte_boundary(Buf, Bits, Out) ->
case Bits of
0 ->
Out;
_ ->
Byte = erlang:'band'(Buf, 16#FF),
<<Out/bitstring, Byte>>
end.
-file("src/packkit/zstd.gleam", 1036).
?DOC(
" Generalised distribution-header writer. `accuracy_log` chooses\n"
" the table size (`1 << accuracy_log`) and the 4-bit `accuracy_log\n"
" - 5` prefix; the rest mirrors the decoder's symmetric reader\n"
" (variable-width per-symbol counts with the 2-bit zero-run codes\n"
" when consecutive symbols have probability 0).\n"
).
-spec encode_fse_dist_header_with_log(list(integer()), integer(), integer()) -> bitstring().
encode_fse_dist_header_with_log(Normalized, Max_used, Accuracy_log) ->
{Buf, Bits, Out} = push_bits_unchecked(0, 0, <<>>, Accuracy_log - 5, 4),
Table_size = erlang:'bsl'(1, Accuracy_log),
Normalized_dict = list_to_indexed_dict(Normalized, 0, maps:new()),
{Buf@1, Bits@1, Out@1} = write_dist_loop(
Normalized_dict,
0,
Max_used,
Table_size + 1,
Table_size,
Accuracy_log + 1,
false,
Buf,
Bits,
Out
),
pad_to_byte_boundary(Buf@1, Bits@1, Out@1).
-file("src/packkit/zstd.gleam", 1253).
-spec build_fse_enc_slots_loop(
gleam@dict:dict(integer(), packkit@internal@fse:state_entry()),
integer(),
integer(),
gleam@dict:dict(integer(), list(fse_enc_slot()))
) -> gleam@dict:dict(integer(), list(fse_enc_slot())).
build_fse_enc_slots_loop(State_table, S_idx, Table_size, Acc) ->
case S_idx >= Table_size of
true ->
Acc;
false ->
Entry = case gleam_stdlib:map_get(State_table, S_idx) of
{ok, E} ->
E;
{error, _} ->
{state_entry, 0, 0, 0}
end,
Span = erlang:'bsl'(1, erlang:element(3, Entry)),
Slot = {fse_enc_slot,
S_idx,
erlang:element(4, Entry),
erlang:element(4, Entry) + Span,
erlang:element(3, Entry)},
Existing = case gleam_stdlib:map_get(Acc, erlang:element(2, Entry)) of
{ok, L} ->
L;
{error, _} ->
[]
end,
build_fse_enc_slots_loop(
State_table,
S_idx + 1,
Table_size,
gleam@dict:insert(
Acc,
erlang:element(2, Entry),
[Slot | Existing]
)
)
end.
-file("src/packkit/zstd.gleam", 1299).
-spec smallest_state_idx_loop(list(fse_enc_slot()), integer()) -> integer().
smallest_state_idx_loop(List, Best) ->
case List of
[] ->
Best;
[Slot | Rest] ->
case erlang:element(2, Slot) < Best of
true ->
smallest_state_idx_loop(Rest, erlang:element(2, Slot));
false ->
smallest_state_idx_loop(Rest, Best)
end
end.
-file("src/packkit/zstd.gleam", 1321).
-spec find_slot_in_list(list(fse_enc_slot()), integer()) -> {ok, fse_enc_slot()} |
{error, nil}.
find_slot_in_list(List, State) ->
case List of
[] ->
{error, nil};
[Slot | Rest] ->
case (State >= erlang:element(3, Slot)) andalso (State < erlang:element(
4,
Slot
)) of
true ->
{ok, Slot};
false ->
find_slot_in_list(Rest, State)
end
end.
-file("src/packkit/zstd.gleam", 1310).
-spec find_slot_for(
gleam@dict:dict(integer(), list(fse_enc_slot())),
integer(),
integer()
) -> {ok, fse_enc_slot()} | {error, nil}.
find_slot_for(Slots, Symbol, Current_state) ->
case gleam_stdlib:map_get(Slots, Symbol) of
{error, _} ->
{error, nil};
{ok, List} ->
find_slot_in_list(List, Current_state)
end.
-file("src/packkit/zstd.gleam", 1389).
-spec dict_index_or_zero(gleam@dict:dict(integer(), integer()), integer()) -> integer().
dict_index_or_zero(D, Idx) ->
case gleam_stdlib:map_get(D, Idx) of
{ok, V} ->
V;
{error, _} ->
0
end.
-file("src/packkit/zstd.gleam", 1396).
-spec fse_encode_transitions(
gleam@dict:dict(integer(), integer()),
integer(),
integer(),
integer(),
gleam@dict:dict(integer(), list(fse_enc_slot())),
integer(),
integer(),
bitstring()
) -> {integer(), integer(), integer(), integer(), bitstring()}.
fse_encode_transitions(Weights, I, State_a, State_b, Slots, Buf, Bits, Out) ->
case I < 0 of
true ->
{Buf, Bits, State_a, State_b, Out};
false ->
W = dict_index_or_zero(Weights, I),
Use_state_a = erlang:'band'(I, 1) =:= 0,
Curr_state = case Use_state_a of
true ->
State_a;
false ->
State_b
end,
case find_slot_for(Slots, W, Curr_state) of
{error, _} ->
fse_encode_transitions(
Weights,
I - 1,
State_a,
State_b,
Slots,
Buf,
Bits,
Out
);
{ok, Slot} ->
Emit_value = Curr_state - erlang:element(3, Slot),
{Buf@1, Bits@1, Out@1} = push_bits_unchecked(
Buf,
Bits,
Out,
Emit_value,
erlang:element(5, Slot)
),
Prev_state = erlang:element(2, Slot),
{New_a, New_b} = case Use_state_a of
true ->
{Prev_state, State_b};
false ->
{State_a, Prev_state}
end,
fse_encode_transitions(
Weights,
I - 1,
New_a,
New_b,
Slots,
Buf@1,
Bits@1,
Out@1
)
end
end.
-file("src/packkit/zstd.gleam", 1486).
?DOC(
" Pack the Literals_Section_Header for the 1-stream Compressed form\n"
" (`size_format = 0`): 3 bytes carrying block_type=2, size_format=0,\n"
" 10-bit regenerated_size, and 10-bit compressed_size; followed by\n"
" the Huffman tree description and the bitstream.\n"
).
-spec build_compressed_literals_section(
integer(),
integer(),
bitstring(),
bitstring()
) -> bitstring().
build_compressed_literals_section(
Regenerated_size,
Compressed_size,
Tree_bytes,
Bitstream
) ->
B0 = erlang:'band'(
erlang:'bor'(
erlang:'bor'(2, 0),
erlang:'bsl'(erlang:'band'(Regenerated_size, 16#F), 4)
),
16#FF
),
Regen_high = erlang:'bsr'(Regenerated_size, 4),
Comp_low = erlang:'band'(Compressed_size, 16#3F),
B1 = erlang:'band'(
erlang:'bor'(
erlang:'band'(Regen_high, 16#3F),
erlang:'bsl'(Comp_low, 6)
),
16#FF
),
B2 = erlang:'band'(erlang:'bsr'(Compressed_size, 2), 16#FF),
gleam_stdlib:bit_array_concat([<<B0, B1, B2>>, Tree_bytes, Bitstream]).
-file("src/packkit/zstd.gleam", 1528).
-spec uniform_byte_loop(integer(), bitstring()) -> {ok, integer()} |
{error, nil}.
uniform_byte_loop(Byte, Rest) ->
case Rest of
<<>> ->
{ok, Byte};
<<B, More/binary>> when B =:= Byte ->
uniform_byte_loop(Byte, More);
_ ->
{error, nil}
end.
-file("src/packkit/zstd.gleam", 1521).
?DOC(
" Returns the single byte the whole chunk repeats, or Error if the\n"
" chunk has more than one distinct value.\n"
).
-spec peek_uniform_byte(bitstring()) -> {ok, integer()} | {error, nil}.
peek_uniform_byte(Bytes) ->
case Bytes of
<<First, Rest/binary>> ->
uniform_byte_loop(First, Rest);
_ ->
{error, nil}
end.
-file("src/packkit/zstd.gleam", 1536).
-spec block_header(integer(), integer(), boolean()) -> bitstring().
block_header(Block_size, Block_type, Is_last) ->
Last_bit = case Is_last of
true ->
1;
false ->
0
end,
Block_header_value = erlang:'bor'(
erlang:'bor'(erlang:'bsl'(Block_size, 3), erlang:'bsl'(Block_type, 1)),
Last_bit
),
Bh0 = erlang:'band'(Block_header_value, 16#FF),
Bh1 = erlang:'band'(erlang:'bsr'(Block_header_value, 8), 16#FF),
Bh2 = erlang:'band'(erlang:'bsr'(Block_header_value, 16), 16#FF),
<<Bh0, Bh1, Bh2>>.
-file("src/packkit/zstd.gleam", 1710).
-spec zstd_hash3(integer(), integer(), integer()) -> integer().
zstd_hash3(B0, B1, B2) ->
erlang:'band'(
erlang:'bxor'(
erlang:'bxor'(B0 * 2654435761, B1 * 40503),
B2 * 2246822519
),
16#FFFF
).
-file("src/packkit/zstd.gleam", 1720).
-spec zstd_byte_at(bitstring(), integer()) -> integer().
zstd_byte_at(Bytes, Pos) ->
case gleam_stdlib:bit_array_slice(Bytes, Pos, 1) of
{ok, <<B>>} ->
B;
_ ->
0
end.
-file("src/packkit/zstd.gleam", 1727).
-spec zstd_byte_slice(bitstring(), integer(), integer()) -> bitstring().
zstd_byte_slice(Bytes, Offset, Length) ->
case gleam_stdlib:bit_array_slice(Bytes, Offset, Length) of
{ok, V} ->
V;
{error, _} ->
<<>>
end.
-file("src/packkit/zstd.gleam", 1734).
-spec zstd_match_len(bitstring(), integer(), integer(), integer(), integer()) -> integer().
zstd_match_len(Bytes, Base, Cursor, Cap, Acc) ->
case Acc >= Cap of
true ->
Acc;
false ->
case zstd_byte_at(Bytes, Base + Acc) =:= zstd_byte_at(
Bytes,
Cursor + Acc
) of
true ->
zstd_match_len(Bytes, Base, Cursor, Cap, Acc + 1);
false ->
Acc
end
end.
-file("src/packkit/zstd.gleam", 1784).
-spec ll_to_code(integer()) -> integer().
ll_to_code(Length) ->
case Length of
N when (N >= 0) andalso (N =< 15) ->
N;
N@1 when N@1 < 18 ->
16;
N@2 when N@2 < 20 ->
17;
N@3 when N@3 < 22 ->
18;
N@4 when N@4 < 24 ->
19;
N@5 when N@5 < 28 ->
20;
N@6 when N@6 < 32 ->
21;
N@7 when N@7 < 40 ->
22;
N@8 when N@8 < 48 ->
23;
N@9 when N@9 < 64 ->
24;
N@10 when N@10 < 128 ->
25;
N@11 when N@11 < 256 ->
26;
N@12 when N@12 < 512 ->
27;
N@13 when N@13 < 1024 ->
28;
N@14 when N@14 < 2048 ->
29;
N@15 when N@15 < 4096 ->
30;
N@16 when N@16 < 8192 ->
31;
N@17 when N@17 < 16384 ->
32;
N@18 when N@18 < 32768 ->
33;
N@19 when N@19 < 65536 ->
34;
_ ->
35
end.
-file("src/packkit/zstd.gleam", 1812).
-spec ml_to_code(integer()) -> integer().
ml_to_code(Length) ->
case Length of
N when (N >= 3) andalso (N =< 34) ->
N - 3;
N@1 when N@1 < 37 ->
32;
N@2 when N@2 < 39 ->
33;
N@3 when N@3 < 41 ->
34;
N@4 when N@4 < 43 ->
35;
N@5 when N@5 < 47 ->
36;
N@6 when N@6 < 51 ->
37;
N@7 when N@7 < 59 ->
38;
N@8 when N@8 < 67 ->
39;
N@9 when N@9 < 83 ->
40;
N@10 when N@10 < 99 ->
41;
N@11 when N@11 < 131 ->
42;
N@12 when N@12 < 259 ->
43;
N@13 when N@13 < 515 ->
44;
N@14 when N@14 < 1027 ->
45;
N@15 when N@15 < 2051 ->
46;
N@16 when N@16 < 4099 ->
47;
N@17 when N@17 < 8195 ->
48;
N@18 when N@18 < 16387 ->
49;
N@19 when N@19 < 32771 ->
50;
N@20 when N@20 < 65539 ->
51;
_ ->
52
end.
-file("src/packkit/zstd.gleam", 1842).
-spec of_to_code(integer()) -> integer().
of_to_code(Raw_offset) ->
packkit@internal@fse:high_bit_position(Raw_offset).
-file("src/packkit/zstd.gleam", 1884).
-spec rep_aware_raw_offset(
integer(),
integer(),
{integer(), integer(), integer()}
) -> {integer(), {integer(), integer(), integer()}}.
rep_aware_raw_offset(Distance, Literal_length, Rep) ->
{R0, R1, R2} = Rep,
case Literal_length > 0 of
true ->
case Distance of
D when D =:= R0 ->
{1, {R0, R1, R2}};
D@1 when D@1 =:= R1 ->
{2, {R1, R0, R2}};
D@2 when D@2 =:= R2 ->
{3, {R2, R0, R1}};
D@3 ->
{D@3 + 3, {D@3, R0, R1}}
end;
false ->
case Distance of
D@4 when D@4 =:= R1 ->
{1, {R1, R0, R2}};
D@5 when D@5 =:= R2 ->
{2, {R2, R0, R1}};
D@6 when (R0 > 1) andalso (D@6 =:= (R0 - 1)) ->
{3, {R0 - 1, R0, R1}};
D@7 ->
{D@7 + 3, {D@7, R0, R1}}
end
end.
-file("src/packkit/zstd.gleam", 1856).
-spec compute_seq_codes(
list(zstd_sequence()),
{integer(), integer(), integer()},
list({integer(), integer(), integer(), integer(), integer(), integer()})
) -> list({integer(), integer(), integer(), integer(), integer(), integer()}).
compute_seq_codes(Sequences, Rep, Acc) ->
case Sequences of
[] ->
lists:reverse(Acc);
[Seq | Rest] ->
Ll_code = ll_to_code(erlang:element(2, Seq)),
Ml_code = ml_to_code(erlang:element(3, Seq)),
{Raw_offset, Next_rep} = rep_aware_raw_offset(
erlang:element(4, Seq),
erlang:element(2, Seq),
Rep
),
Of_code = of_to_code(Raw_offset),
Ll_extra_val = erlang:element(2, Seq) - packkit@internal@fse:ll_base(
Ll_code
),
Ml_extra_val = erlang:element(3, Seq) - packkit@internal@fse:ml_base(
Ml_code
),
Of_extra_val = Raw_offset - erlang:'bsl'(1, Of_code),
compute_seq_codes(
Rest,
Next_rep,
[{Ll_code,
Ml_code,
Of_code,
Ll_extra_val,
Ml_extra_val,
Of_extra_val} |
Acc]
)
end.
-file("src/packkit/zstd.gleam", 1917).
-spec build_seq_enc_slots_loop(
gleam@dict:dict(integer(), packkit@internal@fse:state_entry()),
integer(),
integer(),
gleam@dict:dict(integer(), list(fse_enc_slot()))
) -> gleam@dict:dict(integer(), list(fse_enc_slot())).
build_seq_enc_slots_loop(Table, S_idx, Table_size, Acc) ->
case S_idx >= Table_size of
true ->
Acc;
false ->
Entry = case gleam_stdlib:map_get(Table, S_idx) of
{ok, E} ->
E;
{error, _} ->
{state_entry, 0, 0, 0}
end,
Span = erlang:'bsl'(1, erlang:element(3, Entry)),
Slot = {fse_enc_slot,
S_idx,
erlang:element(4, Entry),
erlang:element(4, Entry) + Span,
erlang:element(3, Entry)},
Existing = case gleam_stdlib:map_get(Acc, erlang:element(2, Entry)) of
{ok, L} ->
L;
{error, _} ->
[]
end,
build_seq_enc_slots_loop(
Table,
S_idx + 1,
Table_size,
gleam@dict:insert(
Acc,
erlang:element(2, Entry),
[Slot | Existing]
)
)
end.
-file("src/packkit/zstd.gleam", 1910).
-spec build_seq_enc_slots(
gleam@dict:dict(integer(), packkit@internal@fse:state_entry()),
integer()
) -> gleam@dict:dict(integer(), list(fse_enc_slot())).
build_seq_enc_slots(Table, Table_size) ->
build_seq_enc_slots_loop(Table, 0, Table_size, maps:new()).
-file("src/packkit/zstd.gleam", 1952).
-spec smallest_state_in(
gleam@dict:dict(integer(), list(fse_enc_slot())),
integer(),
integer()
) -> integer().
smallest_state_in(Slots, Symbol, Table_size) ->
case gleam_stdlib:map_get(Slots, Symbol) of
{error, _} ->
0;
{ok, []} ->
0;
{ok, List} ->
smallest_state_idx_loop(List, Table_size)
end.
-file("src/packkit/zstd.gleam", 2168).
-spec bump_count(gleam@dict:dict(integer(), integer()), integer()) -> integer().
bump_count(D, Key) ->
case gleam_stdlib:map_get(D, Key) of
{ok, V} ->
V + 1;
{error, _} ->
1
end.
-file("src/packkit/zstd.gleam", 2151).
-spec tally_seq_alphabets(
list({integer(), integer(), integer(), integer(), integer(), integer()}),
gleam@dict:dict(integer(), integer()),
gleam@dict:dict(integer(), integer()),
gleam@dict:dict(integer(), integer())
) -> {gleam@dict:dict(integer(), integer()),
gleam@dict:dict(integer(), integer()),
gleam@dict:dict(integer(), integer())}.
tally_seq_alphabets(Seq_codes, Ll, Of_acc, Ml) ->
case Seq_codes of
[] ->
{Ll, Of_acc, Ml};
[{Ll_c, Ml_c, Of_c, _, _, _} | Rest] ->
Ll@1 = gleam@dict:insert(Ll, Ll_c, bump_count(Ll, Ll_c)),
Of_acc@1 = gleam@dict:insert(Of_acc, Of_c, bump_count(Of_acc, Of_c)),
Ml@1 = gleam@dict:insert(Ml, Ml_c, bump_count(Ml, Ml_c)),
tally_seq_alphabets(Rest, Ll@1, Of_acc@1, Ml@1)
end.
-file("src/packkit/zstd.gleam", 2211).
-spec highest_used_seq_code(gleam@dict:dict(integer(), integer()), integer()) -> integer().
highest_used_seq_code(Counts, Max_symbol) ->
gleam@dict:fold(
Counts,
-1,
fun(Acc, Sym, Count) ->
case ((Count > 0) andalso (Sym > Acc)) andalso (Sym =< Max_symbol) of
true ->
Sym;
false ->
Acc
end
end
).
-file("src/packkit/zstd.gleam", 2224).
-spec pick_accuracy_log_loop(integer(), integer(), integer()) -> integer().
pick_accuracy_log_loop(Log, Target, Cap) ->
case Log >= Cap of
true ->
Cap;
false ->
case erlang:'bsl'(1, Log) >= Target of
true ->
Log;
false ->
pick_accuracy_log_loop(Log + 1, Target, Cap)
end
end.
-file("src/packkit/zstd.gleam", 2220).
-spec pick_accuracy_log(integer(), integer()) -> integer().
pick_accuracy_log(Num_used_symbols, Cap) ->
pick_accuracy_log_loop(5, Num_used_symbols, Cap).
-file("src/packkit/zstd.gleam", 2263).
-spec build_floor_normalized_seq(
gleam@dict:dict(integer(), integer()),
integer(),
integer(),
integer(),
integer(),
list(integer())
) -> list(integer()).
build_floor_normalized_seq(Counts, Total, Table_size, Sym, Max_used, Acc) ->
case Sym > Max_used of
true ->
lists:reverse(Acc);
false ->
Count = case gleam_stdlib:map_get(Counts, Sym) of
{ok, V} ->
V;
{error, _} ->
0
end,
Normalized = case Count of
0 ->
0;
_ ->
Scaled = case Total of
0 -> 0;
Gleam@denominator -> Count * Table_size div Gleam@denominator
end,
case Scaled of
0 ->
1;
V@1 ->
V@1
end
end,
build_floor_normalized_seq(
Counts,
Total,
Table_size,
Sym + 1,
Max_used,
[Normalized | Acc]
)
end.
-file("src/packkit/zstd.gleam", 2235).
-spec normalize_seq_counts(
gleam@dict:dict(integer(), integer()),
integer(),
integer(),
integer(),
integer()
) -> {ok, list(integer())} | {error, nil}.
normalize_seq_counts(Counts, Total, Max_used, Table_size, _) ->
case Total of
0 ->
{error, nil};
_ ->
Raw = build_floor_normalized_seq(
Counts,
Total,
Table_size,
0,
Max_used,
[]
),
Sum = sum_int_list(Raw, 0),
Diff = Table_size - Sum,
case Diff of
0 ->
{ok, Raw};
_ ->
Idx = find_largest_count_index(Counts, Max_used),
case Idx < 0 of
true ->
{error, nil};
false ->
{ok, adjust_normalized_at(Raw, Idx, Diff, 0, [])}
end
end
end.
-file("src/packkit/zstd.gleam", 2181).
-spec prep_alphabet(
gleam@dict:dict(integer(), integer()),
integer(),
integer(),
integer()
) -> {ok, {list(integer()), integer(), integer(), bitstring()}} | {error, nil}.
prep_alphabet(Counts, Total, Max_symbol, Max_log) ->
Max_used = highest_used_seq_code(Counts, Max_symbol),
case Max_used < 0 of
true ->
{error, nil};
false ->
Log = pick_accuracy_log(Max_used + 1, Max_log),
Table_size = erlang:'bsl'(1, Log),
case normalize_seq_counts(Counts, Total, Max_used, Table_size, Log) of
{error, _} ->
{error, nil};
{ok, Norm} ->
Desc = encode_fse_dist_header_with_log(Norm, Max_used, Log),
{ok, {Norm, Max_used, Log, Desc}}
end
end.
-file("src/packkit/zstd.gleam", 2341).
-spec push_state_update(
gleam@dict:dict(integer(), list(fse_enc_slot())),
integer(),
integer(),
integer(),
integer(),
bitstring()
) -> {integer(), integer(), bitstring(), integer()}.
push_state_update(Slots, Symbol, Current_state, Buf, Bits, Out) ->
case find_slot_for(Slots, Symbol, Current_state) of
{error, _} ->
{Buf, Bits, Out, Current_state};
{ok, Slot} ->
Emit_value = Current_state - erlang:element(3, Slot),
{Buf@1, Bits@1, Out@1} = push_bits_unchecked(
Buf,
Bits,
Out,
Emit_value,
erlang:element(5, Slot)
),
{Buf@1, Bits@1, Out@1, erlang:element(2, Slot)}
end.
-file("src/packkit/zstd.gleam", 2296).
-spec seq_encode_loop(
list({integer(), integer(), integer(), integer(), integer(), integer()}),
gleam@dict:dict(integer(), list(fse_enc_slot())),
gleam@dict:dict(integer(), list(fse_enc_slot())),
gleam@dict:dict(integer(), list(fse_enc_slot())),
integer(),
integer(),
integer(),
integer(),
integer(),
bitstring()
) -> {integer(), integer(), bitstring(), integer(), integer(), integer()}.
seq_encode_loop(
Remaining,
Ll_slots,
Of_slots,
Ml_slots,
Ll_state,
Of_state,
Ml_state,
Buf,
Bits,
Out
) ->
case Remaining of
[] ->
{Buf, Bits, Out, Ll_state, Of_state, Ml_state};
[{Ll_c, Ml_c, Of_c, Ll_e, Ml_e, Of_e} | Rest] ->
{Buf@1, Bits@1, Out@1, Of_prev} = push_state_update(
Of_slots,
Of_c,
Of_state,
Buf,
Bits,
Out
),
{Buf@2, Bits@2, Out@2, Ml_prev} = push_state_update(
Ml_slots,
Ml_c,
Ml_state,
Buf@1,
Bits@1,
Out@1
),
{Buf@3, Bits@3, Out@3, Ll_prev} = push_state_update(
Ll_slots,
Ll_c,
Ll_state,
Buf@2,
Bits@2,
Out@2
),
{Buf@4, Bits@4, Out@4} = push_bits_unchecked(
Buf@3,
Bits@3,
Out@3,
Ll_e,
packkit@internal@fse:ll_extra_bits(Ll_c)
),
{Buf@5, Bits@5, Out@5} = push_bits_unchecked(
Buf@4,
Bits@4,
Out@4,
Ml_e,
packkit@internal@fse:ml_extra_bits(Ml_c)
),
{Buf@6, Bits@6, Out@6} = push_bits_unchecked(
Buf@5,
Bits@5,
Out@5,
Of_e,
Of_c
),
seq_encode_loop(
Rest,
Ll_slots,
Of_slots,
Ml_slots,
Ll_prev,
Of_prev,
Ml_prev,
Buf@6,
Bits@6,
Out@6
)
end.
-file("src/packkit/zstd.gleam", 1974).
?DOC(
" Encode the FSE sequence bitstream using the supplied per-alphabet\n"
" encoder lookups and accuracy logs. Emits the bits in reverse\n"
" decoder-read order so the resulting backward bitstream finalises\n"
" with the standard \"highest-set-bit of the last byte\" marker.\n"
" `seq_codes` is the forward-order list produced by\n"
" `compute_seq_codes` (which already integrates rep-offset\n"
" collapsing).\n"
).
-spec encode_seq_fse_with_tables(
list({integer(), integer(), integer(), integer(), integer(), integer()}),
gleam@dict:dict(integer(), list(fse_enc_slot())),
gleam@dict:dict(integer(), list(fse_enc_slot())),
gleam@dict:dict(integer(), list(fse_enc_slot())),
integer(),
integer(),
integer()
) -> bitstring().
encode_seq_fse_with_tables(
Seq_codes,
Ll_slots,
Of_slots,
Ml_slots,
Ll_log,
Of_log,
Ml_log
) ->
Ll_size = erlang:'bsl'(1, Ll_log),
Of_size = erlang:'bsl'(1, Of_log),
Ml_size = erlang:'bsl'(1, Ml_log),
Reversed = lists:reverse(Seq_codes),
case Reversed of
[] ->
<<>>;
[First | Rest] ->
{Ll0_c, Ml0_c, Of0_c, Ll0_e, Ml0_e, Of0_e} = First,
Ll_state = smallest_state_in(Ll_slots, Ll0_c, Ll_size),
Of_state = smallest_state_in(Of_slots, Of0_c, Of_size),
Ml_state = smallest_state_in(Ml_slots, Ml0_c, Ml_size),
{Buf, Bits, Out} = {0, 0, <<>>},
{Buf@1, Bits@1, Out@1} = push_bits_unchecked(
Buf,
Bits,
Out,
Ll0_e,
packkit@internal@fse:ll_extra_bits(Ll0_c)
),
{Buf@2, Bits@2, Out@2} = push_bits_unchecked(
Buf@1,
Bits@1,
Out@1,
Ml0_e,
packkit@internal@fse:ml_extra_bits(Ml0_c)
),
{Buf@3, Bits@3, Out@3} = push_bits_unchecked(
Buf@2,
Bits@2,
Out@2,
Of0_e,
Of0_c
),
{Buf@4, Bits@4, Out@4, Ll_state@1, Of_state@1, Ml_state@1} = seq_encode_loop(
Rest,
Ll_slots,
Of_slots,
Ml_slots,
Ll_state,
Of_state,
Ml_state,
Buf@3,
Bits@3,
Out@3
),
{Buf@5, Bits@5, Out@5} = push_bits_unchecked(
Buf@4,
Bits@4,
Out@4,
Ml_state@1,
Ml_log
),
{Buf@6, Bits@6, Out@6} = push_bits_unchecked(
Buf@5,
Bits@5,
Out@5,
Of_state@1,
Of_log
),
{Buf@7, Bits@7, Out@7} = push_bits_unchecked(
Buf@6,
Bits@6,
Out@6,
Ll_state@1,
Ll_log
),
Buf2 = erlang:'bor'(Buf@7, erlang:'bsl'(1, Bits@7)),
Bits2 = Bits@7 + 1,
flush_final_bits(Buf2, Bits2, Out@7)
end.
-file("src/packkit/zstd.gleam", 2036).
?DOC(
" Predefined_Mode sequence section: count bytes, mode byte 0x00,\n"
" FSE bitstream against the three predefined distributions.\n"
).
-spec build_seq_section_predefined(
bitstring(),
list({integer(), integer(), integer(), integer(), integer(), integer()})
) -> bitstring().
build_seq_section_predefined(Count_bytes, Seq_codes) ->
Ll_table = packkit@internal@fse:predefined_literal_length_table(),
Of_table = packkit@internal@fse:predefined_offset_table(),
Ml_table = packkit@internal@fse:predefined_match_length_table(),
Ll_log = packkit@internal@fse:predefined_literal_length_log(),
Of_log = packkit@internal@fse:predefined_offset_log(),
Ml_log = packkit@internal@fse:predefined_match_length_log(),
Ll_slots = build_seq_enc_slots(Ll_table, erlang:'bsl'(1, Ll_log)),
Of_slots = build_seq_enc_slots(Of_table, erlang:'bsl'(1, Of_log)),
Ml_slots = build_seq_enc_slots(Ml_table, erlang:'bsl'(1, Ml_log)),
Seq_bitstream = encode_seq_fse_with_tables(
Seq_codes,
Ll_slots,
Of_slots,
Ml_slots,
Ll_log,
Of_log,
Ml_log
),
gleam_stdlib:bit_array_concat([Count_bytes, <<16#00>>, Seq_bitstream]).
-file("src/packkit/zstd.gleam", 2362).
-spec encode_sequences_count(integer()) -> bitstring().
encode_sequences_count(Num) ->
case Num of
N when N < 128 ->
<<N>>;
N@1 when N@1 < 16#7F00 ->
High = erlang:'bsr'(N@1, 8) + 128,
Low = erlang:'band'(N@1, 16#FF),
<<High, Low>>;
N@2 ->
Value = N@2 - 16#7F00,
Lo = erlang:'band'(Value, 16#FF),
Hi = erlang:'band'(erlang:'bsr'(Value, 8), 16#FF),
<<255, Lo, Hi>>
end.
-file("src/packkit/zstd.gleam", 2483).
-spec build_raw_literals_section(bitstring(), integer()) -> bitstring().
build_raw_literals_section(Literals, Size) ->
B0 = erlang:'bor'(16#00, erlang:'bsl'(erlang:'band'(Size, 16#0F), 4)),
B0@1 = erlang:'bor'(B0, erlang:'bsl'(3, 2)),
B1 = erlang:'band'(erlang:'bsr'(Size, 4), 16#FF),
B2 = erlang:'band'(erlang:'bsr'(Size, 12), 16#FF),
gleam_stdlib:bit_array_concat([<<B0@1, B1, B2>>, Literals]).
-file("src/packkit/zstd.gleam", 2494).
-spec build_rle_literals_section(integer(), integer()) -> bitstring().
build_rle_literals_section(Byte, Size) ->
B0 = erlang:'bor'(16#01, erlang:'bsl'(erlang:'band'(Size, 16#0F), 4)),
B0@1 = erlang:'bor'(B0, erlang:'bsl'(3, 2)),
B1 = erlang:'band'(erlang:'bsr'(Size, 4), 16#FF),
B2 = erlang:'band'(erlang:'bsr'(Size, 12), 16#FF),
gleam_stdlib:bit_array_concat([<<B0@1, B1, B2>>, <<Byte>>]).
-file("src/packkit/zstd.gleam", 2660).
-spec consume_checksum_returning_rest(bitstring(), boolean()) -> {ok,
bitstring()} |
{error, packkit@error:codec_error()}.
consume_checksum_returning_rest(Bytes, Checksum_flag) ->
case Checksum_flag of
false ->
{ok, Bytes};
true ->
case Bytes of
<<_:4/binary, Rest/binary>> ->
{ok, Rest};
_ ->
{error,
{codec_invalid_data,
<<"zstd content checksum is shorter than 4 bytes"/utf8>>}}
end
end.
-file("src/packkit/zstd.gleam", 2721).
-spec skip_window_descriptor(bitstring()) -> {ok, bitstring()} |
{error, packkit@error:codec_error()}.
skip_window_descriptor(Bytes) ->
case Bytes of
<<_, Rest/binary>> ->
{ok, Rest};
_ ->
{error,
{codec_invalid_data,
<<"truncated zstd window descriptor"/utf8>>}}
end.
-file("src/packkit/zstd.gleam", 3085).
-spec huf_error_to_codec(packkit@internal@huf:huf_error()) -> packkit@error:codec_error().
huf_error_to_codec(Err) ->
case Err of
{huf_truncated, Message} ->
{codec_invalid_data, Message};
{huf_invalid_weights, Message@1} ->
{codec_invalid_data, Message@1};
{huf_bitstream_error, _} ->
{codec_invalid_data, <<"zstd Huffman bitstream truncated"/utf8>>};
{huf_unsupported, Feature} ->
{codec_not_implemented, Feature}
end.
-file("src/packkit/zstd.gleam", 3070).
-spec decode_huffman_streams(
packkit@internal@huf:tree(),
bitstring(),
compressed_literals_header()
) -> {ok, bitstring()} | {error, packkit@error:codec_error()}.
decode_huffman_streams(Tree, Bitstream_bytes, Header) ->
case erlang:element(4, Header) of
1 ->
_pipe = packkit@internal@huf:decode_stream(
Tree,
Bitstream_bytes,
erlang:element(2, Header)
),
gleam@result:map_error(_pipe, fun huf_error_to_codec/1);
_ ->
_pipe@1 = packkit@internal@huf:decode_four_streams(
Tree,
Bitstream_bytes,
erlang:element(2, Header)
),
gleam@result:map_error(_pipe@1, fun huf_error_to_codec/1)
end.
-file("src/packkit/zstd.gleam", 3095).
-spec parse_compressed_literals_header(bitstring(), integer(), integer()) -> {ok,
compressed_literals_header()} |
{error, packkit@error:codec_error()}.
parse_compressed_literals_header(Bytes, Header_byte, Size_format) ->
case Size_format of
0 ->
case Bytes of
<<_, B1, B2, _/binary>> ->
High_bits_of_header_byte = erlang:'bsr'(Header_byte, 4),
Regenerated_size = erlang:'bor'(
High_bits_of_header_byte,
erlang:'bsl'(erlang:'band'(B1, 16#3F), 4)
),
Compressed_size = erlang:'bor'(
erlang:'bsr'(B1, 6),
erlang:'bsl'(B2, 2)
),
{ok,
{compressed_literals_header,
Regenerated_size,
Compressed_size,
1,
3}};
_ ->
{error,
{codec_invalid_data,
<<"truncated zstd compressed-literals 3-byte header"/utf8>>}}
end;
1 ->
case Bytes of
<<_, B1@1, B2@1, _/binary>> ->
High_bits_of_header_byte@1 = erlang:'bsr'(Header_byte, 4),
Regenerated_size@1 = erlang:'bor'(
High_bits_of_header_byte@1,
erlang:'bsl'(erlang:'band'(B1@1, 16#3F), 4)
),
Compressed_size@1 = erlang:'bor'(
erlang:'bsr'(B1@1, 6),
erlang:'bsl'(B2@1, 2)
),
{ok,
{compressed_literals_header,
Regenerated_size@1,
Compressed_size@1,
4,
3}};
_ ->
{error,
{codec_invalid_data,
<<"truncated zstd compressed-literals 3-byte header"/utf8>>}}
end;
2 ->
case Bytes of
<<_, B1@2, B2@2, B3, _/binary>> ->
High_bits_of_header_byte@2 = erlang:'bsr'(Header_byte, 4),
Regenerated_size@2 = erlang:'bor'(
High_bits_of_header_byte@2,
erlang:'bor'(
erlang:'bsl'(B1@2, 4),
erlang:'bsl'(erlang:'band'(B2@2, 16#3), 12)
)
),
Compressed_size@2 = erlang:'bor'(
erlang:'bsr'(B2@2, 2),
erlang:'bsl'(B3, 6)
),
{ok,
{compressed_literals_header,
Regenerated_size@2,
Compressed_size@2,
4,
4}};
_ ->
{error,
{codec_invalid_data,
<<"truncated zstd compressed-literals 4-byte header"/utf8>>}}
end;
_ ->
case Bytes of
<<_, B1@3, B2@3, B3@1, B4, _/binary>> ->
High_bits_of_header_byte@3 = erlang:'bsr'(Header_byte, 4),
Regenerated_size@3 = erlang:'bor'(
High_bits_of_header_byte@3,
erlang:'bor'(
erlang:'bsl'(B1@3, 4),
erlang:'bsl'(erlang:'band'(B2@3, 16#3F), 12)
)
),
Compressed_size@3 = erlang:'bor'(
erlang:'bsr'(B2@3, 6),
erlang:'bor'(
erlang:'bsl'(B3@1, 2),
erlang:'bsl'(B4, 10)
)
),
{ok,
{compressed_literals_header,
Regenerated_size@3,
Compressed_size@3,
4,
5}};
_ ->
{error,
{codec_invalid_data,
<<"truncated zstd compressed-literals 5-byte header"/utf8>>}}
end
end.
-file("src/packkit/zstd.gleam", 3306).
-spec zstd_repeat_byte(integer(), integer(), bitstring()) -> bitstring().
zstd_repeat_byte(Byte, Count, Acc) ->
case Count of
0 ->
Acc;
_ ->
zstd_repeat_byte(Byte, Count - 1, <<Acc/bitstring, Byte>>)
end.
-file("src/packkit/zstd.gleam", 3455).
-spec alphabet_max_log(seq_alphabet()) -> integer().
alphabet_max_log(Alphabet) ->
case Alphabet of
seq_alphabet_ll ->
9;
seq_alphabet_of ->
8;
seq_alphabet_ml ->
9
end.
-file("src/packkit/zstd.gleam", 3463).
-spec alphabet_max_symbol(seq_alphabet()) -> integer().
alphabet_max_symbol(Alphabet) ->
case Alphabet of
seq_alphabet_ll ->
35;
seq_alphabet_of ->
31;
seq_alphabet_ml ->
52
end.
-file("src/packkit/zstd.gleam", 3474).
-spec predefined_for(seq_alphabet()) -> {gleam@dict:dict(integer(), packkit@internal@fse:state_entry()),
integer()}.
predefined_for(Alphabet) ->
case Alphabet of
seq_alphabet_ll ->
{packkit@internal@fse:predefined_literal_length_table(),
packkit@internal@fse:predefined_literal_length_log()};
seq_alphabet_of ->
{packkit@internal@fse:predefined_offset_table(),
packkit@internal@fse:predefined_offset_log()};
seq_alphabet_ml ->
{packkit@internal@fse:predefined_match_length_table(),
packkit@internal@fse:predefined_match_length_log()}
end.
-file("src/packkit/zstd.gleam", 3493).
-spec alphabet_label(seq_alphabet()) -> binary().
alphabet_label(Alphabet) ->
case Alphabet of
seq_alphabet_ll ->
<<"literal_length"/utf8>>;
seq_alphabet_of ->
<<"offset"/utf8>>;
seq_alphabet_ml ->
<<"match_length"/utf8>>
end.
-file("src/packkit/zstd.gleam", 3663).
-spec new_fwd_reader(bitstring()) -> fwd_bit_reader().
new_fwd_reader(Bytes) ->
{fwd_bit_reader, Bytes, 0, 0, false, 0}.
-file("src/packkit/zstd.gleam", 3673).
-spec fwd_refill(fwd_bit_reader(), integer()) -> fwd_bit_reader().
fwd_refill(Reader, Needed) ->
case (erlang:element(4, Reader) >= Needed) orelse erlang:element(5, Reader) of
true ->
Reader;
false ->
case erlang:element(2, Reader) of
<<B, Rest/binary>> ->
fwd_refill(
{fwd_bit_reader,
Rest,
erlang:'bor'(
erlang:element(3, Reader),
erlang:'bsl'(B, erlang:element(4, Reader))
),
erlang:element(4, Reader) + 8,
false,
erlang:element(6, Reader)},
Needed
);
_ ->
{fwd_bit_reader,
erlang:element(2, Reader),
erlang:element(3, Reader),
erlang:element(4, Reader),
true,
erlang:element(6, Reader)}
end
end.
-file("src/packkit/zstd.gleam", 3697).
-spec fwd_peek(fwd_bit_reader(), integer()) -> {integer(), fwd_bit_reader()}.
fwd_peek(Reader, Count) ->
Reader@1 = fwd_refill(Reader, Count),
Mask = erlang:'bsl'(1, Count) - 1,
{erlang:'band'(erlang:element(3, Reader@1), Mask), Reader@1}.
-file("src/packkit/zstd.gleam", 3703).
-spec fwd_drop(fwd_bit_reader(), integer()) -> fwd_bit_reader().
fwd_drop(Reader, Count) ->
Reader@1 = fwd_refill(Reader, Count),
{fwd_bit_reader,
erlang:element(2, Reader@1),
erlang:'bsr'(erlang:element(3, Reader@1), Count),
erlang:element(4, Reader@1) - Count,
erlang:element(5, Reader@1),
erlang:element(6, Reader@1) + Count}.
-file("src/packkit/zstd.gleam", 3714).
-spec fwd_read(fwd_bit_reader(), integer(), binary()) -> {ok,
{integer(), fwd_bit_reader()}} |
{error, packkit@error:codec_error()}.
fwd_read(Reader, Count, Label) ->
Reader@1 = fwd_refill(Reader, Count),
case erlang:element(4, Reader@1) < Count of
true ->
{error,
{codec_invalid_data, <<"truncated zstd "/utf8, Label/binary>>}};
false ->
{Value, Reader@2} = fwd_peek(Reader@1, Count),
{ok, {Value, fwd_drop(Reader@2, Count)}}
end.
-file("src/packkit/zstd.gleam", 3842).
?DOC(
" Split out of `decode_fse_distribution` so the dominant case (short\n"
" form) doesn't dominate the inner block's indentation budget.\n"
).
-spec decode_count_bits(integer(), integer(), integer(), integer()) -> {integer(),
integer()}.
decode_count_bits(Value, Threshold, Remaining, Bit_count) ->
Max_val = ((2 * Threshold) - 1) - Remaining,
case erlang:'band'(Value, Threshold - 1) < Max_val of
true ->
{erlang:'band'(Value, Threshold - 1), Bit_count - 1};
false ->
Raw = erlang:'band'(Value, (2 * Threshold) - 1),
Adjusted = case Raw >= Threshold of
true ->
Raw - Max_val;
false ->
Raw
end,
{Adjusted, Bit_count}
end.
-file("src/packkit/zstd.gleam", 3869).
-spec read_zero_rle_loop(fwd_bit_reader(), integer(), binary()) -> {ok,
{integer(), fwd_bit_reader()}} |
{error, packkit@error:codec_error()}.
read_zero_rle_loop(Reader, Acc, Label) ->
gleam@result:'try'(
fwd_read(
Reader,
2,
<<Label/binary, " FSE distribution zero-RLE flag"/utf8>>
),
fun(_use0) ->
{Value, Reader@1} = _use0,
case Value of
3 ->
read_zero_rle_loop(Reader@1, Acc + 3, Label);
N ->
{ok, {Acc + N, Reader@1}}
end
end
).
-file("src/packkit/zstd.gleam", 3862).
-spec read_zero_rle(fwd_bit_reader(), binary()) -> {ok,
{integer(), fwd_bit_reader()}} |
{error, packkit@error:codec_error()}.
read_zero_rle(Reader, Label) ->
read_zero_rle_loop(Reader, 0, Label).
-file("src/packkit/zstd.gleam", 3885).
-spec shrink_threshold(integer(), integer(), integer()) -> {integer(),
integer()}.
shrink_threshold(Threshold, Bit_count, Remaining) ->
case Remaining < Threshold of
true ->
shrink_threshold(Threshold div 2, Bit_count - 1, Remaining);
false ->
{Threshold, Bit_count}
end.
-file("src/packkit/zstd.gleam", 3896).
-spec prepend_zeros(integer(), list(integer())) -> list(integer()).
prepend_zeros(Count, Acc) ->
case Count of
N when N =< 0 ->
Acc;
_ ->
prepend_zeros(Count - 1, [0 | Acc])
end.
-file("src/packkit/zstd.gleam", 3777).
-spec decode_fse_distribution(
fwd_bit_reader(),
integer(),
integer(),
integer(),
integer(),
boolean(),
integer(),
integer(),
list(integer()),
binary()
) -> {ok, {list(integer()), fwd_bit_reader()}} |
{error, packkit@error:codec_error()}.
decode_fse_distribution(
Reader,
_,
Remaining,
Threshold,
Bit_count,
Previous_is_zero,
Charnum,
Max_symbol,
Acc,
Label
) ->
case (Remaining > 1) andalso (Charnum =< Max_symbol) of
false ->
{ok, {lists:reverse(Acc), Reader}};
true ->
case Previous_is_zero of
true ->
gleam@result:'try'(
read_zero_rle(Reader, Label),
fun(_use0) ->
{Extra, Reader@1} = _use0,
Acc@1 = prepend_zeros(Extra, Acc),
decode_fse_distribution(
Reader@1,
0,
Remaining,
Threshold,
Bit_count,
false,
Charnum + Extra,
Max_symbol,
Acc@1,
Label
)
end
);
false ->
{Value, Reader@2} = fwd_peek(Reader, Bit_count),
{Count, Bits_consumed} = decode_count_bits(
Value,
Threshold,
Remaining,
Bit_count
),
Reader@3 = fwd_drop(Reader@2, Bits_consumed),
Probability = Count - 1,
Abs_prob = case Probability < 0 of
true ->
- Probability;
false ->
Probability
end,
Remaining@1 = Remaining - Abs_prob,
Previous_is_zero@1 = Probability =:= 0,
{Threshold@1, Bit_count@1} = shrink_threshold(
Threshold,
Bit_count,
Remaining@1
),
decode_fse_distribution(
Reader@3,
0,
Remaining@1,
Threshold@1,
Bit_count@1,
Previous_is_zero@1,
Charnum + 1,
Max_symbol,
[Probability | Acc],
Label
)
end
end.
-file("src/packkit/zstd.gleam", 3903).
-spec pad_distribution(list(integer()), integer()) -> list(integer()).
pad_distribution(Counts, Target) ->
Current = erlang:length(Counts),
case Current >= Target of
true ->
Counts;
false ->
lists:append(Counts, gleam@list:repeat(0, Target - Current))
end.
-file("src/packkit/zstd.gleam", 3729).
-spec read_fse_distribution(bitstring(), integer(), integer(), binary()) -> {ok,
{list(integer()), integer(), bitstring()}} |
{error, packkit@error:codec_error()}.
read_fse_distribution(Bytes, Max_accuracy_log, Max_symbol, Label) ->
Reader = new_fwd_reader(Bytes),
gleam@result:'try'(
fwd_read(Reader, 4, <<Label/binary, " distribution accuracy_log"/utf8>>),
fun(_use0) ->
{Accuracy_minus_5, Reader@1} = _use0,
Accuracy_log = Accuracy_minus_5 + 5,
gleam@bool:guard(
Accuracy_log > Max_accuracy_log,
{error,
{codec_invalid_data,
<<<<"zstd "/utf8, Label/binary>>/binary,
" FSE accuracy_log exceeds the alphabet's maximum"/utf8>>}},
fun() ->
Table_size = erlang:'bsl'(1, Accuracy_log),
gleam@result:'try'(
decode_fse_distribution(
Reader@1,
Accuracy_log,
Table_size + 1,
Table_size,
Accuracy_log + 1,
false,
0,
Max_symbol,
[],
Label
),
fun(_use0@1) ->
{Counts, Reader@2} = _use0@1,
Bytes_consumed = (erlang:element(6, Reader@2) + 7)
div 8,
Total = erlang:byte_size(Bytes),
case gleam_stdlib:bit_array_slice(
Bytes,
Bytes_consumed,
Total - Bytes_consumed
) of
{ok, Rest} ->
{ok,
{pad_distribution(
Counts,
Max_symbol + 1
),
Accuracy_log,
Rest}};
{error, _} ->
{error,
{codec_invalid_data,
<<<<"truncated zstd "/utf8,
Label/binary>>/binary,
" FSE distribution tail"/utf8>>}}
end
end
)
end
)
end
).
-file("src/packkit/zstd.gleam", 3507).
?DOC(
" Read the table description for one sequence alphabet, honouring the\n"
" Predefined / RLE / FSE_Compressed / Repeat selector encoded in the\n"
" modes byte. Returns the materialised state table, its accuracy_log\n"
" (so the sequence decoder knows how many bits to read for the\n"
" initial state), and the byte slice that immediately follows the\n"
" table description.\n"
).
-spec load_sequence_table(
bitstring(),
integer(),
seq_alphabet(),
gleam@option:option({gleam@dict:dict(integer(), packkit@internal@fse:state_entry()),
integer()})
) -> {ok,
{gleam@dict:dict(integer(), packkit@internal@fse:state_entry()),
integer(),
bitstring()}} |
{error, packkit@error:codec_error()}.
load_sequence_table(Bytes, Mode, Alphabet, Prev) ->
case Mode of
0 ->
{Table, Accuracy_log} = predefined_for(Alphabet),
{ok, {Table, Accuracy_log, Bytes}};
1 ->
case Bytes of
<<Symbol, Rest/binary>> ->
Table@1 = maps:from_list([{0, {state_entry, Symbol, 0, 0}}]),
{ok, {Table@1, 0, Rest}};
_ ->
{error,
{codec_invalid_data,
<<<<"truncated zstd "/utf8,
(alphabet_label(Alphabet))/binary>>/binary,
" RLE mode symbol"/utf8>>}}
end;
2 ->
gleam@result:'try'(
read_fse_distribution(
Bytes,
alphabet_max_log(Alphabet),
alphabet_max_symbol(Alphabet),
alphabet_label(Alphabet)
),
fun(_use0) ->
{Distribution, Accuracy_log@1, Rest@1} = _use0,
Table@2 = packkit@internal@fse:build_state_table(
Distribution,
Accuracy_log@1
),
{ok, {Table@2, Accuracy_log@1, Rest@1}}
end
);
_ ->
case Prev of
{some, {Table@3, Accuracy_log@2}} ->
{ok, {Table@3, Accuracy_log@2, Bytes}};
none ->
{error,
{codec_invalid_data,
<<<<"zstd "/utf8,
(alphabet_label(Alphabet))/binary>>/binary,
" Repeat_Mode without a prior FSE table"/utf8>>}}
end
end.
-file("src/packkit/zstd.gleam", 3911).
-spec read_state_init(
packkit@internal@fse:backward_reader(),
integer(),
binary()
) -> {ok, {integer(), packkit@internal@fse:backward_reader()}} |
{error, packkit@error:codec_error()}.
read_state_init(Reader, Bits, Label) ->
case packkit@internal@fse:read_backward_bits(Reader, Bits) of
{ok, {V, R}} ->
{ok, {V, R}};
{error, _} ->
{error,
{codec_invalid_data,
<<<<"truncated zstd "/utf8, Label/binary>>/binary,
" initial state"/utf8>>}}
end.
-file("src/packkit/zstd.gleam", 4008).
-spec state_symbol(
gleam@dict:dict(integer(), packkit@internal@fse:state_entry()),
integer()
) -> integer().
state_symbol(Table, State) ->
case gleam_stdlib:map_get(Table, State) of
{ok, Entry} ->
erlang:element(2, Entry);
{error, _} ->
0
end.
-file("src/packkit/zstd.gleam", 4015).
-spec update_state(
packkit@internal@fse:backward_reader(),
gleam@dict:dict(integer(), packkit@internal@fse:state_entry()),
integer(),
binary()
) -> {ok, {packkit@internal@fse:backward_reader(), integer()}} |
{error, packkit@error:codec_error()}.
update_state(Reader, Table, State, Label) ->
Entry = case gleam_stdlib:map_get(Table, State) of
{ok, E} ->
E;
{error, _} ->
{state_entry, 0, 0, 0}
end,
case packkit@internal@fse:read_backward_bits(
Reader,
erlang:element(3, Entry)
) of
{ok, {Extra, R}} ->
{ok, {R, erlang:element(4, Entry) + Extra}};
{error, _} ->
{error,
{codec_invalid_data,
<<<<"truncated zstd "/utf8, Label/binary>>/binary,
" state-update bits"/utf8>>}}
end.
-file("src/packkit/zstd.gleam", 4034).
-spec read_bits_for(packkit@internal@fse:backward_reader(), integer(), binary()) -> {ok,
{integer(), packkit@internal@fse:backward_reader()}} |
{error, packkit@error:codec_error()}.
read_bits_for(Reader, Count, Label) ->
case packkit@internal@fse:read_backward_bits(Reader, Count) of
{ok, P} ->
{ok, P};
{error, _} ->
{error,
{codec_invalid_data, <<"truncated zstd "/utf8, Label/binary>>}}
end.
-file("src/packkit/zstd.gleam", 4046).
-spec resolve_offset(seq_context(), integer(), integer(), integer()) -> {integer(),
seq_context()}.
resolve_offset(Ctx, _, Raw_offset, Literal_length) ->
case Raw_offset of
1 ->
case Literal_length of
0 ->
Actual = erlang:element(7, Ctx),
{Actual,
{seq_context,
erlang:element(2, Ctx),
erlang:element(3, Ctx),
erlang:element(4, Ctx),
erlang:element(5, Ctx),
erlang:element(7, Ctx),
erlang:element(6, Ctx),
erlang:element(8, Ctx),
erlang:element(9, Ctx),
erlang:element(10, Ctx),
erlang:element(11, Ctx),
erlang:element(12, Ctx),
erlang:element(13, Ctx),
erlang:element(14, Ctx)}};
_ ->
{erlang:element(6, Ctx), Ctx}
end;
2 ->
case Literal_length of
0 ->
Actual@1 = erlang:element(8, Ctx),
{Actual@1,
{seq_context,
erlang:element(2, Ctx),
erlang:element(3, Ctx),
erlang:element(4, Ctx),
erlang:element(5, Ctx),
Actual@1,
erlang:element(6, Ctx),
erlang:element(7, Ctx),
erlang:element(9, Ctx),
erlang:element(10, Ctx),
erlang:element(11, Ctx),
erlang:element(12, Ctx),
erlang:element(13, Ctx),
erlang:element(14, Ctx)}};
_ ->
Actual@2 = erlang:element(7, Ctx),
{Actual@2,
{seq_context,
erlang:element(2, Ctx),
erlang:element(3, Ctx),
erlang:element(4, Ctx),
erlang:element(5, Ctx),
erlang:element(7, Ctx),
erlang:element(6, Ctx),
erlang:element(8, Ctx),
erlang:element(9, Ctx),
erlang:element(10, Ctx),
erlang:element(11, Ctx),
erlang:element(12, Ctx),
erlang:element(13, Ctx),
erlang:element(14, Ctx)}}
end;
3 ->
case Literal_length of
0 ->
Actual@3 = case erlang:element(6, Ctx) - 1 of
N when N =< 0 ->
1;
N@1 ->
N@1
end,
{Actual@3,
{seq_context,
erlang:element(2, Ctx),
erlang:element(3, Ctx),
erlang:element(4, Ctx),
erlang:element(5, Ctx),
Actual@3,
erlang:element(6, Ctx),
erlang:element(7, Ctx),
erlang:element(9, Ctx),
erlang:element(10, Ctx),
erlang:element(11, Ctx),
erlang:element(12, Ctx),
erlang:element(13, Ctx),
erlang:element(14, Ctx)}};
_ ->
Actual@4 = erlang:element(8, Ctx),
{Actual@4,
{seq_context,
erlang:element(2, Ctx),
erlang:element(3, Ctx),
erlang:element(4, Ctx),
erlang:element(5, Ctx),
Actual@4,
erlang:element(6, Ctx),
erlang:element(7, Ctx),
erlang:element(9, Ctx),
erlang:element(10, Ctx),
erlang:element(11, Ctx),
erlang:element(12, Ctx),
erlang:element(13, Ctx),
erlang:element(14, Ctx)}}
end;
_ ->
Actual@5 = Raw_offset - 3,
{Actual@5,
{seq_context,
erlang:element(2, Ctx),
erlang:element(3, Ctx),
erlang:element(4, Ctx),
erlang:element(5, Ctx),
Actual@5,
erlang:element(6, Ctx),
erlang:element(7, Ctx),
erlang:element(9, Ctx),
erlang:element(10, Ctx),
erlang:element(11, Ctx),
erlang:element(12, Ctx),
erlang:element(13, Ctx),
erlang:element(14, Ctx)}}
end.
-file("src/packkit/zstd.gleam", 4181).
-spec nth_from_back(list(integer()), integer()) -> {ok, integer()} |
{error, nil}.
nth_from_back(Values, N) ->
case {Values, N} of
{[Head | _], 0} ->
{ok, Head};
{[_ | Rest], _} ->
nth_from_back(Rest, N - 1);
{[], _} ->
{error, nil}
end.
-file("src/packkit/zstd.gleam", 4157).
-spec copy_match_loop(seq_context(), integer(), integer()) -> {ok,
seq_context()} |
{error, packkit@error:codec_error()}.
copy_match_loop(Ctx, Offset, Remaining) ->
case Remaining of
0 ->
{ok, Ctx};
_ ->
case nth_from_back(erlang:element(4, Ctx), Offset - 1) of
{ok, Byte} ->
copy_match_loop(
{seq_context,
erlang:element(2, Ctx),
erlang:element(3, Ctx),
[Byte | erlang:element(4, Ctx)],
erlang:element(5, Ctx),
erlang:element(6, Ctx),
erlang:element(7, Ctx),
erlang:element(8, Ctx),
erlang:element(9, Ctx),
erlang:element(10, Ctx),
erlang:element(11, Ctx),
erlang:element(12, Ctx),
erlang:element(13, Ctx),
erlang:element(14, Ctx)},
Offset,
Remaining - 1
);
{error, _} ->
{error,
{codec_invalid_data,
<<"zstd match offset exceeds emitted output"/utf8>>}}
end
end.
-file("src/packkit/zstd.gleam", 4149).
-spec copy_match(seq_context(), integer(), integer()) -> {ok, seq_context()} |
{error, packkit@error:codec_error()}.
copy_match(Ctx, Offset, Length) ->
copy_match_loop(Ctx, Offset, Length).
-file("src/packkit/zstd.gleam", 4189).
-spec prepend_bytes(bitstring(), list(integer())) -> list(integer()).
prepend_bytes(Chunk, Acc) ->
case Chunk of
<<B, Rest/binary>> ->
prepend_bytes(Rest, [B | Acc]);
_ ->
Acc
end.
-file("src/packkit/zstd.gleam", 2859).
?DOC(
" Prepend this block's output bytes to the running per-frame\n"
" reversed output so the next block's matches can reach back.\n"
).
-spec append_block_output(block_state(), bitstring()) -> block_state().
append_block_output(State, Plain) ->
{block_state,
erlang:element(2, State),
erlang:element(3, State),
prepend_bytes(Plain, erlang:element(4, State)),
erlang:element(5, State)}.
-file("src/packkit/zstd.gleam", 4124).
-spec copy_literals(seq_context(), integer()) -> {ok, seq_context()} |
{error, packkit@error:codec_error()}.
copy_literals(Ctx, Count) ->
case Count of
0 ->
{ok, Ctx};
_ ->
case gleam_stdlib:bit_array_slice(
erlang:element(2, Ctx),
erlang:element(3, Ctx),
Count
) of
{ok, Chunk} ->
{ok,
{seq_context,
erlang:element(2, Ctx),
erlang:element(3, Ctx) + Count,
prepend_bytes(Chunk, erlang:element(4, Ctx)),
erlang:element(5, Ctx),
erlang:element(6, Ctx),
erlang:element(7, Ctx),
erlang:element(8, Ctx),
erlang:element(9, Ctx),
erlang:element(10, Ctx),
erlang:element(11, Ctx),
erlang:element(12, Ctx),
erlang:element(13, Ctx),
erlang:element(14, Ctx)}};
{error, _} ->
{error,
{codec_invalid_data,
<<"zstd literal copy exceeds literals section"/utf8>>}}
end
end.
-file("src/packkit/zstd.gleam", 3925).
-spec decode_sequence_loop(
integer(),
seq_context(),
packkit@internal@fse:backward_reader()
) -> {ok, seq_context()} | {error, packkit@error:codec_error()}.
decode_sequence_loop(Remaining, Ctx, Reader) ->
case Remaining of
0 ->
{ok, Ctx};
_ ->
Ll_code = state_symbol(
erlang:element(12, Ctx),
erlang:element(9, Ctx)
),
Of_code = state_symbol(
erlang:element(13, Ctx),
erlang:element(10, Ctx)
),
Ml_code = state_symbol(
erlang:element(14, Ctx),
erlang:element(11, Ctx)
),
gleam@result:'try'(
read_bits_for(Reader, Of_code, <<"offset extra"/utf8>>),
fun(_use0) ->
{Offset_value, Reader@1} = _use0,
gleam@result:'try'(
read_bits_for(
Reader@1,
packkit@internal@fse:ml_extra_bits(Ml_code),
<<"match-length extra"/utf8>>
),
fun(_use0@1) ->
{Match_extra, Reader@2} = _use0@1,
gleam@result:'try'(
read_bits_for(
Reader@2,
packkit@internal@fse:ll_extra_bits(Ll_code),
<<"literal-length extra"/utf8>>
),
fun(_use0@2) ->
{Lit_extra, Reader@3} = _use0@2,
Literal_length = packkit@internal@fse:ll_base(
Ll_code
)
+ Lit_extra,
Match_length = packkit@internal@fse:ml_base(
Ml_code
)
+ Match_extra,
Raw_offset = erlang:'bsl'(1, Of_code) + Offset_value,
{Actual_offset, Ctx_after_offset} = resolve_offset(
Ctx,
Of_code,
Raw_offset,
Literal_length
),
gleam@result:'try'(
copy_literals(
Ctx_after_offset,
Literal_length
),
fun(Ctx_after_lit) ->
gleam@result:'try'(
copy_match(
Ctx_after_lit,
Actual_offset,
Match_length
),
fun(Ctx_after_match) ->
case Remaining of
1 ->
{ok,
Ctx_after_match};
_ ->
gleam@result:'try'(
update_state(
Reader@3,
erlang:element(
12,
Ctx
),
erlang:element(
9,
Ctx
),
<<"literal_length"/utf8>>
),
fun(_use0@3) ->
{Reader@4,
Ll_state} = _use0@3,
gleam@result:'try'(
update_state(
Reader@4,
erlang:element(
14,
Ctx
),
erlang:element(
11,
Ctx
),
<<"match_length"/utf8>>
),
fun(
_use0@4
) ->
{Reader@5,
Ml_state} = _use0@4,
gleam@result:'try'(
update_state(
Reader@5,
erlang:element(
13,
Ctx
),
erlang:element(
10,
Ctx
),
<<"offset"/utf8>>
),
fun(
_use0@5
) ->
{Reader@6,
Of_state} = _use0@5,
decode_sequence_loop(
Remaining
- 1,
{seq_context,
erlang:element(
2,
Ctx_after_match
),
erlang:element(
3,
Ctx_after_match
),
erlang:element(
4,
Ctx_after_match
),
erlang:element(
5,
Ctx_after_match
),
erlang:element(
6,
Ctx_after_match
),
erlang:element(
7,
Ctx_after_match
),
erlang:element(
8,
Ctx_after_match
),
Ll_state,
Of_state,
Ml_state,
erlang:element(
12,
Ctx_after_match
),
erlang:element(
13,
Ctx_after_match
),
erlang:element(
14,
Ctx_after_match
)},
Reader@6
)
end
)
end
)
end
)
end
end
)
end
)
end
)
end
)
end
)
end.
-file("src/packkit/zstd.gleam", 4212).
?DOC(
" Drop the `n` trailing elements from a list. Used to strip the\n"
" previous-blocks suffix off the running output buffer so only the\n"
" current block's payload is returned.\n"
).
-spec list_drop_tail(list(integer()), integer()) -> list(integer()).
list_drop_tail(Items, N) ->
Total = erlang:length(Items),
case Total - N of
Keep when Keep =< 0 ->
[];
Keep@1 ->
gleam@list:take(Items, Keep@1)
end.
-file("src/packkit/zstd.gleam", 4220).
-spec reverse_list_to_bit_array(list(integer()), bitstring()) -> bitstring().
reverse_list_to_bit_array(Values, Acc) ->
case Values of
[] ->
Acc;
[Head | Rest] ->
reverse_list_to_bit_array(Rest, <<Head, Acc/bitstring>>)
end.
-file("src/packkit/zstd.gleam", 4196).
-spec append_remaining_literals(seq_context()) -> bitstring().
append_remaining_literals(Ctx) ->
Remaining = erlang:byte_size(erlang:element(2, Ctx)) - erlang:element(
3,
Ctx
),
Tail@1 = case gleam_stdlib:bit_array_slice(
erlang:element(2, Ctx),
erlang:element(3, Ctx),
Remaining
) of
{ok, Tail} -> Tail;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/zstd"/utf8>>,
function => <<"append_remaining_literals"/utf8>>,
line => 4198,
value => _assert_fail,
start => 127265,
'end' => 127348,
pattern_start => 127276,
pattern_end => 127284})
end,
This_block_rev = list_drop_tail(
erlang:element(4, Ctx),
erlang:element(5, Ctx)
),
Prefix = reverse_list_to_bit_array(This_block_rev, <<>>),
gleam_stdlib:bit_array_concat([Prefix, Tail@1]).
-file("src/packkit/zstd.gleam", 3566).
-spec apply_sequences_with_tables(
integer(),
bitstring(),
bitstring(),
gleam@dict:dict(integer(), packkit@internal@fse:state_entry()),
integer(),
gleam@dict:dict(integer(), packkit@internal@fse:state_entry()),
integer(),
gleam@dict:dict(integer(), packkit@internal@fse:state_entry()),
integer(),
list(integer()),
{integer(), integer(), integer()}
) -> {ok, {bitstring(), {integer(), integer(), integer()}}} |
{error, packkit@error:codec_error()}.
apply_sequences_with_tables(
Num_sequences,
Bitstream,
Literals,
Ll_table,
Ll_log,
Of_table,
Of_log,
Ml_table,
Ml_log,
Previous_output_rev,
Reps
) ->
case packkit@internal@fse:new_backward_reader(Bitstream) of
{error, _} ->
{error,
{codec_invalid_data,
<<"zstd sequences bitstream is empty or missing marker"/utf8>>}};
{ok, Reader} ->
gleam@result:'try'(
read_state_init(Reader, Ll_log, <<"literal_length"/utf8>>),
fun(_use0) ->
{Ll_state, Reader@1} = _use0,
gleam@result:'try'(
read_state_init(Reader@1, Of_log, <<"offset"/utf8>>),
fun(_use0@1) ->
{Of_state, Reader@2} = _use0@1,
gleam@result:'try'(
read_state_init(
Reader@2,
Ml_log,
<<"match_length"/utf8>>
),
fun(_use0@2) ->
{Ml_state, Reader@3} = _use0@2,
Prev_size = erlang:length(
Previous_output_rev
),
{Rep0, Rep1, Rep2} = Reps,
Ctx = {seq_context,
Literals,
0,
Previous_output_rev,
Prev_size,
Rep0,
Rep1,
Rep2,
Ll_state,
Of_state,
Ml_state,
Ll_table,
Of_table,
Ml_table},
gleam@result:'try'(
decode_sequence_loop(
Num_sequences,
Ctx,
Reader@3
),
fun(Ctx@1) ->
{ok,
{append_remaining_literals(
Ctx@1
),
{erlang:element(6, Ctx@1),
erlang:element(7, Ctx@1),
erlang:element(8, Ctx@1)}}}
end
)
end
)
end
)
end
)
end.
-file("src/packkit/zstd.gleam", 4227).
-spec slice_or_error(bitstring(), integer(), integer(), binary()) -> {ok,
bitstring()} |
{error, packkit@error:codec_error()}.
slice_or_error(Bytes, Offset, Length, Label) ->
case gleam_stdlib:bit_array_slice(Bytes, Offset, Length) of
{ok, V} ->
{ok, V};
{error, _} ->
{error, {codec_invalid_data, <<"truncated "/utf8, Label/binary>>}}
end.
-file("src/packkit/zstd.gleam", 2982).
-spec decode_huffman_literals_block(bitstring(), compressed_literals_header()) -> {ok,
{bitstring(),
bitstring(),
gleam@option:option(packkit@internal@huf:tree())}} |
{error, packkit@error:codec_error()}.
decode_huffman_literals_block(Bytes, Header) ->
Section_total = erlang:element(5, Header) + erlang:element(3, Header),
gleam@result:'try'(
slice_or_error(
Bytes,
0,
Section_total,
<<"zstd compressed literals section body"/utf8>>
),
fun(Section) ->
After_section@1 = case gleam_stdlib:bit_array_slice(
Bytes,
Section_total,
erlang:byte_size(Bytes) - Section_total
) of
{ok, After_section} -> After_section;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/zstd"/utf8>>,
function => <<"decode_huffman_literals_block"/utf8>>,
line => 2995,
value => _assert_fail,
start => 92763,
'end' => 92904,
pattern_start => 92774,
pattern_end => 92791})
end,
Tree_bytes@1 = case gleam_stdlib:bit_array_slice(
Section,
erlang:element(5, Header),
Section_total - erlang:element(5, Header)
) of
{ok, Tree_bytes} -> Tree_bytes;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/zstd"/utf8>>,
function => <<"decode_huffman_literals_block"/utf8>>,
line => 3002,
value => _assert_fail@1,
start => 92908,
'end' => 93047,
pattern_start => 92919,
pattern_end => 92933})
end,
case packkit@internal@huf:read_tree(Tree_bytes@1) of
{error, Reason} ->
{error, huf_error_to_codec(Reason)};
{ok, {Tree, Tree_consumed}} ->
Bitstream_size = erlang:element(3, Header) - Tree_consumed,
gleam@result:'try'(
slice_or_error(
Section,
erlang:element(5, Header) + Tree_consumed,
Bitstream_size,
<<"zstd Huffman literal bitstream"/utf8>>
),
fun(Bitstream_bytes) ->
gleam@result:'try'(
decode_huffman_streams(
Tree,
Bitstream_bytes,
Header
),
fun(Literals) ->
{ok,
{Literals,
After_section@1,
{some, Tree}}}
end
)
end
)
end
end
).
-file("src/packkit/zstd.gleam", 3028).
-spec decode_treeless_literals_block(
bitstring(),
compressed_literals_header(),
gleam@option:option(packkit@internal@huf:tree())
) -> {ok,
{bitstring(),
bitstring(),
gleam@option:option(packkit@internal@huf:tree())}} |
{error, packkit@error:codec_error()}.
decode_treeless_literals_block(Bytes, Header, Prev_tree) ->
case Prev_tree of
none ->
{error,
{codec_invalid_data,
<<"zstd treeless literals without a prior Huffman tree"/utf8>>}};
{some, Tree} ->
Section_total = erlang:element(5, Header) + erlang:element(
3,
Header
),
gleam@result:'try'(
slice_or_error(
Bytes,
0,
Section_total,
<<"zstd treeless literals section body"/utf8>>
),
fun(Section) ->
After_section@1 = case gleam_stdlib:bit_array_slice(
Bytes,
Section_total,
erlang:byte_size(Bytes) - Section_total
) of
{ok, After_section} -> After_section;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/zstd"/utf8>>,
function => <<"decode_treeless_literals_block"/utf8>>,
line => 3046,
value => _assert_fail,
start => 94208,
'end' => 94369,
pattern_start => 94219,
pattern_end => 94236})
end,
gleam@result:'try'(
slice_or_error(
Section,
erlang:element(5, Header),
erlang:element(3, Header),
<<"zstd treeless literal bitstream"/utf8>>
),
fun(Bitstream_bytes) ->
gleam@result:'try'(
decode_huffman_streams(
Tree,
Bitstream_bytes,
Header
),
fun(Literals) ->
{ok, {Literals, After_section@1, Prev_tree}}
end
)
end
)
end
)
end.
-file("src/packkit/zstd.gleam", 2964).
-spec parse_compressed_literals(
bitstring(),
integer(),
integer(),
boolean(),
gleam@option:option(packkit@internal@huf:tree())
) -> {ok,
{bitstring(),
bitstring(),
gleam@option:option(packkit@internal@huf:tree())}} |
{error, packkit@error:codec_error()}.
parse_compressed_literals(Bytes, Header_byte, Size_format, Treeless, Prev_tree) ->
gleam@result:'try'(
parse_compressed_literals_header(Bytes, Header_byte, Size_format),
fun(Header) -> case Treeless of
true ->
decode_treeless_literals_block(Bytes, Header, Prev_tree);
false ->
decode_huffman_literals_block(Bytes, Header)
end end
).
-file("src/packkit/zstd.gleam", 3280).
-spec finalize_literals(bitstring(), integer(), boolean()) -> {ok,
{bitstring(), bitstring()}} |
{error, packkit@error:codec_error()}.
finalize_literals(Bytes, Size, Is_rle) ->
case Is_rle of
true ->
case Bytes of
<<Byte, Rest/binary>> ->
{ok, {zstd_repeat_byte(Byte, Size, <<>>), Rest}};
_ ->
{error,
{codec_invalid_data,
<<"truncated zstd RLE literals"/utf8>>}}
end;
false ->
gleam@result:'try'(
slice_or_error(
Bytes,
0,
Size,
<<"zstd raw literals body"/utf8>>
),
fun(Chunk) ->
Rest@2 = case gleam_stdlib:bit_array_slice(
Bytes,
Size,
erlang:byte_size(Bytes) - Size
) of
{ok, Rest@1} -> Rest@1;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/zstd"/utf8>>,
function => <<"finalize_literals"/utf8>>,
line => 3299,
value => _assert_fail,
start => 102339,
'end' => 102432,
pattern_start => 102350,
pattern_end => 102358})
end,
{ok, {Chunk, Rest@2}}
end
)
end.
-file("src/packkit/zstd.gleam", 3221).
-spec parse_raw_or_rle_literals(bitstring(), integer(), integer(), boolean()) -> {ok,
{bitstring(), bitstring()}} |
{error, packkit@error:codec_error()}.
parse_raw_or_rle_literals(Bytes, Header_byte, Size_format, Is_rle) ->
case Size_format of
0 ->
Regenerated_size = erlang:'bsr'(Header_byte, 3),
After_header@1 = case gleam_stdlib:bit_array_slice(
Bytes,
1,
erlang:byte_size(Bytes) - 1
) of
{ok, After_header} -> After_header;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/zstd"/utf8>>,
function => <<"parse_raw_or_rle_literals"/utf8>>,
line => 3231,
value => _assert_fail,
start => 100228,
'end' => 100323,
pattern_start => 100239,
pattern_end => 100255})
end,
finalize_literals(After_header@1, Regenerated_size, Is_rle);
2 ->
Regenerated_size = erlang:'bsr'(Header_byte, 3),
After_header@1 = case gleam_stdlib:bit_array_slice(
Bytes,
1,
erlang:byte_size(Bytes) - 1
) of
{ok, After_header} -> After_header;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/zstd"/utf8>>,
function => <<"parse_raw_or_rle_literals"/utf8>>,
line => 3231,
value => _assert_fail,
start => 100228,
'end' => 100323,
pattern_start => 100239,
pattern_end => 100255})
end,
finalize_literals(After_header@1, Regenerated_size, Is_rle);
1 ->
case Bytes of
<<_, B1, _/binary>> ->
Regenerated_size@1 = erlang:'bor'(
erlang:'bsr'(Header_byte, 4),
erlang:'bsl'(B1, 4)
),
After_header@3 = case gleam_stdlib:bit_array_slice(
Bytes,
2,
erlang:byte_size(Bytes) - 2
) of
{ok, After_header@2} -> After_header@2;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/zstd"/utf8>>,
function => <<"parse_raw_or_rle_literals"/utf8>>,
line => 3244,
value => _assert_fail@1,
start => 100716,
'end' => 100815,
pattern_start => 100727,
pattern_end => 100743})
end,
finalize_literals(
After_header@3,
Regenerated_size@1,
Is_rle
);
_ ->
{error,
{codec_invalid_data,
<<"truncated zstd literals 2-byte header"/utf8>>}}
end;
_ ->
case Bytes of
<<_, B1@1, B2, _/binary>> ->
Regenerated_size@2 = erlang:'bor'(
erlang:'bsr'(Header_byte, 4),
erlang:'bor'(
erlang:'bsl'(B1@1, 4),
erlang:'bsl'(B2, 12)
)
),
After_header@5 = case gleam_stdlib:bit_array_slice(
Bytes,
3,
erlang:byte_size(Bytes) - 3
) of
{ok, After_header@4} -> After_header@4;
_assert_fail@2 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/zstd"/utf8>>,
function => <<"parse_raw_or_rle_literals"/utf8>>,
line => 3267,
value => _assert_fail@2,
start => 101509,
'end' => 101608,
pattern_start => 101520,
pattern_end => 101536})
end,
finalize_literals(
After_header@5,
Regenerated_size@2,
Is_rle
);
_ ->
{error,
{codec_invalid_data,
<<"truncated zstd literals 3-byte header"/utf8>>}}
end
end.
-file("src/packkit/zstd.gleam", 2908).
-spec parse_literals_section(
bitstring(),
gleam@option:option(packkit@internal@huf:tree())
) -> {ok,
{bitstring(),
bitstring(),
gleam@option:option(packkit@internal@huf:tree())}} |
{error, packkit@error:codec_error()}.
parse_literals_section(Bytes, Prev_tree) ->
case Bytes of
<<Header_byte, _/binary>> ->
Literals_block_type = erlang:'band'(Header_byte, 16#3),
Size_format = erlang:'band'(erlang:'bsr'(Header_byte, 2), 16#3),
case Literals_block_type of
0 ->
_pipe = parse_raw_or_rle_literals(
Bytes,
Header_byte,
Size_format,
false
),
gleam@result:map(
_pipe,
fun(Pair) ->
{erlang:element(1, Pair),
erlang:element(2, Pair),
Prev_tree}
end
);
1 ->
_pipe@1 = parse_raw_or_rle_literals(
Bytes,
Header_byte,
Size_format,
true
),
gleam@result:map(
_pipe@1,
fun(Pair@1) ->
{erlang:element(1, Pair@1),
erlang:element(2, Pair@1),
Prev_tree}
end
);
2 ->
parse_compressed_literals(
Bytes,
Header_byte,
Size_format,
false,
Prev_tree
);
_ ->
parse_compressed_literals(
Bytes,
Header_byte,
Size_format,
true,
Prev_tree
)
end;
_ ->
{error,
{codec_invalid_data, <<"truncated zstd literals header"/utf8>>}}
end.
-file("src/packkit/zstd.gleam", 4239).
-spec slice_after(bitstring(), integer(), binary()) -> {ok, bitstring()} |
{error, packkit@error:codec_error()}.
slice_after(Bytes, Offset, Label) ->
case gleam_stdlib:bit_array_slice(
Bytes,
Offset,
erlang:byte_size(Bytes) - Offset
) of
{ok, V} ->
{ok, V};
{error, _} ->
{error, {codec_invalid_data, <<"truncated "/utf8, Label/binary>>}}
end.
-file("src/packkit/zstd.gleam", 3364).
-spec parse_sequences(
bitstring(),
integer(),
integer(),
bitstring(),
seq_tables_state(),
list(integer()),
{integer(), integer(), integer()}
) -> {ok, {bitstring(), seq_tables_state(), {integer(), integer(), integer()}}} |
{error, packkit@error:codec_error()}.
parse_sequences(
Bytes,
Count_size,
Num_sequences,
Literals,
Prev_tables,
Previous_output_rev,
Reps
) ->
gleam@result:'try'(
slice_after(Bytes, Count_size, <<"zstd sequences count"/utf8>>),
fun(After_count) -> case After_count of
<<Modes, _/binary>> ->
Literal_lengths_mode = erlang:'band'(
erlang:'bsr'(Modes, 6),
16#3
),
Offsets_mode = erlang:'band'(erlang:'bsr'(Modes, 4), 16#3),
Match_lengths_mode = erlang:'band'(
erlang:'bsr'(Modes, 2),
16#3
),
Reserved = erlang:'band'(Modes, 16#3),
gleam@bool:guard(
Reserved /= 0,
{error,
{codec_invalid_data,
<<"zstd sequences mode byte has reserved bits set"/utf8>>}},
fun() ->
gleam@result:'try'(
slice_after(
After_count,
1,
<<"zstd sequences mode byte"/utf8>>
),
fun(After_modes) ->
gleam@result:'try'(
load_sequence_table(
After_modes,
Literal_lengths_mode,
seq_alphabet_ll,
erlang:element(2, Prev_tables)
),
fun(_use0) ->
{Ll_table, Ll_log, After_ll} = _use0,
gleam@result:'try'(
load_sequence_table(
After_ll,
Offsets_mode,
seq_alphabet_of,
erlang:element(
3,
Prev_tables
)
),
fun(_use0@1) ->
{Of_table, Of_log, After_of} = _use0@1,
gleam@result:'try'(
load_sequence_table(
After_of,
Match_lengths_mode,
seq_alphabet_ml,
erlang:element(
4,
Prev_tables
)
),
fun(_use0@2) ->
{Ml_table,
Ml_log,
Bitstream} = _use0@2,
gleam@result:'try'(
apply_sequences_with_tables(
Num_sequences,
Bitstream,
Literals,
Ll_table,
Ll_log,
Of_table,
Of_log,
Ml_table,
Ml_log,
Previous_output_rev,
Reps
),
fun(_use0@3) ->
{Plain,
New_reps} = _use0@3,
{ok,
{Plain,
{seq_tables_state,
{some,
{Ll_table,
Ll_log}},
{some,
{Of_table,
Of_log}},
{some,
{Ml_table,
Ml_log}}},
New_reps}}
end
)
end
)
end
)
end
)
end
)
end
);
_ ->
{error,
{codec_invalid_data,
<<"truncated zstd sequences modes byte"/utf8>>}}
end end
).
-file("src/packkit/zstd.gleam", 3315).
-spec parse_and_apply_sequences(
bitstring(),
bitstring(),
seq_tables_state(),
list(integer()),
{integer(), integer(), integer()}
) -> {ok, {bitstring(), seq_tables_state(), {integer(), integer(), integer()}}} |
{error, packkit@error:codec_error()}.
parse_and_apply_sequences(
Bytes,
Literals,
Prev_tables,
Previous_output_rev,
Reps
) ->
case Bytes of
<<>> ->
{ok, {Literals, Prev_tables, Reps}};
<<Num_byte, _/binary>> when Num_byte =:= 0 ->
{ok, {Literals, Prev_tables, Reps}};
<<Num_byte@1, _/binary>> when Num_byte@1 < 128 ->
parse_sequences(
Bytes,
1,
Num_byte@1,
Literals,
Prev_tables,
Previous_output_rev,
Reps
);
<<Num_byte@2, B1, _/binary>> when Num_byte@2 < 255 ->
N = ((Num_byte@2 - 128) * 256) + B1,
parse_sequences(
Bytes,
2,
N,
Literals,
Prev_tables,
Previous_output_rev,
Reps
);
<<255, B1@1, B2, _/binary>> ->
N@1 = (B1@1 + (B2 * 256)) + 16#7F00,
parse_sequences(
Bytes,
3,
N@1,
Literals,
Prev_tables,
Previous_output_rev,
Reps
);
_ ->
{error,
{codec_invalid_data, <<"truncated zstd sequences header"/utf8>>}}
end.
-file("src/packkit/zstd.gleam", 2868).
-spec decode_compressed_block(bitstring(), integer(), block_state()) -> {ok,
{bitstring(), bitstring(), block_state()}} |
{error, packkit@error:codec_error()}.
decode_compressed_block(Bytes, Block_size, State) ->
gleam@result:'try'(
slice_or_error(
Bytes,
0,
Block_size,
<<"zstd compressed block payload"/utf8>>
),
fun(Payload) ->
Rest@1 = case gleam_stdlib:bit_array_slice(
Bytes,
Block_size,
erlang:byte_size(Bytes) - Block_size
) of
{ok, Rest} -> Rest;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/zstd"/utf8>>,
function => <<"decode_compressed_block"/utf8>>,
line => 2879,
value => _assert_fail,
start => 89271,
'end' => 89372,
pattern_start => 89282,
pattern_end => 89290})
end,
gleam@result:'try'(
parse_literals_section(Payload, erlang:element(2, State)),
fun(_use0) ->
{Literals, After_literals, Next_huffman} = _use0,
gleam@result:'try'(
parse_and_apply_sequences(
After_literals,
Literals,
erlang:element(3, State),
erlang:element(4, State),
erlang:element(5, State)
),
fun(_use0@1) ->
{Plain, Next_sequences, Next_reps} = _use0@1,
{ok,
{Plain,
Rest@1,
{block_state,
Next_huffman,
Next_sequences,
prepend_bytes(
Plain,
erlang:element(4, State)
),
Next_reps}}}
end
)
end
)
end
).
-file("src/packkit/zstd.gleam", 4250).
-spec decode_raw_block(bitstring(), integer()) -> {ok,
{bitstring(), bitstring()}} |
{error, packkit@error:codec_error()}.
decode_raw_block(Bytes, Block_size) ->
case gleam_stdlib:bit_array_slice(Bytes, 0, Block_size) of
{ok, Chunk} ->
case gleam_stdlib:bit_array_slice(
Bytes,
Block_size,
erlang:byte_size(Bytes) - Block_size
) of
{ok, Rest} ->
{ok, {Chunk, Rest}};
{error, _} ->
{error,
{codec_invalid_data,
<<"truncated zstd raw block tail"/utf8>>}}
end;
{error, _} ->
{error, {codec_invalid_data, <<"truncated zstd raw block"/utf8>>}}
end.
-file("src/packkit/zstd.gleam", 4282).
-spec repeat_byte(integer(), integer(), bitstring()) -> bitstring().
repeat_byte(Byte, Count, Acc) ->
case Count of
0 ->
Acc;
_ ->
repeat_byte(Byte, Count - 1, <<Acc/bitstring, Byte>>)
end.
-file("src/packkit/zstd.gleam", 4272).
-spec decode_rle_block(bitstring(), integer()) -> {ok,
{bitstring(), bitstring()}} |
{error, packkit@error:codec_error()}.
decode_rle_block(Bytes, Block_size) ->
case Bytes of
<<Byte, Rest/binary>> ->
{ok, {repeat_byte(Byte, Block_size, <<>>), Rest}};
_ ->
{error, {codec_invalid_data, <<"truncated zstd RLE block"/utf8>>}}
end.
-file("src/packkit/zstd.gleam", 2833).
-spec decode_one_block(bitstring(), integer(), integer(), block_state()) -> {ok,
{bitstring(), bitstring(), block_state()}} |
{error, packkit@error:codec_error()}.
decode_one_block(Bytes, Block_type, Block_size, State) ->
case Block_type of
0 ->
_pipe = decode_raw_block(Bytes, Block_size),
gleam@result:map(
_pipe,
fun(Pair) ->
{Plain, Rest} = Pair,
{Plain, Rest, append_block_output(State, Plain)}
end
);
1 ->
_pipe@1 = decode_rle_block(Bytes, Block_size),
gleam@result:map(
_pipe@1,
fun(Pair@1) ->
{Plain@1, Rest@1} = Pair@1,
{Plain@1, Rest@1, append_block_output(State, Plain@1)}
end
);
2 ->
decode_compressed_block(Bytes, Block_size, State);
_ ->
{error, {codec_invalid_data, <<"zstd reserved block type 3"/utf8>>}}
end.
-file("src/packkit/zstd.gleam", 4291).
-spec drop_bytes(bitstring(), integer(), binary()) -> {ok, bitstring()} |
{error, packkit@error:codec_error()}.
drop_bytes(Bytes, Count, Label) ->
case Count of
0 ->
{ok, Bytes};
_ ->
case gleam_stdlib:bit_array_slice(
Bytes,
Count,
erlang:byte_size(Bytes) - Count
) of
{ok, Rest} ->
{ok, Rest};
{error, _} ->
{error,
{codec_invalid_data,
<<"truncated "/utf8, Label/binary>>}}
end
end.
-file("src/packkit/zstd.gleam", 2729).
-spec skip_dictionary_id(bitstring(), integer()) -> {ok, bitstring()} |
{error, packkit@error:codec_error()}.
skip_dictionary_id(Bytes, Flag) ->
Size = case Flag of
0 ->
0;
1 ->
1;
2 ->
2;
3 ->
4;
_ ->
0
end,
drop_bytes(Bytes, Size, <<"zstd dictionary id"/utf8>>).
-file("src/packkit/zstd.gleam", 2743).
-spec skip_frame_content_size(bitstring(), integer(), boolean()) -> {ok,
bitstring()} |
{error, packkit@error:codec_error()}.
skip_frame_content_size(Bytes, Flag, Single_segment) ->
Size = case Flag of
0 ->
case Single_segment of
true ->
1;
false ->
0
end;
1 ->
2;
2 ->
4;
3 ->
8;
_ ->
0
end,
drop_bytes(Bytes, Size, <<"zstd frame content size"/utf8>>).
-file("src/packkit/zstd.gleam", 2689).
-spec parse_frame_descriptor(bitstring()) -> {ok, {boolean(), bitstring()}} |
{error, packkit@error:codec_error()}.
parse_frame_descriptor(Bytes) ->
case Bytes of
<<Descriptor, Rest/binary>> ->
Fcs_flag = erlang:'bsr'(Descriptor, 6),
Single_segment = erlang:'band'(Descriptor, 16#20) /= 0,
Reserved_bit = erlang:'band'(Descriptor, 16#08) /= 0,
Checksum_flag = erlang:'band'(Descriptor, 16#04) /= 0,
Dict_id_flag = erlang:'band'(Descriptor, 16#03),
gleam@bool:guard(
Reserved_bit,
{error,
{codec_invalid_data,
<<"zstd reserved descriptor bit must be zero"/utf8>>}},
fun() -> gleam@result:'try'(case Single_segment of
true ->
{ok, Rest};
false ->
skip_window_descriptor(Rest)
end, fun(Rest@1) ->
gleam@result:'try'(
skip_dictionary_id(Rest@1, Dict_id_flag),
fun(Rest@2) ->
gleam@result:'try'(
skip_frame_content_size(
Rest@2,
Fcs_flag,
Single_segment
),
fun(Rest@3) ->
{ok, {Checksum_flag, Rest@3}}
end
)
end
)
end) end
);
_ ->
{error,
{codec_invalid_data, <<"truncated zstd frame header"/utf8>>}}
end.
-file("src/packkit/zstd.gleam", 4307).
-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/zstd.gleam", 2798).
-spec decode_blocks(
bitstring(),
bitstring(),
packkit@limit:limits(),
block_state()
) -> {ok, {bitstring(), bitstring()}} | {error, packkit@error:codec_error()}.
decode_blocks(Bytes, Output, Limits, State) ->
case Bytes of
<<B0, B1, B2, Rest/binary>> ->
Header = erlang:'bor'(
B0,
erlang:'bor'(erlang:'bsl'(B1, 8), erlang:'bsl'(B2, 16))
),
Last = erlang:'band'(Header, 16#1) =:= 1,
Block_type = erlang:'band'(erlang:'bsr'(Header, 1), 16#3),
Block_size = erlang:'bsr'(Header, 3),
gleam@result:'try'(
decode_one_block(Rest, Block_type, Block_size, State),
fun(_use0) ->
{Plain, Rest@1, Next_state} = _use0,
gleam@result:'try'(
append_with_limit(Output, Plain, Limits),
fun(New_output) -> case Last of
true ->
{ok, {New_output, Rest@1}};
false ->
decode_blocks(
Rest@1,
New_output,
Limits,
Next_state
)
end end
)
end
);
_ ->
{error,
{codec_invalid_data, <<"truncated zstd block header"/utf8>>}}
end.
-file("src/packkit/zstd.gleam", 2679).
-spec parse_frame_header(bitstring()) -> {ok, {boolean(), bitstring()}} |
{error, packkit@error:codec_error()}.
parse_frame_header(Bytes) ->
case Bytes of
<<M:32/little-unsigned, Rest/binary>> when M =:= 16#FD2FB528 ->
parse_frame_descriptor(Rest);
_ ->
{error, {codec_invalid_data, <<"missing zstd frame magic"/utf8>>}}
end.
-file("src/packkit/zstd.gleam", 1027).
-spec encode_fse_dist_header(list(integer()), integer()) -> bitstring().
encode_fse_dist_header(Normalized, Max_used) ->
encode_fse_dist_header_with_log(Normalized, Max_used, 6).
-file("src/packkit/zstd.gleam", 935).
-spec build_floor_normalized(
gleam@dict:dict(integer(), integer()),
integer(),
integer(),
integer(),
list(integer())
) -> list(integer()).
build_floor_normalized(Counts, Total, Sym, Max_used, Acc) ->
case Sym > Max_used of
true ->
lists:reverse(Acc);
false ->
Count = case gleam_stdlib:map_get(Counts, Sym) of
{ok, V} ->
V;
{error, _} ->
0
end,
Normalized = case Count of
0 ->
0;
_ ->
Scaled = case Total of
0 -> 0;
Gleam@denominator -> Count * 64 div Gleam@denominator
end,
case Scaled of
0 ->
1;
V@1 ->
V@1
end
end,
build_floor_normalized(
Counts,
Total,
Sym + 1,
Max_used,
[Normalized | Acc]
)
end.
-file("src/packkit/zstd.gleam", 910).
-spec normalize_fse_weight_counts(
gleam@dict:dict(integer(), integer()),
integer(),
integer()
) -> {ok, list(integer())} | {error, nil}.
normalize_fse_weight_counts(Counts, Total, Max_used) ->
case Total of
0 ->
{error, nil};
_ ->
Raw = build_floor_normalized(Counts, Total, 0, Max_used, []),
Sum = sum_int_list(Raw, 0),
Diff = 64 - Sum,
case Diff of
0 ->
{ok, Raw};
_ ->
Idx = find_largest_count_index(Counts, Max_used),
case Idx < 0 of
true ->
{error, nil};
false ->
{ok, adjust_normalized_at(Raw, Idx, Diff, 0, [])}
end
end
end.
-file("src/packkit/zstd.gleam", 1247).
-spec build_fse_enc_slots(
gleam@dict:dict(integer(), packkit@internal@fse:state_entry())
) -> gleam@dict:dict(integer(), list(fse_enc_slot())).
build_fse_enc_slots(State_table) ->
build_fse_enc_slots_loop(State_table, 0, 64, maps:new()).
-file("src/packkit/zstd.gleam", 1288).
-spec smallest_state_for_symbol(
gleam@dict:dict(integer(), list(fse_enc_slot())),
integer()
) -> {ok, integer()} | {error, nil}.
smallest_state_for_symbol(Slots, Symbol) ->
case gleam_stdlib:map_get(Slots, Symbol) of
{error, _} ->
{error, nil};
{ok, []} ->
{error, nil};
{ok, List} ->
{ok, smallest_state_idx_loop(List, 64)}
end.
-file("src/packkit/zstd.gleam", 1335).
-spec encode_fse_weight_bitstream(
list(integer()),
gleam@dict:dict(integer(), packkit@internal@fse:state_entry())
) -> bitstring().
encode_fse_weight_bitstream(Weights, State_table) ->
N = erlang:length(Weights),
Slots = build_fse_enc_slots(State_table),
Weights_dict = list_to_indexed_dict(Weights, 0, maps:new()),
{Target_a_sym, Target_b_sym} = case erlang:'band'(N, 1) of
0 ->
{dict_index_or_zero(Weights_dict, N - 2),
dict_index_or_zero(Weights_dict, N - 1)};
_ ->
{dict_index_or_zero(Weights_dict, N - 1),
dict_index_or_zero(Weights_dict, N - 2)}
end,
State_a_init = case smallest_state_for_symbol(Slots, Target_a_sym) of
{ok, S} ->
S;
{error, _} ->
0
end,
State_b_init = case smallest_state_for_symbol(Slots, Target_b_sym) of
{ok, S@1} ->
S@1;
{error, _} ->
0
end,
{Buf, Bits, State_a, State_b, Out} = fse_encode_transitions(
Weights_dict,
N - 3,
State_a_init,
State_b_init,
Slots,
0,
0,
<<>>
),
{Buf@1, Bits@1, Out@1} = push_bits_unchecked(Buf, Bits, Out, State_b, 6),
{Buf@2, Bits@2, Out@2} = push_bits_unchecked(
Buf@1,
Bits@1,
Out@1,
State_a,
6
),
Buf2 = erlang:'bor'(Buf@2, erlang:'bsl'(1, Bits@2)),
Bits2 = Bits@2 + 1,
flush_final_bits(Buf2, Bits2, Out@2).
-file("src/packkit/zstd.gleam", 861).
-spec fse_encode_weight_stream(list(integer())) -> {ok, bitstring()} |
{error, nil}.
fse_encode_weight_stream(Weights) ->
Total = erlang:length(Weights),
Counts = tally_fse_weights(Weights, maps:new()),
Max_used = highest_used_fse_weight(Counts),
case Max_used < 0 of
true ->
{error, nil};
false ->
case normalize_fse_weight_counts(Counts, Total, Max_used) of
{error, _} ->
{error, nil};
{ok, Normalized} ->
Header = encode_fse_dist_header(Normalized, Max_used),
State_table = packkit@internal@fse:build_state_table(
Normalized,
6
),
Bitstream = encode_fse_weight_bitstream(
Weights,
State_table
),
{ok, gleam_stdlib:bit_array_concat([Header, Bitstream])}
end
end.
-file("src/packkit/zstd.gleam", 844).
?DOC(
" Try to serialize the Huffman tree as an FSE-compressed weight\n"
" stream. Returns `None` when the FSE body wouldn't fit the 127-byte\n"
" cap imposed by the 1-byte tree-description header (so the chunk\n"
" will fall back to Raw / RLE).\n"
).
-spec try_serialize_huffman_tree_fse(list(integer())) -> gleam@option:option(bitstring()).
try_serialize_huffman_tree_fse(Serialized) ->
case erlang:length(Serialized) < 2 of
true ->
none;
false ->
case fse_encode_weight_stream(Serialized) of
{error, _} ->
none;
{ok, Body} ->
Body_size = erlang:byte_size(Body),
case (Body_size =:= 0) orelse (Body_size > 127) of
true ->
none;
false ->
{some, <<Body_size, Body/bitstring>>}
end
end
end.
-file("src/packkit/zstd.gleam", 1460).
?DOC(
" Unified Huffman tree-description serializer. Picks the direct-\n"
" weight form when the alphabet fits (≤ 127 streamed weights) and\n"
" otherwise falls back to the FSE-compressed form. Returns `None`\n"
" when neither form fits — the caller drops Huffman for the chunk\n"
" and emits a Raw / RLE block instead.\n"
).
-spec serialize_huffman_tree_unified(list(integer())) -> gleam@option:option(bitstring()).
serialize_huffman_tree_unified(Lengths) ->
Max_bits = max_length_in_list(Lengths, 0),
Weights = gleam@list:map(Lengths, fun(L) -> case L of
0 ->
0;
_ ->
(Max_bits + 1) - L
end end),
Trimmed = trim_trailing_zero_weights(lists:reverse(Weights), []),
Serialized = drop_last_weight(Trimmed, []),
Num_serialized = erlang:length(Serialized),
case Num_serialized =< 127 of
true ->
Header_byte = 127 + Num_serialized,
Packed = pack_weights_4bit(Serialized, <<>>),
{some, <<Header_byte, Packed/bitstring>>};
false ->
try_serialize_huffman_tree_fse(Serialized)
end.
-file("src/packkit/zstd.gleam", 269).
?DOC(
" Try to encode `chunk` as a Huffman-compressed literals block.\n"
" Returns None when the chunk has fewer than two distinct bytes (a\n"
" trivial RLE case), when the resulting code would exceed zstd's\n"
" 11-bit tree-depth limit, or when the encoded form would not fit in\n"
" the 10-bit compressed-size field of the 1-stream literals header.\n"
).
-spec try_huffman_block(bitstring(), integer(), boolean()) -> gleam@option:option(bitstring()).
try_huffman_block(Chunk, Chunk_size, Is_last) ->
Freqs = count_byte_frequencies(Chunk),
Distinct = erlang:length(
gleam@list:filter(Freqs, fun(P) -> erlang:element(2, P) > 0 end)
),
case Distinct < 2 of
true ->
none;
false ->
case build_canonical_lengths(Freqs) of
{error, _} ->
none;
{ok, {Lengths, Max_bits}} ->
case Max_bits > 11 of
true ->
none;
false ->
case serialize_huffman_tree_unified(Lengths) of
none ->
none;
{some, Tree_bytes} ->
Code_table = assign_canonical_codes(
Lengths,
Max_bits
),
Bitstream = encode_huffman_bitstream(
Chunk,
Code_table
),
Comp_size = erlang:byte_size(Tree_bytes) + erlang:byte_size(
Bitstream
),
case Comp_size >= 1024 of
true ->
none;
false ->
Literals_section = build_compressed_literals_section(
Chunk_size,
Comp_size,
Tree_bytes,
Bitstream
),
Block_body = gleam_stdlib:bit_array_concat(
[Literals_section, <<16#00>>]
),
Block_body_size = erlang:byte_size(
Block_body
),
{some,
gleam_stdlib:bit_array_concat(
[block_header(
Block_body_size,
2,
Is_last
),
Block_body]
)}
end
end
end
end
end.
-file("src/packkit/zstd.gleam", 339).
?DOC(
" Same as `try_huffman_block`, but uses the 4-stream form (literals\n"
" header `size_format = 2`, 4-byte header, 14-bit regen / compressed\n"
" fields, 6-byte jump table before the four sub-bitstreams). Lets\n"
" the encoder Huffman-code blocks above the 1-stream 1023-byte cap,\n"
" up to 16 383 bytes per block. Splits the chunk into four parts\n"
" using zstd's `(N+3)/4, (N+2)/4, (N+1)/4, N/4` formula and runs the\n"
" existing 1-stream bitstream encoder once per part with the shared\n"
" Huffman code table.\n"
).
-spec try_huffman_block_4stream(bitstring(), integer(), boolean()) -> gleam@option:option(bitstring()).
try_huffman_block_4stream(Chunk, Chunk_size, Is_last) ->
Freqs = count_byte_frequencies(Chunk),
Distinct = erlang:length(
gleam@list:filter(Freqs, fun(P) -> erlang:element(2, P) > 0 end)
),
case Distinct < 2 of
true ->
none;
false ->
case build_canonical_lengths(Freqs) of
{error, _} ->
none;
{ok, {Lengths, Max_bits}} ->
case Max_bits > 11 of
true ->
none;
false ->
case serialize_huffman_tree_unified(Lengths) of
none ->
none;
{some, Tree_bytes} ->
Code_table = assign_canonical_codes(
Lengths,
Max_bits
),
Parts = split_chunk_4(Chunk, Chunk_size),
{P1, P2, P3, P4} = Parts,
S1 = encode_huffman_bitstream(
P1,
Code_table
),
S2 = encode_huffman_bitstream(
P2,
Code_table
),
S3 = encode_huffman_bitstream(
P3,
Code_table
),
S4 = encode_huffman_bitstream(
P4,
Code_table
),
S1_size = erlang:byte_size(S1),
S2_size = erlang:byte_size(S2),
S3_size = erlang:byte_size(S3),
S4_size = erlang:byte_size(S4),
case ((S1_size > 16#FFFF) orelse (S2_size > 16#FFFF))
orelse (S3_size > 16#FFFF) of
true ->
none;
false ->
Jump_table = <<S1_size:16/little,
S2_size:16/little,
S3_size:16/little>>,
Comp_size = ((((erlang:byte_size(
Tree_bytes
)
+ 6)
+ S1_size)
+ S2_size)
+ S3_size)
+ S4_size,
case Comp_size > 16383 of
true ->
none;
false ->
Literals_section = build_compressed_literals_section_4stream(
Chunk_size,
Comp_size,
Tree_bytes,
Jump_table,
S1,
S2,
S3,
S4
),
Block_body = gleam_stdlib:bit_array_concat(
[Literals_section,
<<16#00>>]
),
Block_body_size = erlang:byte_size(
Block_body
),
{some,
gleam_stdlib:bit_array_concat(
[block_header(
Block_body_size,
2,
Is_last
),
Block_body]
)}
end
end
end
end
end
end.
-file("src/packkit/zstd.gleam", 2507).
?DOC(
" Same Huffman 1-stream literals section the existing\n"
" `try_huffman_block` builds — exposed here without the surrounding\n"
" Sequences_Section so a sequences-encoding block can reuse it as\n"
" just the literals portion.\n"
).
-spec build_huffman_literals_section_only(bitstring(), integer()) -> gleam@option:option(bitstring()).
build_huffman_literals_section_only(Chunk, Chunk_size) ->
Freqs = count_byte_frequencies(Chunk),
Distinct = erlang:length(
gleam@list:filter(Freqs, fun(P) -> erlang:element(2, P) > 0 end)
),
case Distinct < 2 of
true ->
none;
false ->
case build_canonical_lengths(Freqs) of
{error, _} ->
none;
{ok, {Lengths, Max_bits}} ->
case Max_bits > 11 of
true ->
none;
false ->
case serialize_huffman_tree_unified(Lengths) of
none ->
none;
{some, Tree_bytes} ->
Code_table = assign_canonical_codes(
Lengths,
Max_bits
),
Bitstream = encode_huffman_bitstream(
Chunk,
Code_table
),
Comp_size = erlang:byte_size(Tree_bytes) + erlang:byte_size(
Bitstream
),
case Comp_size >= 1024 of
true ->
none;
false ->
{some,
build_compressed_literals_section(
Chunk_size,
Comp_size,
Tree_bytes,
Bitstream
)}
end
end
end
end
end.
-file("src/packkit/zstd.gleam", 2441).
-spec encode_literals_section_choice(bitstring(), integer()) -> bitstring().
encode_literals_section_choice(Literals, Literals_size) ->
Raw_section = build_raw_literals_section(Literals, Literals_size),
Rle_section = case {Literals_size >= 1, peek_uniform_byte(Literals)} of
{true, {ok, Byte}} ->
{some, build_rle_literals_section(Byte, Literals_size)};
{_, _} ->
none
end,
Candidates = case Rle_section of
{some, R} ->
[{erlang:byte_size(R), R},
{erlang:byte_size(Raw_section), Raw_section}];
none ->
[{erlang:byte_size(Raw_section), Raw_section}]
end,
Huff = case (Literals_size >= 64) andalso (Literals_size =< 1023) of
true ->
build_huffman_literals_section_only(Literals, Literals_size);
false ->
none
end,
Candidates@1 = case Huff of
{some, H} ->
[{erlang:byte_size(H), H} | Candidates];
none ->
Candidates
end,
case Candidates@1 of
[First | Rest] ->
erlang:element(
2,
gleam@list:fold(
Rest,
First,
fun(Acc, Item) ->
case erlang:element(1, Item) < erlang:element(1, Acc) of
true ->
Item;
false ->
Acc
end
end
)
);
[] ->
Raw_section
end.
-file("src/packkit/zstd.gleam", 1753).
-spec zstd_update_hashes_range(
bitstring(),
gleam@dict:dict(integer(), integer()),
integer(),
integer(),
integer()
) -> gleam@dict:dict(integer(), integer()).
zstd_update_hashes_range(Bytes, Hashes, From, To, Size) ->
case (From >= To) orelse ((From + 3) > Size) of
true ->
Hashes;
false ->
Key = zstd_hash3(
zstd_byte_at(Bytes, From),
zstd_byte_at(Bytes, From + 1),
zstd_byte_at(Bytes, From + 2)
),
zstd_update_hashes_range(
Bytes,
gleam@dict:insert(Hashes, Key, From),
From + 1,
To,
Size
)
end.
-file("src/packkit/zstd.gleam", 1599).
-spec zstd_lz77_loop(
bitstring(),
integer(),
integer(),
integer(),
gleam@dict:dict(integer(), integer()),
list(zstd_sequence()),
bitstring()
) -> {list(zstd_sequence()), bitstring(), integer()}.
zstd_lz77_loop(Bytes, Pos, Size, Last_emit, Hashes, Seqs_rev, Literals) ->
case Pos >= Size of
true ->
Trailing = zstd_byte_slice(Bytes, Last_emit, Size - Last_emit),
Final_literals = gleam_stdlib:bit_array_concat([Literals, Trailing]),
{Seqs_rev, Final_literals, Pos};
false ->
case (Pos + 3) > Size of
true ->
zstd_lz77_loop(
Bytes,
Pos + 1,
Size,
Last_emit,
Hashes,
Seqs_rev,
Literals
);
false ->
B0 = zstd_byte_at(Bytes, Pos),
B1 = zstd_byte_at(Bytes, Pos + 1),
B2 = zstd_byte_at(Bytes, Pos + 2),
Key = zstd_hash3(B0, B1, B2),
case gleam_stdlib:map_get(Hashes, Key) of
{error, _} ->
zstd_lz77_loop(
Bytes,
Pos + 1,
Size,
Last_emit,
gleam@dict:insert(Hashes, Key, Pos),
Seqs_rev,
Literals
);
{ok, Prev} ->
Distance = Pos - Prev,
case (Distance =< 0) orelse (Distance > 16#8000) of
true ->
zstd_lz77_loop(
Bytes,
Pos + 1,
Size,
Last_emit,
gleam@dict:insert(Hashes, Key, Pos),
Seqs_rev,
Literals
);
false ->
Cap = case (Size - Pos) < 131074 of
true ->
Size - Pos;
false ->
131074
end,
M_len = zstd_match_len(
Bytes,
Prev,
Pos,
Cap,
0
),
case M_len >= 3 of
true ->
Lit_len = Pos - Last_emit,
Lit_bytes = zstd_byte_slice(
Bytes,
Last_emit,
Lit_len
),
Seq = {zstd_sequence,
Lit_len,
M_len,
Distance},
Hashes@1 = zstd_update_hashes_range(
Bytes,
gleam@dict:insert(
Hashes,
Key,
Pos
),
Pos + 1,
Pos + M_len,
Size
),
zstd_lz77_loop(
Bytes,
Pos + M_len,
Size,
Pos + M_len,
Hashes@1,
[Seq | Seqs_rev],
gleam_stdlib:bit_array_concat(
[Literals, Lit_bytes]
)
);
false ->
zstd_lz77_loop(
Bytes,
Pos + 1,
Size,
Last_emit,
gleam@dict:insert(
Hashes,
Key,
Pos
),
Seqs_rev,
Literals
)
end
end
end
end
end.
-file("src/packkit/zstd.gleam", 1590).
?DOC(
" Run a greedy LZ77 match finder over `chunk` and return the list of\n"
" emitted sequences (in input order) plus the concatenated literal\n"
" buffer (every byte not covered by a match). Lengths and offsets\n"
" are real values — converting them to the LL/OF/ML wire symbols is\n"
" the next stage's job.\n"
).
-spec build_zstd_sequences(bitstring(), integer()) -> {list(zstd_sequence()),
bitstring()}.
build_zstd_sequences(Chunk, Chunk_size) ->
{Sequences_rev, Literals_acc, _} = zstd_lz77_loop(
Chunk,
0,
Chunk_size,
0,
maps:new(),
[],
<<>>
),
{lists:reverse(Sequences_rev), Literals_acc}.
-file("src/packkit/zstd.gleam", 2082).
?DOC(
" Try to encode the sequence section using FSE_Compressed_Mode for\n"
" LL/OF/ML. Returns `None` when normalisation fails for any of the\n"
" three alphabets — the caller falls back to Predefined_Mode.\n"
).
-spec build_seq_section_fse_compressed(
bitstring(),
list({integer(), integer(), integer(), integer(), integer(), integer()})
) -> gleam@option:option(bitstring()).
build_seq_section_fse_compressed(Count_bytes, Seq_codes) ->
{Ll_counts, Of_counts, Ml_counts} = tally_seq_alphabets(
Seq_codes,
maps:new(),
maps:new(),
maps:new()
),
Total = erlang:length(Seq_codes),
case {prep_alphabet(Ll_counts, Total, 35, 9),
prep_alphabet(Of_counts, Total, 31, 8),
prep_alphabet(Ml_counts, Total, 52, 9)} of
{{ok, {Ll_norm, _, Ll_log, Ll_desc}},
{ok, {Of_norm, _, Of_log, Of_desc}},
{ok, {Ml_norm, _, Ml_log, Ml_desc}}} ->
Ll_table = packkit@internal@fse:build_state_table(Ll_norm, Ll_log),
Of_table = packkit@internal@fse:build_state_table(Of_norm, Of_log),
Ml_table = packkit@internal@fse:build_state_table(Ml_norm, Ml_log),
Ll_slots = build_seq_enc_slots(Ll_table, erlang:'bsl'(1, Ll_log)),
Of_slots = build_seq_enc_slots(Of_table, erlang:'bsl'(1, Of_log)),
Ml_slots = build_seq_enc_slots(Ml_table, erlang:'bsl'(1, Ml_log)),
Bitstream = encode_seq_fse_with_tables(
Seq_codes,
Ll_slots,
Of_slots,
Ml_slots,
Ll_log,
Of_log,
Ml_log
),
Mode_byte = <<16#A8>>,
{some,
gleam_stdlib:bit_array_concat(
[Count_bytes,
Mode_byte,
Ll_desc,
Of_desc,
Ml_desc,
Bitstream]
)};
{_, _, _} ->
none
end.
-file("src/packkit/zstd.gleam", 2383).
?DOC(
" Try emitting `chunk` as a Compressed_Block with LZ77 sequences.\n"
" Returns None when sequences would not improve over the literals-\n"
" only (Huffman) path — i.e. when the match finder finds no matches\n"
" or when the resulting block grows past `huffman_max_block_compressed`.\n"
).
-spec try_sequences_block(bitstring(), integer(), boolean()) -> gleam@option:option(bitstring()).
try_sequences_block(Chunk, Chunk_size, Is_last) ->
{Sequences, Literals} = build_zstd_sequences(Chunk, Chunk_size),
Num_sequences = erlang:length(Sequences),
case Num_sequences of
0 ->
none;
_ ->
Literals_size = erlang:byte_size(Literals),
Literals_section = encode_literals_section_choice(
Literals,
Literals_size
),
Count_bytes = encode_sequences_count(Num_sequences),
Seq_codes = compute_seq_codes(Sequences, {1, 4, 8}, []),
Pre_section = build_seq_section_predefined(Count_bytes, Seq_codes),
Sequence_section = case Num_sequences >= 32 of
true ->
case build_seq_section_fse_compressed(
Count_bytes,
Seq_codes
) of
{some, Fse_section} ->
case erlang:byte_size(Fse_section) < erlang:byte_size(
Pre_section
) of
true ->
Fse_section;
false ->
Pre_section
end;
none ->
Pre_section
end;
false ->
Pre_section
end,
Block_body = gleam_stdlib:bit_array_concat(
[Literals_section, Sequence_section]
),
Block_body_size = erlang:byte_size(Block_body),
case Block_body_size >= erlang:'bsl'(1, 20) of
true ->
none;
false ->
{some,
gleam_stdlib:bit_array_concat(
[block_header(Block_body_size, 2, Is_last),
Block_body]
)}
end
end.
-file("src/packkit/zstd.gleam", 191).
?DOC(
" Encode one ≤ 1 KiB chunk and return whichever block representation\n"
" is the smallest: Raw, RLE (when the chunk is one repeating byte),\n"
" or a Compressed_Block whose Literals_Section is Huffman-coded.\n"
" The Sequences_Section always carries `Number_of_Sequences = 0` so\n"
" literals ARE the output — no LZ77, no sequences. Picking the\n"
" smallest of the three keeps the encoder strictly non-regressing on\n"
" uncompressible payloads.\n"
).
-spec pick_best_block(bitstring(), integer(), boolean()) -> bitstring().
pick_best_block(Chunk, Chunk_size, Is_last) ->
Raw_block = gleam_stdlib:bit_array_concat(
[block_header(Chunk_size, 0, Is_last), Chunk]
),
Raw_size = erlang:byte_size(Raw_block),
Rle_block = case {Chunk_size >= 2, peek_uniform_byte(Chunk)} of
{true, {ok, Byte}} ->
{some,
gleam_stdlib:bit_array_concat(
[block_header(Chunk_size, 1, Is_last), <<Byte>>]
)};
{_, _} ->
none
end,
Huff_block = case (Chunk_size >= 64) andalso (Chunk_size =< 1023) of
true ->
try_huffman_block(Chunk, Chunk_size, Is_last);
false ->
none
end,
Huff_4stream_block = case (Chunk_size > 1023) andalso (Chunk_size >= 4) of
true ->
try_huffman_block_4stream(Chunk, Chunk_size, Is_last);
false ->
none
end,
Seq_block = case Chunk_size >= 4 of
true ->
try_sequences_block(Chunk, Chunk_size, Is_last);
false ->
none
end,
Candidates = [{Raw_size, Raw_block} | case Rle_block of
{some, Rle} ->
[{erlang:byte_size(Rle), Rle}];
none ->
[]
end],
Candidates@1 = case Huff_block of
{some, H} ->
[{erlang:byte_size(H), H} | Candidates];
none ->
Candidates
end,
Candidates@2 = case Huff_4stream_block of
{some, H@1} ->
[{erlang:byte_size(H@1), H@1} | Candidates@1];
none ->
Candidates@1
end,
Candidates@3 = case Seq_block of
{some, S} ->
[{erlang:byte_size(S), S} | Candidates@2];
none ->
Candidates@2
end,
pick_smallest_block(Candidates@3).
-file("src/packkit/zstd.gleam", 151).
-spec emit_raw_blocks_loop(bitstring(), integer(), bitstring()) -> bitstring().
emit_raw_blocks_loop(Remaining_bytes, Remaining_size, Acc) ->
case Remaining_size of
0 ->
Acc;
N ->
Chunk_size = case N > 16383 of
true ->
16383;
false ->
N
end,
Is_last = Chunk_size =:= N,
Chunk@1 = case gleam_stdlib:bit_array_slice(
Remaining_bytes,
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/zstd"/utf8>>,
function => <<"emit_raw_blocks_loop"/utf8>>,
line => 167,
value => _assert_fail,
start => 6261,
'end' => 6331,
pattern_start => 6272,
pattern_end => 6281})
end,
Rest@1 = case gleam_stdlib:bit_array_slice(
Remaining_bytes,
Chunk_size,
erlang:byte_size(Remaining_bytes) - Chunk_size
) of
{ok, Rest} -> Rest;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/zstd"/utf8>>,
function => <<"emit_raw_blocks_loop"/utf8>>,
line => 168,
value => _assert_fail@1,
start => 6338,
'end' => 6504,
pattern_start => 6349,
pattern_end => 6357})
end,
Chunk_block = pick_best_block(Chunk@1, Chunk_size, Is_last),
emit_raw_blocks_loop(
Rest@1,
Remaining_size - Chunk_size,
gleam_stdlib:bit_array_concat([Acc, Chunk_block])
)
end.
-file("src/packkit/zstd.gleam", 144).
-spec build_raw_blocks(bitstring(), integer()) -> bitstring().
build_raw_blocks(Bytes, Total) ->
case Total of
0 ->
block_header(0, 0, true);
_ ->
emit_raw_blocks_loop(Bytes, Total, <<>>)
end.
-file("src/packkit/zstd.gleam", 76).
?DOC(
" Encode `bytes` as a Zstandard frame. The encoder picks the\n"
" cheapest of `Raw_Block` and `RLE_Block` per chunk — a chunk that\n"
" repeats a single byte collapses to a 1-byte RLE payload — so\n"
" inputs like `repeat('A', N)` compress, but mixed input still\n"
" passes through as raw bytes. No LZ77 or Huffman compression yet,\n"
" no content checksum. Output is a valid Zstandard frame any\n"
" conforming decoder can read.\n"
).
-spec encode(bitstring()) -> {ok, bitstring()} |
{error, packkit@error:codec_error()}.
encode(Bytes) ->
Size = erlang:byte_size(Bytes),
gleam@result:'try'(
frame_header_for_size(Size),
fun(Header) ->
Blocks = build_raw_blocks(Bytes, Size),
{ok, gleam_stdlib:bit_array_concat([Header, Blocks])}
end
).
-file("src/packkit/zstd.gleam", 2589).
-spec decode_data_frame(
bitstring(),
bitstring(),
integer(),
packkit@limit:limits()
) -> {ok, bitstring()} | {error, packkit@error:codec_error()}.
decode_data_frame(Bytes, Acc, Accumulated_size, Limits) ->
gleam@result:'try'(
parse_frame_header(Bytes),
fun(_use0) ->
{Checksum_flag, Rest} = _use0,
gleam@result:'try'(
decode_blocks(
Rest,
<<>>,
Limits,
{block_state,
none,
{seq_tables_state, none, none, none},
[],
{1, 4, 8}}
),
fun(_use0@1) ->
{Output, Rest@1} = _use0@1,
gleam@result:'try'(
consume_checksum_returning_rest(Rest@1, Checksum_flag),
fun(Rest@2) ->
Next_size = Accumulated_size + erlang:byte_size(
Output
),
case Next_size > packkit@limit:max_output_bytes(
Limits
) of
true ->
{error,
{codec_limit_exceeded,
<<"max_output_bytes"/utf8>>,
Next_size}};
false ->
Acc@1 = gleam_stdlib:bit_array_concat(
[Acc, Output]
),
case erlang:byte_size(Rest@2) of
0 ->
{ok, Acc@1};
_ ->
decode_frames_loop(
Rest@2,
Acc@1,
Next_size,
Limits
)
end
end
end
)
end
)
end
).
-file("src/packkit/zstd.gleam", 2571).
-spec decode_frames_loop(
bitstring(),
bitstring(),
integer(),
packkit@limit:limits()
) -> {ok, bitstring()} | {error, packkit@error:codec_error()}.
decode_frames_loop(Bytes, Acc, Accumulated_size, Limits) ->
case Bytes of
<<M:32/little-unsigned, _/binary>> when (M >= 16#184D2A50) andalso (M =< 16#184D2A5F) ->
skip_skippable_frame(Bytes, Acc, Accumulated_size, Limits);
_ ->
decode_data_frame(Bytes, Acc, Accumulated_size, Limits)
end.
-file("src/packkit/zstd.gleam", 2556).
?DOC(
" Decode a Zstandard frame using explicit limits. Per RFC 8478 §3,\n"
" a zstd \"byte stream\" is one or more frames concatenated; the\n"
" decoder walks the entire input, appending each frame's payload to\n"
" the result.\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() -> decode_frames_loop(Bytes, <<>>, 0, Limits) end
).
-file("src/packkit/zstd.gleam", 2548).
?DOC(" Decode a Zstandard frame using default limits.\n").
-spec decode(bitstring()) -> {ok, bitstring()} |
{error, packkit@error:codec_error()}.
decode(Bytes) ->
decode_with_limits(Bytes, packkit@limit:default()).
-file("src/packkit/zstd.gleam", 2620).
-spec skip_skippable_frame(
bitstring(),
bitstring(),
integer(),
packkit@limit:limits()
) -> {ok, bitstring()} | {error, packkit@error:codec_error()}.
skip_skippable_frame(Bytes, Acc, Accumulated_size, Limits) ->
case Bytes of
<<_:4/binary, Frame_size:32/little-unsigned, Rest/binary>> ->
case erlang:byte_size(Rest) >= Frame_size of
false ->
{error,
{codec_invalid_data,
<<"zstd skippable frame body is shorter than the declared Frame_Size"/utf8>>}};
true ->
case gleam_stdlib:bit_array_slice(
Rest,
Frame_size,
erlang:byte_size(Rest) - Frame_size
) of
{ok, After_skip} ->
case erlang:byte_size(After_skip) of
0 ->
{ok, Acc};
_ ->
decode_frames_loop(
After_skip,
Acc,
Accumulated_size,
Limits
)
end;
{error, _} ->
{error,
{codec_invalid_data,
<<"zstd skippable frame slice failed"/utf8>>}}
end
end;
_ ->
{error,
{codec_invalid_data,
<<"zstd skippable frame header is shorter than 8 bytes"/utf8>>}}
end.