Current section
Files
Jump to
Current section
Files
src/gleamlz_string.erl
-module(gleamlz_string).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([decompress_from_uint8/1, decompress_from_base64/1, decompress_from_encoded_uri/1, compress_to_uint8/1, compress_to_base64/1, compress_to_encoded_uri/1]).
-export_type([decompress_error/0, decode_type/0]).
-type decompress_error() :: e_invalid_input.
-type decode_type() :: {char,
{bitstring(), bitstring(), gleam@dict:dict(integer(), bitstring())}} |
{index, {integer(), bitstring()}} |
eof.
-spec decode_base64(
list(binary()),
gleam@dict:dict(binary(), integer()),
bitstring()
) -> {ok, bitstring()} | {error, decompress_error()}.
decode_base64(String_list, Key_dict, Bitstring) ->
case String_list of
[Char | Rest] ->
case gleam@dict:get(Key_dict, Char) of
{ok, Num} ->
decode_base64(
Rest,
Key_dict,
<<Bitstring/bitstring, <<Num:6>>/bitstring>>
);
_ ->
{error, e_invalid_input}
end;
[] ->
{ok, Bitstring}
end.
-spec to_utf16(bitstring(), binary()) -> {ok, binary()} |
{error, decompress_error()}.
to_utf16(Bitstring, String) ->
case Bitstring of
<<>> ->
{ok, String};
<<Bytes:16, Rest/bitstring>> ->
case Bytes of
Surrogate when (Surrogate >= 16#D800) andalso (Surrogate =< 16#DFFF) ->
case Surrogate of
High when (High >= 16#D800) andalso (High =< 16#DBFF) ->
case Rest of
<<Low:16, Rest@1/bitstring>> ->
Codepoint = (((High - 16#D800) * 16#400) + (Low
- 16#DC00))
+ 16#10000,
_assert_subject = gleam@string:utf_codepoint(
Codepoint
),
{ok, Codepoint@1} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(
#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"gleamlz_string"/utf8>>,
function => <<"to_utf16"/utf8>>,
line => 326}
)
end,
to_utf16(
Rest@1,
<<String/binary,
(gleam_stdlib:utf_codepoint_list_to_string(
[Codepoint@1]
))/binary>>
);
_ ->
{error, e_invalid_input}
end;
_ ->
{error, e_invalid_input}
end;
Other ->
_assert_subject@2 = case Other of
65534 ->
gleam@bit_array:to_string(<<239, 191, 190>>);
65535 ->
gleam@bit_array:to_string(<<239, 191, 191>>);
Any ->
_assert_subject@1 = gleam@string:utf_codepoint(Any),
{ok, Codepoint@2} = case _assert_subject@1 of
{ok, _} -> _assert_subject@1;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@1,
module => <<"gleamlz_string"/utf8>>,
function => <<"to_utf16"/utf8>>,
line => 347})
end,
{ok,
gleam_stdlib:utf_codepoint_list_to_string(
[Codepoint@2]
)}
end,
{ok, Str} = case _assert_subject@2 of
{ok, _} -> _assert_subject@2;
_assert_fail@2 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@2,
module => <<"gleamlz_string"/utf8>>,
function => <<"to_utf16"/utf8>>,
line => 339})
end,
to_utf16(Rest, <<String/binary, Str/binary>>)
end;
_ ->
{error, e_invalid_input}
end.
-spec find_bits(integer()) -> integer().
find_bits(Num) ->
_pipe = Num,
_pipe@1 = gleam@int:to_base2(_pipe),
gleam@string:length(_pipe@1).
-spec reverse(bitstring()) -> bitstring().
reverse(Bitstring) ->
case Bitstring of
<<>> ->
<<>>;
_ ->
<<Value:1/bitstring, Rest/bitstring>> = case Bitstring of
<<_:1/bitstring, _/bitstring>> -> Bitstring;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"gleamlz_string"/utf8>>,
function => <<"reverse"/utf8>>,
line => 374})
end,
gleam@bit_array:append(reverse(Rest), Value)
end.
-spec w_output(
binary(),
gleam@dict:dict(binary(), {integer(), boolean()}),
boolean()
) -> {gleam@dict:dict(binary(), {integer(), boolean()}), bitstring()}.
w_output(W, Dict, Char_just_added) ->
_assert_subject = gleam@dict:get(Dict, W),
{ok, Var} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"gleamlz_string"/utf8>>,
function => <<"w_output"/utf8>>,
line => 174})
end,
case Var of
{Index, true} ->
Dict@1 = gleam@dict:insert(Dict, W, {Index, false}),
Marker_size = find_bits(Index),
_assert_subject@1 = <<W/binary>>,
<<Char_codepoint/utf8, _/bitstring>> = case _assert_subject@1 of
<<_/utf8, _/bitstring>> -> _assert_subject@1;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@1,
module => <<"gleamlz_string"/utf8>>,
function => <<"w_output"/utf8>>,
line => 180})
end,
Char_val = gleam@string:utf_codepoint_to_int(Char_codepoint),
{Size_marker, Char_size} = (case find_bits(Char_val) of
Index@1 when Index@1 =< 8 ->
{0, 8};
_ ->
{1, 16}
end),
Size_marker_bits = reverse(
<<Size_marker:(lists:max([(Marker_size), 0]))>>
),
Char_bits = reverse(<<Char_val:(lists:max([(Char_size), 0]))>>),
{Dict@1, <<Size_marker_bits/bitstring, Char_bits/bitstring>>};
{Index@2, false} ->
Map_size = maps:size(Dict) + 2,
Map_size@1 = case Char_just_added of
true ->
Map_size - 1;
false ->
Map_size
end,
Size = find_bits(Map_size@1),
{Dict, reverse(<<Index@2:(lists:max([(Size), 0]))>>)}
end.
-spec compress_string(
binary(),
list(integer()),
gleam@dict:dict(binary(), {integer(), boolean()}),
bitstring()
) -> bitstring().
compress_string(W, Str, Dict, Final_str) ->
case Str of
[] ->
Size = find_bits(maps:size(Dict) + 2),
{_, Output} = w_output(W, Dict, false),
<<Final_str/bitstring,
Output/bitstring,
(reverse(<<2:(lists:max([(Size), 0]))>>))/bitstring>>;
[C | Rest] ->
Char_just_added = not gleam@dict:has_key(
Dict,
gleam_stdlib:utf_codepoint_list_to_string([C])
),
Dict@1 = case Char_just_added of
true ->
gleam@dict:insert(
Dict,
gleam_stdlib:utf_codepoint_list_to_string([C]),
{maps:size(Dict) + 3, true}
);
false ->
Dict
end,
Wc = <<W/binary,
(gleam_stdlib:utf_codepoint_list_to_string([C]))/binary>>,
case gleam@dict:has_key(Dict@1, Wc) of
true ->
compress_string(Wc, Rest, Dict@1, Final_str);
false ->
{Dict@2, Output@1} = w_output(W, Dict@1, Char_just_added),
Dict@3 = gleam@dict:insert(
Dict@2,
Wc,
{maps:size(Dict@2) + 3, false}
),
compress_string(
gleam_stdlib:utf_codepoint_list_to_string([C]),
Rest,
Dict@3,
<<Final_str/bitstring, Output@1/bitstring>>
)
end
end.
-spec decode_next_segment(bitstring(), gleam@dict:dict(integer(), bitstring())) -> {ok,
decode_type()} |
{error, decompress_error()}.
decode_next_segment(Bitstring, Dict) ->
Size = begin
_pipe = (maps:size(Dict) + 3),
find_bits(_pipe)
end,
case Bitstring of
<<Dict_entry:Size, Rest/bitstring>> ->
_assert_subject = reverse(<<Dict_entry:(lists:max([(Size), 0]))>>),
<<Dict_entry@1:Size>> = case _assert_subject of
<<_:Size>> -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"gleamlz_string"/utf8>>,
function => <<"decode_next_segment"/utf8>>,
line => 273})
end,
case Dict_entry@1 of
0 ->
case Rest of
<<C:8, Rest@1/bitstring>> ->
_assert_subject@1 = reverse(<<C:8>>),
<<C@1:8>> = case _assert_subject@1 of
<<_:8>> -> _assert_subject@1;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@1,
module => <<"gleamlz_string"/utf8>>,
function => <<"decode_next_segment"/utf8>>,
line => 278})
end,
_assert_subject@2 = gleam@string:utf_codepoint(C@1),
{ok, Codepoint} = case _assert_subject@2 of
{ok, _} -> _assert_subject@2;
_assert_fail@2 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@2,
module => <<"gleamlz_string"/utf8>>,
function => <<"decode_next_segment"/utf8>>,
line => 279})
end,
Char = <<Codepoint/utf16>>,
Dict@1 = gleam@dict:insert(
Dict,
maps:size(Dict) + 3,
Char
),
{ok, {char, {Char, Rest@1, Dict@1}}};
_ ->
{error, e_invalid_input}
end;
1 ->
case Rest of
<<C@2:16, Rest@2/bitstring>> ->
_assert_subject@3 = reverse(<<C@2:16>>),
<<C@3:16>> = case _assert_subject@3 of
<<_:16>> -> _assert_subject@3;
_assert_fail@3 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@3,
module => <<"gleamlz_string"/utf8>>,
function => <<"decode_next_segment"/utf8>>,
line => 290})
end,
Char@1 = <<C@3:16>>,
Dict@2 = gleam@dict:insert(
Dict,
maps:size(Dict) + 3,
Char@1
),
{ok, {char, {Char@1, Rest@2, Dict@2}}};
_ ->
{error, e_invalid_input}
end;
2 ->
{ok, eof};
Index ->
{ok, {index, {Index, Rest}}}
end;
_ ->
{error, e_invalid_input}
end.
-spec decompress_string(
bitstring(),
bitstring(),
gleam@dict:dict(integer(), bitstring()),
bitstring()
) -> {ok, bitstring()} | {error, decompress_error()}.
decompress_string(W, Str, Dict, Final_str) ->
gleam@result:'try'(
decode_next_segment(Str, Dict),
fun(Return) -> case Return of
{char, Char} ->
Dict@1 = gleam@dict:insert(
erlang:element(3, Char),
maps:size(erlang:element(3, Char)) + 3,
gleam@bit_array:append(W, erlang:element(1, Char))
),
decompress_string(
erlang:element(1, Char),
erlang:element(2, Char),
Dict@1,
<<Final_str/bitstring, W/bitstring>>
);
{index, Seq} ->
C = case gleam@dict:get(Dict, erlang:element(1, Seq)) of
{ok, Value} ->
{ok, Value};
{error, nil} ->
case (maps:size(Dict) + 3) =:= erlang:element(
1,
Seq
) of
true ->
{ok,
gleam@bit_array:append(
W,
<<W:16/bitstring>>
)};
false ->
{error, e_invalid_input}
end
end,
gleam@result:'try'(
C,
fun(C@1) ->
Dict@2 = gleam@dict:insert(
Dict,
maps:size(Dict) + 3,
gleam@bit_array:append(W, <<C@1:16/bitstring>>)
),
decompress_string(
C@1,
erlang:element(2, Seq),
Dict@2,
<<Final_str/bitstring, W/bitstring>>
)
end
);
eof ->
{ok, <<Final_str/bitstring, W/bitstring>>}
end end
).
-spec decompress(bitstring()) -> {ok, binary()} | {error, decompress_error()}.
decompress(Bstring) ->
case Bstring of
<<>> ->
{ok, <<""/utf8>>};
_ ->
gleam@result:'try'(
decode_next_segment(Bstring, gleam@dict:new()),
fun(Return) -> case Return of
{char, Char} ->
gleam@result:'try'(
decompress_string(
erlang:element(1, Char),
erlang:element(2, Char),
erlang:element(3, Char),
<<>>
),
fun(String) -> to_utf16(String, <<""/utf8>>) end
);
_ ->
{error, e_invalid_input}
end end
)
end.
-spec decompress_from_uint8(bitstring()) -> {ok, binary()} |
{error, decompress_error()}.
decompress_from_uint8(Bits) ->
decompress(Bits).
-spec decompress_from_base64(binary()) -> {ok, binary()} |
{error, decompress_error()}.
decompress_from_base64(Base64_string) ->
_pipe = <<"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="/utf8>>,
_pipe@1 = gleam@string:to_graphemes(_pipe),
_pipe@2 = gleam@list:index_map(_pipe@1, fun(X, I) -> {X, I} end),
_pipe@3 = maps:from_list(_pipe@2),
_pipe@4 = decode_base64(
gleam@string:to_graphemes(Base64_string),
_pipe@3,
<<>>
),
gleam@result:'try'(_pipe@4, fun decompress/1).
-spec decompress_from_encoded_uri(binary()) -> {ok, binary()} |
{error, decompress_error()}.
decompress_from_encoded_uri(Uri_string) ->
_pipe = Uri_string,
_pipe@1 = gleam@string:replace(_pipe, <<"-"/utf8>>, <<"/"/utf8>>),
_pipe@2 = gleam@string:replace(_pipe@1, <<"$"/utf8>>, <<"="/utf8>>),
decompress_from_base64(_pipe@2).
-spec bit_size(bitstring(), integer()) -> integer().
bit_size(Bits, Size) ->
case Bits of
<<_:1/bitstring, Rest/bitstring>> ->
bit_size(Rest, Size + 1);
_ ->
Size
end.
-spec compress(binary()) -> bitstring().
compress(String) ->
case String of
<<""/utf8>> ->
<<""/utf8>>;
_ ->
Bitstring = begin
_pipe = gleam@string:to_utf_codepoints(String),
compress_string(<<""/utf8>>, _pipe, gleam@dict:new(), <<>>)
end,
Padding_bits = 16 - (begin
_pipe@1 = Bitstring,
bit_size(_pipe@1, 0)
end
rem 16),
<<Bitstring/bitstring, 0:(lists:max([(Padding_bits), 0]))>>
end.
-spec compress_to_uint8(binary()) -> bitstring().
compress_to_uint8(String) ->
compress(String).
-spec compress_to_base64(binary()) -> binary().
compress_to_base64(String) ->
_pipe = String,
_pipe@1 = compress(_pipe),
gleam_stdlib:bit_array_base64_encode(_pipe@1, true).
-spec compress_to_encoded_uri(binary()) -> binary().
compress_to_encoded_uri(String) ->
_pipe = String,
_pipe@1 = compress_to_base64(_pipe),
_pipe@2 = gleam@string:replace(_pipe@1, <<"/"/utf8>>, <<"-"/utf8>>),
gleam@string:replace(_pipe@2, <<"="/utf8>>, <<"$"/utf8>>).