Skip to main content

src/packkit@limit.erl

-module(packkit@limit).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/packkit/limit.gleam").
-export([default/0, max_input_bytes/1, max_output_bytes/1, max_members/1, max_entry_name_bytes/1, max_entry_depth/1, max_window_bits/1, with_max_window_bits/2, with_max_input_bytes/2, with_max_output_bytes/2, with_max_members/2, with_max_entry_depth/2, with_max_entry_name_bytes/2, with_max_input_bytes_checked/2, with_max_output_bytes_checked/2, with_max_members_checked/2, with_max_entry_depth_checked/2, with_max_entry_name_bytes_checked/2, new_checked/6, new/6, with_max_window_bits_checked/2]).
-export_type([limits/0, limit_error/0]).

-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.

-opaque limits() :: {limits,
        integer(),
        integer(),
        integer(),
        integer(),
        integer(),
        integer()}.

-type limit_error() :: {limit_must_be_positive, binary(), integer()} |
    {window_bits_out_of_range, integer()}.

-file("src/packkit/limit.gleam", 23).
?DOC(" Conservative cross-target defaults for early development.\n").
-spec default() -> limits().
default() ->
    {limits, 64000000, 256000000, 10000, 4096, 32, 15}.

-file("src/packkit/limit.gleam", 95).
?DOC(" Read `max_input_bytes`.\n").
-spec max_input_bytes(limits()) -> integer().
max_input_bytes(Limits) ->
    erlang:element(2, Limits).

-file("src/packkit/limit.gleam", 100).
?DOC(" Read `max_output_bytes`.\n").
-spec max_output_bytes(limits()) -> integer().
max_output_bytes(Limits) ->
    erlang:element(3, Limits).

-file("src/packkit/limit.gleam", 105).
?DOC(" Read `max_members`.\n").
-spec max_members(limits()) -> integer().
max_members(Limits) ->
    erlang:element(4, Limits).

-file("src/packkit/limit.gleam", 110).
?DOC(" Read `max_entry_name_bytes`.\n").
-spec max_entry_name_bytes(limits()) -> integer().
max_entry_name_bytes(Limits) ->
    erlang:element(5, Limits).

-file("src/packkit/limit.gleam", 115).
?DOC(" Read `max_entry_depth`.\n").
-spec max_entry_depth(limits()) -> integer().
max_entry_depth(Limits) ->
    erlang:element(6, Limits).

-file("src/packkit/limit.gleam", 120).
?DOC(" Read `max_window_bits`.\n").
-spec max_window_bits(limits()) -> integer().
max_window_bits(Limits) ->
    erlang:element(7, Limits).

-file("src/packkit/limit.gleam", 209).
?DOC(
    " Unchecked setter for `max_window_bits`.  Out-of-range values are\n"
    " clamped to the valid 8..30 window.\n"
).
-spec with_max_window_bits(limits(), integer()) -> limits().
with_max_window_bits(Limits, Bits) ->
    Clamped = case Bits of
        N when N < 8 ->
            8;

        N@1 when N@1 > 30 ->
            30;

        N@2 ->
            N@2
    end,
    {limits,
        erlang:element(2, Limits),
        erlang:element(3, Limits),
        erlang:element(4, Limits),
        erlang:element(5, Limits),
        erlang:element(6, Limits),
        Clamped}.

-file("src/packkit/limit.gleam", 218).
-spec clamp_positive(integer()) -> integer().
clamp_positive(Value) ->
    case Value of
        N when N < 1 ->
            1;

        N@1 ->
            N@1
    end.

-file("src/packkit/limit.gleam", 181).
?DOC(
    " Unchecked setter for `max_input_bytes`.  The caller is responsible\n"
    " for passing a positive value; non-positive values are clamped to 1\n"
    " to keep downstream decoders well-behaved.\n"
).
-spec with_max_input_bytes(limits(), integer()) -> limits().
with_max_input_bytes(Limits, Bytes) ->
    {limits,
        clamp_positive(Bytes),
        erlang:element(3, Limits),
        erlang:element(4, Limits),
        erlang:element(5, Limits),
        erlang:element(6, Limits),
        erlang:element(7, Limits)}.

-file("src/packkit/limit.gleam", 187).
?DOC(
    " Unchecked setter for `max_output_bytes`.  See [with_max_input_bytes]\n"
    " for the contract.\n"
).
-spec with_max_output_bytes(limits(), integer()) -> limits().
with_max_output_bytes(Limits, Bytes) ->
    {limits,
        erlang:element(2, Limits),
        clamp_positive(Bytes),
        erlang:element(4, Limits),
        erlang:element(5, Limits),
        erlang:element(6, Limits),
        erlang:element(7, Limits)}.

-file("src/packkit/limit.gleam", 192).
?DOC(" Unchecked setter for `max_members`.\n").
-spec with_max_members(limits(), integer()) -> limits().
with_max_members(Limits, Count) ->
    {limits,
        erlang:element(2, Limits),
        erlang:element(3, Limits),
        clamp_positive(Count),
        erlang:element(5, Limits),
        erlang:element(6, Limits),
        erlang:element(7, Limits)}.

-file("src/packkit/limit.gleam", 197).
?DOC(" Unchecked setter for `max_entry_depth`.\n").
-spec with_max_entry_depth(limits(), integer()) -> limits().
with_max_entry_depth(Limits, Depth) ->
    {limits,
        erlang:element(2, Limits),
        erlang:element(3, Limits),
        erlang:element(4, Limits),
        erlang:element(5, Limits),
        clamp_positive(Depth),
        erlang:element(7, Limits)}.

-file("src/packkit/limit.gleam", 203).
?DOC(
    " Unchecked setter for `max_entry_name_bytes`.  See\n"
    " [with_max_input_bytes] for the contract.\n"
).
-spec with_max_entry_name_bytes(limits(), integer()) -> limits().
with_max_entry_name_bytes(Limits, Bytes) ->
    {limits,
        erlang:element(2, Limits),
        erlang:element(3, Limits),
        erlang:element(4, Limits),
        clamp_positive(Bytes),
        erlang:element(6, Limits),
        erlang:element(7, Limits)}.

-file("src/packkit/limit.gleam", 225).
-spec positive(binary(), integer()) -> {ok, nil} | {error, limit_error()}.
positive(Name, Value) ->
    gleam@bool:guard(
        Value =< 0,
        {error, {limit_must_be_positive, Name, Value}},
        fun() -> {ok, nil} end
    ).

-file("src/packkit/limit.gleam", 125).
?DOC(" Update `max_input_bytes` after validation.\n").
-spec with_max_input_bytes_checked(limits(), integer()) -> {ok, limits()} |
    {error, limit_error()}.
with_max_input_bytes_checked(Limits, Bytes) ->
    _pipe = positive(<<"max_input_bytes"/utf8>>, Bytes),
    gleam@result:map(
        _pipe,
        fun(_) ->
            {limits,
                Bytes,
                erlang:element(3, Limits),
                erlang:element(4, Limits),
                erlang:element(5, Limits),
                erlang:element(6, Limits),
                erlang:element(7, Limits)}
        end
    ).

-file("src/packkit/limit.gleam", 134).
?DOC(" Update `max_output_bytes` after validation.\n").
-spec with_max_output_bytes_checked(limits(), integer()) -> {ok, limits()} |
    {error, limit_error()}.
with_max_output_bytes_checked(Limits, Bytes) ->
    _pipe = positive(<<"max_output_bytes"/utf8>>, Bytes),
    gleam@result:map(
        _pipe,
        fun(_) ->
            {limits,
                erlang:element(2, Limits),
                Bytes,
                erlang:element(4, Limits),
                erlang:element(5, Limits),
                erlang:element(6, Limits),
                erlang:element(7, Limits)}
        end
    ).

-file("src/packkit/limit.gleam", 143).
?DOC(" Update `max_members` after validation.\n").
-spec with_max_members_checked(limits(), integer()) -> {ok, limits()} |
    {error, limit_error()}.
with_max_members_checked(Limits, Count) ->
    _pipe = positive(<<"max_members"/utf8>>, Count),
    gleam@result:map(
        _pipe,
        fun(_) ->
            {limits,
                erlang:element(2, Limits),
                erlang:element(3, Limits),
                Count,
                erlang:element(5, Limits),
                erlang:element(6, Limits),
                erlang:element(7, Limits)}
        end
    ).

-file("src/packkit/limit.gleam", 152).
?DOC(" Update `max_entry_depth` after validation.\n").
-spec with_max_entry_depth_checked(limits(), integer()) -> {ok, limits()} |
    {error, limit_error()}.
with_max_entry_depth_checked(Limits, Depth) ->
    _pipe = positive(<<"max_entry_depth"/utf8>>, Depth),
    gleam@result:map(
        _pipe,
        fun(_) ->
            {limits,
                erlang:element(2, Limits),
                erlang:element(3, Limits),
                erlang:element(4, Limits),
                erlang:element(5, Limits),
                Depth,
                erlang:element(7, Limits)}
        end
    ).

-file("src/packkit/limit.gleam", 161).
?DOC(" Update `max_entry_name_bytes` after validation.\n").
-spec with_max_entry_name_bytes_checked(limits(), integer()) -> {ok, limits()} |
    {error, limit_error()}.
with_max_entry_name_bytes_checked(Limits, Bytes) ->
    _pipe = positive(<<"max_entry_name_bytes"/utf8>>, Bytes),
    gleam@result:map(
        _pipe,
        fun(_) ->
            {limits,
                erlang:element(2, Limits),
                erlang:element(3, Limits),
                erlang:element(4, Limits),
                Bytes,
                erlang:element(6, Limits),
                erlang:element(7, Limits)}
        end
    ).

-file("src/packkit/limit.gleam", 233).
-spec validate_window_bits(integer()) -> {ok, nil} | {error, limit_error()}.
validate_window_bits(Bits) ->
    gleam@bool:guard(
        (Bits < 8) orelse (Bits > 30),
        {error, {window_bits_out_of_range, Bits}},
        fun() -> {ok, nil} end
    ).

-file("src/packkit/limit.gleam", 35).
?DOC(" Checked constructor for a full limits value.\n").
-spec new_checked(
    integer(),
    integer(),
    integer(),
    integer(),
    integer(),
    integer()
) -> {ok, limits()} | {error, limit_error()}.
new_checked(
    Max_input_bytes,
    Max_output_bytes,
    Max_members,
    Max_entry_name_bytes,
    Max_entry_depth,
    Max_window_bits
) ->
    _pipe = positive(<<"max_input_bytes"/utf8>>, Max_input_bytes),
    _pipe@1 = gleam@result:'try'(
        _pipe,
        fun(_) -> positive(<<"max_output_bytes"/utf8>>, Max_output_bytes) end
    ),
    _pipe@2 = gleam@result:'try'(
        _pipe@1,
        fun(_) -> positive(<<"max_members"/utf8>>, Max_members) end
    ),
    _pipe@3 = gleam@result:'try'(
        _pipe@2,
        fun(_) ->
            positive(<<"max_entry_name_bytes"/utf8>>, Max_entry_name_bytes)
        end
    ),
    _pipe@4 = gleam@result:'try'(
        _pipe@3,
        fun(_) -> positive(<<"max_entry_depth"/utf8>>, Max_entry_depth) end
    ),
    _pipe@5 = gleam@result:'try'(
        _pipe@4,
        fun(_) -> validate_window_bits(Max_window_bits) end
    ),
    gleam@result:map(
        _pipe@5,
        fun(_) ->
            {limits,
                Max_input_bytes,
                Max_output_bytes,
                Max_members,
                Max_entry_name_bytes,
                Max_entry_depth,
                Max_window_bits}
        end
    ).

-file("src/packkit/limit.gleam", 68).
?DOC(" Panicking counterpart of `new_checked`.\n").
-spec new(integer(), integer(), integer(), integer(), integer(), integer()) -> limits().
new(
    Max_input_bytes,
    Max_output_bytes,
    Max_members,
    Max_entry_name_bytes,
    Max_entry_depth,
    Max_window_bits
) ->
    case new_checked(
        Max_input_bytes,
        Max_output_bytes,
        Max_members,
        Max_entry_name_bytes,
        Max_entry_depth,
        Max_window_bits
    ) of
        {ok, Limits} ->
            Limits;

        {error, {limit_must_be_positive, Name, _}} ->
            erlang:error(#{gleam_error => panic,
                    message => (<<<<"packkit/limit.new: "/utf8, Name/binary>>/binary,
                        " must be > 0"/utf8>>),
                    file => <<?FILEPATH/utf8>>,
                    module => <<"packkit/limit"/utf8>>,
                    function => <<"new"/utf8>>,
                    line => 88});

        {error, {window_bits_out_of_range, _}} ->
            erlang:error(#{gleam_error => panic,
                    message => <<"packkit/limit.new: max_window_bits must be in the inclusive range 8..30"/utf8>>,
                    file => <<?FILEPATH/utf8>>,
                    module => <<"packkit/limit"/utf8>>,
                    function => <<"new"/utf8>>,
                    line => 90})
    end.

-file("src/packkit/limit.gleam", 170).
?DOC(" Update `max_window_bits` after validation.\n").
-spec with_max_window_bits_checked(limits(), integer()) -> {ok, limits()} |
    {error, limit_error()}.
with_max_window_bits_checked(Limits, Bits) ->
    _pipe = validate_window_bits(Bits),
    gleam@result:map(
        _pipe,
        fun(_) ->
            {limits,
                erlang:element(2, Limits),
                erlang:element(3, Limits),
                erlang:element(4, Limits),
                erlang:element(5, Limits),
                erlang:element(6, Limits),
                Bits}
        end
    ).