-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 => <>, 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 => <>, 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 => <>, 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 => <>, 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( [<>, 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 <> -> 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), <>; [High, Low | Rest] -> Byte@1 = erlang:'bor'(erlang:'bsl'(High, 4), Low), pack_weights_4bit(Rest, <>) 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 <> -> 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, <>); 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, <>) 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), <> 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([<>, 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}; <> 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 <> -> 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), <>. -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; _ -> 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@1 when N@1 < 16#7F00 -> High = erlang:'bsr'(N@1, 8) + 128, Low = erlang:'band'(N@1, 16#FF), <>; 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([<>, 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([<>, <>]). -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, <>) 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 <> -> 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, <