-module(packkit). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/packkit.gleam"). -export([package_version/0, decompress_with_limits/3, decompress/2, compress/2, read_with_limits/3, read/2, write/2, detect_filename/1, detect_bytes/1, detect_path_or_bytes/2, pack/2, unpack_with_limits/3, unpack/2]). -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( " Facade for the `packkit` package. This module wires the codec,\n" " archive, and recipe primitives so callers can read, write, pack,\n" " and unpack data without selecting the underlying engine by hand.\n" ). -file("src/packkit.gleam", 60). ?DOC(" The package version.\n"). -spec package_version() -> binary(). package_version() -> <<"0.1.0"/utf8>>. -file("src/packkit.gleam", 165). -spec enforce_input_limit(bitstring(), packkit@limit:limits()) -> {ok, nil} | {error, packkit@error:codec_error()}. enforce_input_limit(Bytes, Limits) -> Size = erlang:byte_size(Bytes), case Size > packkit@limit:max_input_bytes(Limits) of true -> {error, {codec_limit_exceeded, <<"max_input_bytes"/utf8>>, Size}}; false -> {ok, nil} end. -file("src/packkit.gleam", 219). -spec decompress_zlib( bitstring(), packkit@codec:codec(), packkit@limit:limits() ) -> {ok, bitstring()} | {error, packkit@error:codec_error()}. decompress_zlib(Bytes, Codec_value, Limits) -> case packkit@codec:dictionary_of(Codec_value) of none -> packkit@zlib:decode_with_limits(Bytes, Limits); {some, Dict} -> packkit@zlib:decode_with_dictionary_and_limits( Bytes, packkit@codec:dictionary_bytes(Dict), Limits ) end. -file("src/packkit.gleam", 294). -spec reject_dictionary(packkit@codec:codec()) -> {ok, nil} | {error, packkit@error:codec_error()}. reject_dictionary(Codec_value) -> case packkit@codec:dictionary_of(Codec_value) of none -> {ok, nil}; {some, _} -> case packkit@codec:name(Codec_value) of <<"zlib"/utf8>> -> {ok, nil}; Name -> {error, {codec_option_unsupported, <<"dictionary"/utf8>>, Name}} end end. -file("src/packkit.gleam", 309). -spec reject_level(packkit@codec:codec(), binary()) -> {ok, nil} | {error, packkit@error:codec_error()}. reject_level(Codec_value, Codec_name) -> case packkit@codec:level(Codec_value) of none -> {ok, nil}; {some, _} -> {error, {codec_option_unsupported, <<"level"/utf8>>, Codec_name}} end. -file("src/packkit.gleam", 266). ?DOC( " Codecs whose encoders genuinely cannot consume a level knob — any\n" " non-`None` level (other than the implicit default) is reported as\n" " `CodecOptionUnsupported` so callers see the mismatch instead of\n" " the codec silently doing the same thing for every level.\n" ). -spec compress_levelless( bitstring(), packkit@codec:codec(), binary(), fun((bitstring()) -> {ok, bitstring()} | {error, packkit@error:codec_error()}) ) -> {ok, bitstring()} | {error, packkit@error:codec_error()}. compress_levelless(Bytes, Codec_value, Codec_name, Run) -> gleam@result:'try'( reject_dictionary(Codec_value), fun(_) -> gleam@result:'try'( reject_level(Codec_value, Codec_name), fun(_) -> Run(Bytes) end ) end ). -file("src/packkit.gleam", 345). -spec default_level_value() -> integer(). default_level_value() -> packkit@level:value(packkit@level:default()). -file("src/packkit.gleam", 327). ?DOC( " Accepts the implicit default level, rejects anything else with\n" " `CodecOptionUnsupported`. Used by codecs whose encoders share a\n" " single fixed strategy, so non-default levels would be silently\n" " dropped if accepted.\n" ). -spec reject_non_default_level(packkit@codec:codec(), binary()) -> {ok, nil} | {error, packkit@error:codec_error()}. reject_non_default_level(Codec_value, Codec_name) -> case packkit@codec:level(Codec_value) of none -> {ok, nil}; {some, L} -> case packkit@level:value(L) =:= default_level_value() of true -> {ok, nil}; false -> {error, {codec_option_unsupported, <<"level"/utf8>>, Codec_name}} end end. -file("src/packkit.gleam", 112). ?DOC( " Decompress `bytes` with `codec`, threading the supplied `Limits`\n" " value through to the underlying codec's `decode_with_limits`\n" " entrypoint. Codecs without an explicit limits hook receive their\n" " own family-specific defaults; today every byte-to-byte codec we\n" " support honours `Limits`.\n" ). -spec decompress_with_limits( bitstring(), packkit@codec:codec(), packkit@limit:limits() ) -> {ok, bitstring()} | {error, packkit@error:codec_error()}. decompress_with_limits(Bytes, Codec_value, Limits) -> case packkit@codec:kind(Codec_value) of identity -> gleam@result:'try'( reject_dictionary(Codec_value), fun(_) -> gleam@result:'try'( reject_non_default_level( Codec_value, <<"identity"/utf8>> ), fun(_) -> _pipe = enforce_input_limit(Bytes, Limits), gleam@result:map(_pipe, fun(_) -> Bytes end) end ) end ); deflate -> gleam@result:'try'( reject_dictionary(Codec_value), fun(_) -> packkit@deflate:decode_with_limits(Bytes, Limits) end ); zlib -> decompress_zlib(Bytes, Codec_value, Limits); gzip -> gleam@result:'try'( reject_dictionary(Codec_value), fun(_) -> _pipe@1 = packkit@gzip:decode_with_limits(Bytes, Limits), gleam@result:map( _pipe@1, fun(Decoded) -> erlang:element(3, Decoded) end ) end ); lz4 -> gleam@result:'try'( reject_dictionary(Codec_value), fun(_) -> packkit@lz4:decode_with_limits(Bytes, Limits) end ); snappy -> gleam@result:'try'( reject_dictionary(Codec_value), fun(_) -> packkit@snappy:decode_with_limits(Bytes, Limits) end ); bzip2 -> gleam@result:'try'( reject_dictionary(Codec_value), fun(_) -> packkit@bzip2:decode_with_limits(Bytes, Limits) end ); lzw -> gleam@result:'try'( reject_dictionary(Codec_value), fun(_) -> packkit@lzw:decode_with_limits(Bytes, Limits) end ); xz -> gleam@result:'try'( reject_dictionary(Codec_value), fun(_) -> packkit@xz:decode_with_limits(Bytes, Limits) end ); zstd -> gleam@result:'try'( reject_dictionary(Codec_value), fun(_) -> packkit@zstd:decode_with_limits(Bytes, Limits) end ); brotli -> gleam@result:'try'( reject_dictionary(Codec_value), fun(_) -> packkit@brotli:decode_with_limits(Bytes, Limits) end ) end. -file("src/packkit.gleam", 96). ?DOC( " Decompress `bytes` with `codec` using the default limits. Honours\n" " the codec's optional preset dictionary (currently only zlib) and\n" " otherwise rejects dictionary use with a typed error.\n" ). -spec decompress(bitstring(), packkit@codec:codec()) -> {ok, bitstring()} | {error, packkit@error:codec_error()}. decompress(Bytes, Codec_value) -> decompress_with_limits(Bytes, Codec_value, packkit@limit:default()). -file("src/packkit.gleam", 200). -spec compress_zlib(bitstring(), packkit@codec:codec()) -> {ok, bitstring()} | {error, packkit@error:codec_error()}. compress_zlib(Bytes, Codec_value) -> gleam@result:'try'( reject_non_default_level(Codec_value, <<"zlib"/utf8>>), fun(_) -> case packkit@codec:dictionary_of(Codec_value) of none -> packkit@zlib:encode(Bytes); {some, Dict} -> packkit@zlib:encode_with_dictionary( Bytes, packkit@codec:dictionary_bytes(Dict) ) end end ). -file("src/packkit.gleam", 235). -spec compress_gzip(bitstring(), packkit@codec:codec()) -> {ok, bitstring()} | {error, packkit@error:codec_error()}. compress_gzip(Bytes, Codec_value) -> gleam@result:'try'( reject_dictionary(Codec_value), fun(_) -> gleam@result:'try'( reject_non_default_level(Codec_value, <<"gzip"/utf8>>), fun(_) -> packkit@gzip:encode(Bytes) end ) end ). -file("src/packkit.gleam", 283). ?DOC( " Codecs whose encoders accept a level conceptually but currently\n" " always emit the simplest representation (xz LZMA2 uncompressed,\n" " zstd raw frames, brotli uncompressed metablocks). We accept the\n" " implicit default level (so the smart constructor still works) but\n" " reject any caller-supplied non-default level so it's never\n" " silently dropped. Dictionaries are still rejected.\n" ). -spec compress_fixed_level( bitstring(), packkit@codec:codec(), binary(), fun((bitstring()) -> {ok, bitstring()} | {error, packkit@error:codec_error()}) ) -> {ok, bitstring()} | {error, packkit@error:codec_error()}. compress_fixed_level(Bytes, Codec_value, Codec_name, Run) -> gleam@result:'try'( reject_dictionary(Codec_value), fun(_) -> gleam@result:'try'( reject_non_default_level(Codec_value, Codec_name), fun(_) -> Run(Bytes) end ) end ). -file("src/packkit.gleam", 349). -spec effective_level(packkit@codec:codec()) -> gleam@option:option(integer()). effective_level(Codec_value) -> case packkit@codec:level(Codec_value) of {some, L} -> {some, packkit@level:value(L)}; none -> none end. -file("src/packkit.gleam", 177). -spec compress_deflate(bitstring(), packkit@codec:codec()) -> {ok, bitstring()} | {error, packkit@error:codec_error()}. compress_deflate(Bytes, Codec_value) -> gleam@result:'try'( reject_dictionary(Codec_value), fun(_) -> case effective_level(Codec_value) of none -> packkit@deflate:encode(Bytes); {some, 0} -> packkit@deflate:encode_stored_only(Bytes); {some, N} -> case N =:= default_level_value() of true -> packkit@deflate:encode(Bytes); false -> {error, {codec_option_unsupported, <<"level"/utf8>>, <<"deflate"/utf8>>}} end end end ). -file("src/packkit.gleam", 356). -spec int_clamp(integer(), integer(), integer()) -> integer(). int_clamp(Value, Low, High) -> case {Value < Low, Value > High} of {true, _} -> Low; {_, true} -> High; {_, _} -> Value end. -file("src/packkit.gleam", 246). -spec compress_bzip2(bitstring(), packkit@codec:codec()) -> {ok, bitstring()} | {error, packkit@error:codec_error()}. compress_bzip2(Bytes, Codec_value) -> gleam@result:'try'( reject_dictionary(Codec_value), fun(_) -> Level_value = case effective_level(Codec_value) of {some, 0} -> 1; {some, N} -> int_clamp(N, 1, 9); none -> 9 end, packkit@bzip2:encode_with_level(Bytes, Level_value) end ). -file("src/packkit.gleam", 68). ?DOC( " Compress `bytes` with `codec`. The codec's optional level and\n" " preset dictionary are honoured where the family supports them; if\n" " the family cannot honour an option a typed `CodecOptionUnsupported`\n" " error is returned instead of silently dropping the request.\n" ). -spec compress(bitstring(), packkit@codec:codec()) -> {ok, bitstring()} | {error, packkit@error:codec_error()}. compress(Bytes, Codec_value) -> case packkit@codec:kind(Codec_value) of identity -> gleam@result:'try'( reject_dictionary(Codec_value), fun(_) -> gleam@result:'try'( reject_non_default_level( Codec_value, <<"identity"/utf8>> ), fun(_) -> {ok, Bytes} end ) end ); deflate -> compress_deflate(Bytes, Codec_value); zlib -> compress_zlib(Bytes, Codec_value); gzip -> compress_gzip(Bytes, Codec_value); lz4 -> compress_levelless( Bytes, Codec_value, <<"lz4"/utf8>>, fun packkit@lz4:encode/1 ); snappy -> compress_levelless( Bytes, Codec_value, <<"snappy"/utf8>>, fun packkit@snappy:encode/1 ); bzip2 -> compress_bzip2(Bytes, Codec_value); lzw -> compress_levelless( Bytes, Codec_value, <<"lzw"/utf8>>, fun packkit@lzw:encode/1 ); xz -> compress_fixed_level( Bytes, Codec_value, <<"xz"/utf8>>, fun packkit@xz:encode/1 ); zstd -> compress_fixed_level( Bytes, Codec_value, <<"zstd"/utf8>>, fun packkit@zstd:encode/1 ); brotli -> compress_fixed_level( Bytes, Codec_value, <<"brotli"/utf8>>, fun packkit@brotli:encode/1 ) end. -file("src/packkit.gleam", 377). ?DOC( " Read an archive while threading the supplied `Limits` through to\n" " the underlying archive decoder. Each family enforces the subset of\n" " limits that applies to it (input size, member count, name length,\n" " entry depth).\n" ). -spec read_with_limits( bitstring(), packkit@archive:archive_format(), packkit@limit:limits() ) -> {ok, packkit@archive:archive()} | {error, packkit@error:archive_error()}. read_with_limits(Bytes, Format, Limits) -> case packkit@archive:kind(Format) of tar -> packkit@tar:decode_with_limits(Bytes, Limits); zip -> packkit@zip:decode_with_limits(Bytes, Limits); cpio_newc -> packkit@cpio:decode_with_limits(Bytes, Limits); ar -> packkit@ar:decode_with_limits(Bytes, Limits); seven_z -> packkit@seven_z:decode_with_limits(Bytes, Limits) end. -file("src/packkit.gleam", 366). ?DOC( " Read an archive from `bytes` interpreted as `format` using the\n" " default resource limits.\n" ). -spec read(bitstring(), packkit@archive:archive_format()) -> {ok, packkit@archive:archive()} | {error, packkit@error:archive_error()}. read(Bytes, Format) -> read_with_limits(Bytes, Format, packkit@limit:default()). -file("src/packkit.gleam", 410). -spec ensure_archive_format_matches( packkit@archive:archive(), packkit@archive:archive_format() ) -> {ok, nil} | {error, packkit@error:archive_error()}. ensure_archive_format_matches(Archive_value, Requested) -> Archive_kind = packkit@archive:kind(packkit@archive:format(Archive_value)), Requested_kind = packkit@archive:kind(Requested), case Archive_kind =:= Requested_kind of true -> {ok, nil}; false -> {error, {archive_format_mismatch, packkit@archive:name(packkit@archive:format(Archive_value)), packkit@archive:name(Requested)}} end. -file("src/packkit.gleam", 396). ?DOC( " Serialise an archive to bytes using `format`. The supplied\n" " `format` must match the format tag the `Archive` was constructed\n" " with — `Archive` is bound to one format at construction time, and\n" " pretending it is a different format would silently corrupt the\n" " output. Mismatches surface as `ArchiveFormatMismatch`.\n" ). -spec write(packkit@archive:archive(), packkit@archive:archive_format()) -> {ok, bitstring()} | {error, packkit@error:archive_error()}. write(Archive_value, Format) -> gleam@result:'try'( ensure_archive_format_matches(Archive_value, Format), fun(_) -> case packkit@archive:kind(Format) of tar -> packkit@tar:encode(Archive_value); zip -> packkit@zip:encode(Archive_value); cpio_newc -> packkit@cpio:encode(Archive_value); ar -> packkit@ar:encode(Archive_value); seven_z -> packkit@seven_z:encode(Archive_value) end end ). -file("src/packkit.gleam", 474). ?DOC(" Detect from a filename or path suffix.\n"). -spec detect_filename(binary()) -> {ok, packkit@detect:detected()} | {error, packkit@error:detect_error()}. detect_filename(Path) -> packkit@detect:from_filename(Path). -file("src/packkit.gleam", 479). ?DOC(" Detect from byte signatures.\n"). -spec detect_bytes(bitstring()) -> {ok, packkit@detect:detected()} | {error, packkit@error:detect_error()}. detect_bytes(Bytes) -> packkit@detect:from_bytes(Bytes). -file("src/packkit.gleam", 487). ?DOC( " Detect via filename first, then fall back to magic-byte detection\n" " on the supplied content. Re-exports\n" " `packkit/detect.from_path_or_bytes` from the top-level facade so\n" " most CLI integrations only need to import `packkit`.\n" ). -spec detect_path_or_bytes(binary(), bitstring()) -> {ok, packkit@detect:detected()} | {error, packkit@error:detect_error()}. detect_path_or_bytes(Path, Bytes) -> packkit@detect:from_path_or_bytes(Path, Bytes). -file("src/packkit.gleam", 494). -spec apply_codec_chain_forward(bitstring(), list(packkit@codec:codec())) -> {ok, bitstring()} | {error, packkit@error:codec_error()}. apply_codec_chain_forward(Bytes, Codecs) -> case Codecs of [] -> {ok, Bytes}; [Head | Rest] -> gleam@result:'try'( compress(Bytes, Head), fun(Compressed) -> apply_codec_chain_forward(Compressed, Rest) end ) end. -file("src/packkit.gleam", 507). -spec apply_codec_chain_reverse( bitstring(), list(packkit@codec:codec()), packkit@limit:limits() ) -> {ok, bitstring()} | {error, packkit@error:codec_error()}. apply_codec_chain_reverse(Bytes, Codecs, Limits) -> case Codecs of [] -> {ok, Bytes}; [Head | Rest] -> gleam@result:'try'( decompress_with_limits(Bytes, Head, Limits), fun(Plain) -> apply_codec_chain_reverse(Plain, Rest, Limits) end ) end. -file("src/packkit.gleam", 525). -spec codec_to_archive_error( {ok, WIG} | {error, packkit@error:codec_error()}, binary() ) -> {ok, WIG} | {error, packkit@error:archive_error()}. codec_to_archive_error(Value, Step) -> case Value of {ok, V} -> {ok, V}; {error, Err} -> {error, {archive_codec_failed, Step, Err}} end. -file("src/packkit.gleam", 427). ?DOC(" Pack an archive with the codec chain described by `recipe`.\n"). -spec pack(packkit@archive:archive(), packkit@recipe:recipe()) -> {ok, bitstring()} | {error, packkit@error:archive_error()}. pack(Archive_value, Recipe_value) -> gleam@result:'try'( write(Archive_value, packkit@recipe:archive_format(Recipe_value)), fun(Archive_bytes) -> _pipe = apply_codec_chain_forward( Archive_bytes, packkit@recipe:codecs(Recipe_value) ), codec_to_archive_error(_pipe, <<"encode"/utf8>>) end ). -file("src/packkit.gleam", 452). ?DOC( " Unpack a byte stream produced by `recipe`, threading the supplied\n" " `Limits` through both the codec chain and the underlying archive\n" " decoder.\n" ). -spec unpack_with_limits( bitstring(), packkit@recipe:recipe(), packkit@limit:limits() ) -> {ok, packkit@archive:archive()} | {error, packkit@error:archive_error()}. unpack_with_limits(Bytes, Recipe_value, Limits) -> gleam@result:'try'( begin _pipe = apply_codec_chain_reverse( Bytes, lists:reverse(packkit@recipe:codecs(Recipe_value)), Limits ), codec_to_archive_error(_pipe, <<"decode"/utf8>>) end, fun(Raw_bytes) -> read_with_limits( Raw_bytes, packkit@recipe:archive_format(Recipe_value), Limits ) end ). -file("src/packkit.gleam", 442). ?DOC( " Unpack a byte stream produced by `recipe` using the default\n" " resource limits.\n" ). -spec unpack(bitstring(), packkit@recipe:recipe()) -> {ok, packkit@archive:archive()} | {error, packkit@error:archive_error()}. unpack(Bytes, Recipe_value) -> unpack_with_limits(Bytes, Recipe_value, packkit@limit:default()).