Skip to main content

src/internal@encoder@percent_encoding.erl

-module(internal@encoder@percent_encoding).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/internal/encoder/percent_encoding.gleam").
-export([estimate_encoded_size/2, encode_string/3]).

-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(
    " Percent Encodes strings according to RFC 3986.\n"
    "\n"
    " See the following links for reference:\n"
    " - <https://tools.ietf.org/html/rfc3986>\n"
).

-file("src/internal/encoder/percent_encoding.gleam", 82).
-spec should_encode_character(binary()) -> boolean().
should_encode_character(Character) ->
    ((((gleam@string:compare(Character, <<"0"/utf8>>) =:= lt) orelse (gleam@string:compare(
        Character,
        <<"9"/utf8>>
    )
    =:= gt))
    andalso ((gleam@string:compare(Character, <<"A"/utf8>>) =:= lt) orelse (gleam@string:compare(
        Character,
        <<"Z"/utf8>>
    )
    =:= gt)))
    andalso ((gleam@string:compare(Character, <<"a"/utf8>>) =:= lt) orelse (gleam@string:compare(
        Character,
        <<"z"/utf8>>
    )
    =:= gt)))
    andalso not gleam_stdlib:contains_string(<<"-_.~"/utf8>>, Character).

-file("src/internal/encoder/percent_encoding.gleam", 18).
?DOC(
    " Estimates the percent encoded size of a string in bytes, taking\n"
    " maximum size of a line into account.\n"
).
-spec estimate_encoded_size(binary(), integer()) -> {ok, integer()} |
    {error, internal@encoder@encoding:encoder_error()}.
estimate_encoded_size(String, Maximum_size) ->
    _pipe = String,
    _pipe@1 = gleam@string:split(_pipe, <<""/utf8>>),
    gleam@list:try_fold(
        _pipe@1,
        0,
        fun(Size, Character) ->
            Character_size = erlang:byte_size(Character),
            _pipe@2 = case should_encode_character(Character) of
                true ->
                    {ok, Size + (3 * Character_size)};

                false ->
                    {ok, Size + Character_size}
            end,
            gleam@result:'try'(
                _pipe@2,
                fun(Size@1) -> case Size@1 =< Maximum_size of
                        true ->
                            {ok, Size@1};

                        false ->
                            {error, {maximum_size_exceeded, Maximum_size}}
                    end end
            )
        end
    ).

-file("src/internal/encoder/percent_encoding.gleam", 106).
-spec do_encode_bytes(bitstring(), list(binary())) -> binary().
do_encode_bytes(Bytes, Acc) ->
    case Bytes of
        <<Byte:1/binary, Rest/binary>> ->
            do_encode_bytes(
                Rest,
                [<<"%"/utf8, (gleam_stdlib:base16_encode(Byte))/binary>> | Acc]
            );

        <<_/bitstring>> ->
            _pipe = Acc,
            _pipe@1 = lists:reverse(_pipe),
            gleam@string:join(_pipe@1, <<""/utf8>>)
    end.

-file("src/internal/encoder/percent_encoding.gleam", 98).
-spec encode_character(binary()) -> binary().
encode_character(Character) ->
    gleam@bool:guard(
        not should_encode_character(Character),
        Character,
        fun() -> do_encode_bytes(gleam_stdlib:identity(Character), []) end
    ).

-file("src/internal/encoder/percent_encoding.gleam", 53).
-spec do_encode_string(list(binary()), integer(), integer()) -> {ok,
        list(binary())} |
    {error, internal@encoder@encoding:encoder_error()}.
do_encode_string(Characters, Count, Maximum_size) ->
    _pipe = Characters,
    _pipe@1 = gleam@list:try_fold(
        _pipe,
        {Count, []},
        fun(Accumulator, Character) ->
            {Used_size, Lines} = Accumulator,
            Encoded_character = encode_character(Character),
            Encoded_character_size = erlang:byte_size(Encoded_character),
            case Lines of
                [] ->
                    {ok, {Encoded_character_size, [Encoded_character]}};

                [First_line | Other_lines] when (Used_size + Encoded_character_size) =< Maximum_size ->
                    {ok,
                        {Used_size + Encoded_character_size,
                            [<<First_line/binary, Encoded_character/binary>> |
                                Other_lines]}};

                _ ->
                    {error, {maximum_size_exceeded, Maximum_size}}
            end
        end
    ),
    gleam@result:map(_pipe@1, fun gleam@pair:second/1).

-file("src/internal/encoder/percent_encoding.gleam", 43).
?DOC(
    " Percent encode a string, taking the maximum line size into\n"
    " account and pretending to start the first line at the passed\n"
    " start position.\n"
).
-spec encode_string(binary(), integer(), integer()) -> {ok, list(binary())} |
    {error, internal@encoder@encoding:encoder_error()}.
encode_string(String, Position, Maximum_size) ->
    _pipe = String,
    _pipe@1 = gleam@string:split(_pipe, <<""/utf8>>),
    do_encode_string(_pipe@1, Position, Maximum_size).