Current section
Files
Jump to
Current section
Files
src/apiculture@key.erl
-module(apiculture@key).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/apiculture/key.gleam").
-export([new/0, new_as_config/0, is_ready/1, generate/1, new_default/0, value/1, new_as_string/0, default_format/0, format_with_prefix/2, format_without_prefix/1, format_with_separator/2, format_with_encoding/2, format_with_checksum/2, format_without_checksum_name/1, format_without_checksum/1, format_with_checksum_bytes/2, format_with_content_bytes/2, with_random_bytes/2, with_random_chars/2, with_alphabet/2, with_encoding/2, with_prefix/2, with_separator/2, with_checksum/2, with_checksum_bytes/2, without_checksum/1, disable_prefix/1, disable_checksum_name/1, from_bytes/2, bytes_from_uuid/1, from_uuid_with/2, from_uuid/1, from_uuid_with_config/2, bytes_from_ulid/1, from_ulid_with/2, from_ulid/1, from_ulid_with_config/2, parse_with_format/2, parse/1, bytes/1, prefix_value/1, separator_value/1, has_prefix/1, has_checksum/1, content_value/1, content_bytes/1, content_byte_count/1, content_char_count/1, checksum_name/1, checksum_value/1, checksum_bytes/1, checksum_byte_count/1, checksum_char_count/1, sections/1, verify_checksum/2, verify_default_checksum/1]).
-export_type([key_config/0, key/0, key_sections/0, key_format/0, key_sections_parts/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(
" Key generation, formatting, parsing, and inspection.\n"
"\n"
" This is the implementation module behind the top-level `apiculture` API.\n"
" It keeps generation plans (`KeyConfig`), finalized values (`Key`), and\n"
" parse descriptions (`KeyFormat`) as separate types so each pipeline stage\n"
" has an explicit meaning.\n"
).
-type key_config() :: {key_config,
gleam@option:option(integer()),
gleam@option:option(integer()),
gleam@option:option(apiculture@alphabet:alphabet()),
gleam@option:option(apiculture@encoding:encoding()),
gleam@option:option(binary()),
gleam@option:option(binary()),
gleam@option:option(apiculture@checksum:checksum()),
gleam@option:option(binary()),
gleam@option:option(integer())}.
-type key() :: {key,
binary(),
bitstring(),
gleam@option:option(binary()),
gleam@option:option(binary()),
binary(),
gleam@option:option(binary()),
gleam@option:option(binary()),
gleam@option:option(bitstring())}.
-type key_sections() :: {key_sections,
gleam@option:option(binary()),
gleam@option:option(binary()),
binary(),
bitstring(),
gleam@option:option(binary()),
gleam@option:option(binary()),
gleam@option:option(bitstring())}.
-type key_format() :: {key_format,
gleam@option:option(binary()),
binary(),
apiculture@encoding:encoding(),
gleam@option:option(apiculture@checksum:checksum()),
gleam@option:option(binary()),
gleam@option:option(integer()),
gleam@option:option(integer())}.
-type key_sections_parts() :: {key_sections_parts,
binary(),
gleam@option:option(binary()),
gleam@option:option(binary()),
gleam@option:option(binary()),
gleam@option:option(binary()),
gleam@option:option(bitstring())}.
-file("src/apiculture/key.gleam", 85).
?DOC(" Returns an empty configuration for building a custom key plan.\n").
-spec new() -> key_config().
new() ->
{key_config, none, none, none, none, none, none, none, none, none}.
-file("src/apiculture/key.gleam", 100).
?DOC(" Returns a ready configuration containing the v0.3.0 defaults.\n").
-spec new_as_config() -> key_config().
new_as_config() ->
{key_config,
{some, 16},
none,
none,
{some, apiculture@encoding:base62()},
{some, <<"sk"/utf8>>},
{some, <<"_"/utf8>>},
{some, apiculture@checksum:crc32_checksum()},
{some, <<"crc32"/utf8>>},
{some, 4}}.
-file("src/apiculture/key.gleam", 821).
-spec hex_digit(integer()) -> binary().
hex_digit(Nibble) ->
case Nibble of
0 ->
<<"0"/utf8>>;
1 ->
<<"1"/utf8>>;
2 ->
<<"2"/utf8>>;
3 ->
<<"3"/utf8>>;
4 ->
<<"4"/utf8>>;
5 ->
<<"5"/utf8>>;
6 ->
<<"6"/utf8>>;
7 ->
<<"7"/utf8>>;
8 ->
<<"8"/utf8>>;
9 ->
<<"9"/utf8>>;
10 ->
<<"a"/utf8>>;
11 ->
<<"b"/utf8>>;
12 ->
<<"c"/utf8>>;
13 ->
<<"d"/utf8>>;
14 ->
<<"e"/utf8>>;
15 ->
<<"f"/utf8>>;
_ ->
<<""/utf8>>
end.
-file("src/apiculture/key.gleam", 815).
-spec int_to_hex(integer()) -> binary().
int_to_hex(Byte) ->
Nibble_high = Byte div 16,
Nibble_low = Byte rem 16,
<<(hex_digit(Nibble_high))/binary, (hex_digit(Nibble_low))/binary>>.
-file("src/apiculture/key.gleam", 804).
-spec do_bytes_to_hex(bitstring(), list(binary())) -> list(binary()).
do_bytes_to_hex(Bytes, Acc) ->
case Bytes of
<<>> ->
Acc;
<<Byte, Rest/bitstring>> ->
Hex = int_to_hex(Byte),
do_bytes_to_hex(Rest, [Hex | Acc]);
_ ->
Acc
end.
-file("src/apiculture/key.gleam", 797).
-spec bytes_to_hex(bitstring()) -> binary().
bytes_to_hex(Bytes) ->
_pipe = Bytes,
_pipe@1 = do_bytes_to_hex(_pipe, []),
_pipe@2 = lists:reverse(_pipe@1),
erlang:list_to_binary(_pipe@2).
-file("src/apiculture/key.gleam", 631).
-spec encode_checksum(bitstring(), key_config()) -> binary().
encode_checksum(Crc_bytes, Config) ->
case erlang:element(5, Config) of
{some, Enc} ->
apiculture@encoding:encode(Enc, Crc_bytes);
none ->
bytes_to_hex(Crc_bytes)
end.
-file("src/apiculture/key.gleam", 615).
-spec drop_first_bytes(bitstring(), integer()) -> bitstring().
drop_first_bytes(Bytes, N) ->
case N of
0 ->
Bytes;
_ ->
case Bytes of
<<_, Rest/binary>> ->
drop_first_bytes(Rest, N - 1);
_ ->
<<>>
end
end.
-file("src/apiculture/key.gleam", 608).
-spec truncate_checksum(bitstring(), gleam@option:option(integer())) -> bitstring().
truncate_checksum(Bytes, Byte_count) ->
case Byte_count of
{some, Count} ->
drop_first_bytes(Bytes, erlang:byte_size(Bytes) - Count);
none ->
Bytes
end.
-file("src/apiculture/key.gleam", 563).
-spec key_sections_parts(binary(), bitstring(), key_config()) -> key_sections_parts().
key_sections_parts(Content, Bytes, Config) ->
Prefixed = case erlang:element(6, Config) of
{some, Prefix} ->
Sep = begin
_pipe = erlang:element(7, Config),
gleam@option:unwrap(_pipe, <<""/utf8>>)
end,
<<<<Prefix/binary, Sep/binary>>/binary, Content/binary>>;
none ->
Content
end,
case erlang:element(8, Config) of
{some, Chk} ->
Checksum_bytes = begin
_pipe@1 = (erlang:element(2, Chk))(Bytes),
truncate_checksum(_pipe@1, erlang:element(10, Config))
end,
Checksum_value = encode_checksum(Checksum_bytes, Config),
Separator = begin
_pipe@2 = erlang:element(7, Config),
gleam@option:unwrap(_pipe@2, <<"_"/utf8>>)
end,
Named_checksum = case erlang:element(9, Config) of
{some, Name} ->
<<<<<<Separator/binary, Name/binary>>/binary,
Separator/binary>>/binary,
Checksum_value/binary>>;
none ->
<<Separator/binary, Checksum_value/binary>>
end,
{key_sections_parts,
<<Prefixed/binary, Named_checksum/binary>>,
erlang:element(6, Config),
erlang:element(7, Config),
erlang:element(9, Config),
{some, Checksum_value},
{some, Checksum_bytes}};
none ->
{key_sections_parts,
Prefixed,
erlang:element(6, Config),
erlang:element(7, Config),
none,
none,
none}
end.
-file("src/apiculture/key.gleam", 534).
-spec build_key_with_content(binary(), bitstring(), key_config()) -> key().
build_key_with_content(Content, Bytes, Config) ->
Sections = key_sections_parts(Content, Bytes, Config),
{key,
erlang:element(2, Sections),
Bytes,
erlang:element(3, Sections),
erlang:element(4, Sections),
Content,
erlang:element(5, Sections),
erlang:element(6, Sections),
erlang:element(7, Sections)}.
-file("src/apiculture/key.gleam", 522).
-spec encode_bytes_with_config(bitstring(), key_config()) -> binary().
encode_bytes_with_config(Bytes, Config) ->
case erlang:element(5, Config) of
{some, Enc} ->
apiculture@encoding:encode(Enc, Bytes);
none ->
bytes_to_hex(Bytes)
end.
-file("src/apiculture/key.gleam", 529).
-spec build_key(bitstring(), key_config()) -> key().
build_key(Bytes, Config) ->
Content = encode_bytes_with_config(Bytes, Config),
build_key_with_content(Content, Bytes, Config).
-file("src/apiculture/key.gleam", 479).
-spec generate_from_bytes(key_config()) -> {ok, key()} |
{error, apiculture@error:error()}.
generate_from_bytes(Config) ->
case erlang:element(2, Config) of
{some, Byte_count} ->
case apiculture@random:random_bytes(Byte_count) of
{ok, Bytes} ->
{ok, build_key(Bytes, Config)};
{error, E} ->
{error, E}
end;
none ->
{error, invalid_byte_count}
end.
-file("src/apiculture/key.gleam", 507).
-spec generate_from_encoding(key_config()) -> {ok, key()} |
{error, apiculture@error:error()}.
generate_from_encoding(Config) ->
case {erlang:element(2, Config), erlang:element(5, Config)} of
{{some, Byte_count}, {some, Encoding}} ->
case apiculture@random:random_bytes(Byte_count) of
{ok, Bytes} ->
Encoded = apiculture@encoding:encode(Encoding, Bytes),
{ok, build_key_with_content(Encoded, Bytes, Config)};
{error, E} ->
{error, E}
end;
{_, _} ->
{error, invalid_byte_count}
end.
-file("src/apiculture/key.gleam", 789).
-spec get_nth(integer(), list(binary())) -> binary().
get_nth(N, Items) ->
case {N, Items} of
{0, [First | _]} ->
First;
{_, [_ | Rest]} ->
get_nth(N - 1, Rest);
{_, []} ->
<<""/utf8>>
end.
-file("src/apiculture/key.gleam", 777).
-spec chars_from_indices(list(integer()), apiculture@alphabet:alphabet()) -> binary().
chars_from_indices(Indices, Alphabet) ->
Char_list = apiculture@alphabet:characters(Alphabet),
_pipe = Indices,
_pipe@1 = gleam@list:map(
_pipe,
fun(Index) ->
case (Index >= 0) andalso (Index < erlang:length(Char_list)) of
true ->
get_nth(Index, Char_list);
false ->
<<""/utf8>>
end
end
),
erlang:list_to_binary(_pipe@1).
-file("src/apiculture/key.gleam", 491).
-spec generate_from_alphabet(key_config()) -> {ok, key()} |
{error, apiculture@error:error()}.
generate_from_alphabet(Config) ->
case {erlang:element(3, Config), erlang:element(4, Config)} of
{{some, Char_count}, {some, Alphabet}} ->
case apiculture@random:random_chars(Alphabet, Char_count) of
{ok, Indices} ->
Chars = chars_from_indices(Indices, Alphabet),
Bytes = gleam_stdlib:identity(Chars),
{ok, build_key_with_content(Chars, Bytes, Config)};
{error, E} ->
{error, E}
end;
{_, _} ->
{error, invalid_byte_count}
end.
-file("src/apiculture/key.gleam", 270).
?DOC(" Reports whether a configuration selects one valid content source mode.\n").
-spec is_ready(key_config()) -> boolean().
is_ready(Config) ->
case {erlang:element(2, Config),
erlang:element(3, Config),
erlang:element(4, Config),
erlang:element(5, Config)} of
{none, {some, _}, {some, _}, none} ->
true;
{{some, _}, none, none, {some, _}} ->
true;
{{some, _}, none, none, none} ->
true;
{_, _, _, _} ->
false
end.
-file("src/apiculture/key.gleam", 280).
?DOC(" Finalizes a configuration by generating its selected content.\n").
-spec generate(key_config()) -> {ok, key()} | {error, apiculture@error:error()}.
generate(Config) ->
case is_ready(Config) of
true ->
case {erlang:element(2, Config),
erlang:element(3, Config),
erlang:element(4, Config),
erlang:element(5, Config)} of
{none, {some, _}, {some, _}, none} ->
generate_from_alphabet(Config);
{{some, _}, none, none, {some, _}} ->
generate_from_encoding(Config);
{{some, _}, none, none, none} ->
generate_from_bytes(Config);
{_, _, _, _} ->
{error, invalid_byte_count}
end;
false ->
{error, invalid_byte_count}
end.
-file("src/apiculture/key.gleam", 115).
?DOC(" Generates one finalized key using the v0.3.0 defaults.\n").
-spec new_default() -> {ok, key()} | {error, apiculture@error:error()}.
new_default() ->
generate(new_as_config()).
-file("src/apiculture/key.gleam", 844).
?DOC(" Returns the string value of the key.\n").
-spec value(key()) -> binary().
value(Key) ->
erlang:element(2, Key).
-file("src/apiculture/key.gleam", 120).
?DOC(" Generates and serializes one key using the v0.3.0 defaults.\n").
-spec new_as_string() -> {ok, binary()} | {error, apiculture@error:error()}.
new_as_string() ->
case new_default() of
{ok, Key} ->
{ok, value(Key)};
{error, Error} ->
{error, Error}
end.
-file("src/apiculture/key.gleam", 128).
?DOC(" Returns the strict parser format for the v0.3.0 default layout.\n").
-spec default_format() -> key_format().
default_format() ->
{key_format,
{some, <<"sk"/utf8>>},
<<"_"/utf8>>,
apiculture@encoding:base62(),
{some, apiculture@checksum:crc32_checksum()},
{some, <<"crc32"/utf8>>},
{some, 4},
{some, 16}}.
-file("src/apiculture/key.gleam", 141).
?DOC(" Returns a parser format with the expected prefix changed.\n").
-spec format_with_prefix(key_format(), binary()) -> key_format().
format_with_prefix(Format, Prefix) ->
{key_format,
{some, Prefix},
erlang:element(3, Format),
erlang:element(4, Format),
erlang:element(5, Format),
erlang:element(6, Format),
erlang:element(7, Format),
erlang:element(8, Format)}.
-file("src/apiculture/key.gleam", 146).
?DOC(" Returns a parser format that does not expect a prefix.\n").
-spec format_without_prefix(key_format()) -> key_format().
format_without_prefix(Format) ->
{key_format,
none,
erlang:element(3, Format),
erlang:element(4, Format),
erlang:element(5, Format),
erlang:element(6, Format),
erlang:element(7, Format),
erlang:element(8, Format)}.
-file("src/apiculture/key.gleam", 151).
?DOC(" Returns a parser format with a different structural separator.\n").
-spec format_with_separator(key_format(), binary()) -> key_format().
format_with_separator(Format, Separator) ->
{key_format,
erlang:element(2, Format),
Separator,
erlang:element(4, Format),
erlang:element(5, Format),
erlang:element(6, Format),
erlang:element(7, Format),
erlang:element(8, Format)}.
-file("src/apiculture/key.gleam", 159).
?DOC(" Returns a parser format with a different content encoding.\n").
-spec format_with_encoding(key_format(), apiculture@encoding:encoding()) -> key_format().
format_with_encoding(Format, Encoding) ->
{key_format,
erlang:element(2, Format),
erlang:element(3, Format),
Encoding,
erlang:element(5, Format),
erlang:element(6, Format),
erlang:element(7, Format),
erlang:element(8, Format)}.
-file("src/apiculture/key.gleam", 167).
?DOC(" Returns a parser format expecting the supplied checksum algorithm and name.\n").
-spec format_with_checksum(key_format(), apiculture@checksum:checksum()) -> key_format().
format_with_checksum(Format, Checksum) ->
{key_format,
erlang:element(2, Format),
erlang:element(3, Format),
erlang:element(4, Format),
{some, Checksum},
{some, string:lowercase(erlang:element(3, Checksum))},
erlang:element(7, Format),
erlang:element(8, Format)}.
-file("src/apiculture/key.gleam", 179).
?DOC(" Returns a parser format that does not expect a checksum algorithm name.\n").
-spec format_without_checksum_name(key_format()) -> key_format().
format_without_checksum_name(Format) ->
{key_format,
erlang:element(2, Format),
erlang:element(3, Format),
erlang:element(4, Format),
erlang:element(5, Format),
none,
erlang:element(7, Format),
erlang:element(8, Format)}.
-file("src/apiculture/key.gleam", 184).
?DOC(" Returns a parser format that does not expect a checksum.\n").
-spec format_without_checksum(key_format()) -> key_format().
format_without_checksum(Format) ->
{key_format,
erlang:element(2, Format),
erlang:element(3, Format),
erlang:element(4, Format),
none,
none,
none,
erlang:element(8, Format)}.
-file("src/apiculture/key.gleam", 189).
?DOC(" Returns a parser format expecting the supplied checksum byte count.\n").
-spec format_with_checksum_bytes(key_format(), integer()) -> key_format().
format_with_checksum_bytes(Format, Count) ->
{key_format,
erlang:element(2, Format),
erlang:element(3, Format),
erlang:element(4, Format),
erlang:element(5, Format),
erlang:element(6, Format),
{some, Count},
erlang:element(8, Format)}.
-file("src/apiculture/key.gleam", 194).
?DOC(" Returns a parser format expecting the supplied content byte count.\n").
-spec format_with_content_bytes(key_format(), integer()) -> key_format().
format_with_content_bytes(Format, Count) ->
{key_format,
erlang:element(2, Format),
erlang:element(3, Format),
erlang:element(4, Format),
erlang:element(5, Format),
erlang:element(6, Format),
erlang:element(7, Format),
{some, Count}}.
-file("src/apiculture/key.gleam", 201).
?DOC(
" Selects secure random byte generation with the given byte count.\n"
"\n"
" This clears direct alphabet sampling settings.\n"
).
-spec with_random_bytes(key_config(), integer()) -> key_config().
with_random_bytes(Config, Count) ->
{key_config,
{some, Count},
none,
none,
erlang:element(5, Config),
erlang:element(6, Config),
erlang:element(7, Config),
erlang:element(8, Config),
erlang:element(9, Config),
erlang:element(10, Config)}.
-file("src/apiculture/key.gleam", 208).
?DOC(
" Selects direct random character sampling with the given character count.\n"
"\n"
" Pair this with `with_alphabet`. This clears byte encoding settings.\n"
).
-spec with_random_chars(key_config(), integer()) -> key_config().
with_random_chars(Config, Count) ->
{key_config,
none,
{some, Count},
erlang:element(4, Config),
none,
erlang:element(6, Config),
erlang:element(7, Config),
erlang:element(8, Config),
erlang:element(9, Config),
erlang:element(10, Config)}.
-file("src/apiculture/key.gleam", 213).
?DOC(" Sets the alphabet used by direct character sampling.\n").
-spec with_alphabet(key_config(), apiculture@alphabet:alphabet()) -> key_config().
with_alphabet(Config, Alphabet) ->
{key_config,
erlang:element(2, Config),
erlang:element(3, Config),
{some, Alphabet},
erlang:element(5, Config),
erlang:element(6, Config),
erlang:element(7, Config),
erlang:element(8, Config),
erlang:element(9, Config),
erlang:element(10, Config)}.
-file("src/apiculture/key.gleam", 218).
?DOC(" Sets the encoding used for generated or imported bytes.\n").
-spec with_encoding(key_config(), apiculture@encoding:encoding()) -> key_config().
with_encoding(Config, Encoding) ->
{key_config,
erlang:element(2, Config),
none,
none,
{some, Encoding},
erlang:element(6, Config),
erlang:element(7, Config),
erlang:element(8, Config),
erlang:element(9, Config),
erlang:element(10, Config)}.
-file("src/apiculture/key.gleam", 228).
?DOC(" Sets the serialized prefix for a key.\n").
-spec with_prefix(key_config(), binary()) -> key_config().
with_prefix(Config, Prefix) ->
{key_config,
erlang:element(2, Config),
erlang:element(3, Config),
erlang:element(4, Config),
erlang:element(5, Config),
{some, Prefix},
erlang:element(7, Config),
erlang:element(8, Config),
erlang:element(9, Config),
erlang:element(10, Config)}.
-file("src/apiculture/key.gleam", 233).
?DOC(" Sets the separator used at every structural boundary.\n").
-spec with_separator(key_config(), binary()) -> key_config().
with_separator(Config, Separator) ->
{key_config,
erlang:element(2, Config),
erlang:element(3, Config),
erlang:element(4, Config),
erlang:element(5, Config),
erlang:element(6, Config),
{some, Separator},
erlang:element(8, Config),
erlang:element(9, Config),
erlang:element(10, Config)}.
-file("src/apiculture/key.gleam", 238).
?DOC(" Sets the checksum algorithm and its serialized lowercase name.\n").
-spec with_checksum(key_config(), apiculture@checksum:checksum()) -> key_config().
with_checksum(Config, Checksum) ->
{key_config,
erlang:element(2, Config),
erlang:element(3, Config),
erlang:element(4, Config),
erlang:element(5, Config),
erlang:element(6, Config),
erlang:element(7, Config),
{some, Checksum},
{some, string:lowercase(erlang:element(3, Checksum))},
erlang:element(10, Config)}.
-file("src/apiculture/key.gleam", 250).
?DOC(" Sets how many checksum bytes are retained in the serialized key.\n").
-spec with_checksum_bytes(key_config(), integer()) -> key_config().
with_checksum_bytes(Config, Count) ->
{key_config,
erlang:element(2, Config),
erlang:element(3, Config),
erlang:element(4, Config),
erlang:element(5, Config),
erlang:element(6, Config),
erlang:element(7, Config),
erlang:element(8, Config),
erlang:element(9, Config),
{some, Count}}.
-file("src/apiculture/key.gleam", 255).
?DOC(" Removes the checksum and its serialized name from a configuration.\n").
-spec without_checksum(key_config()) -> key_config().
without_checksum(Config) ->
{key_config,
erlang:element(2, Config),
erlang:element(3, Config),
erlang:element(4, Config),
erlang:element(5, Config),
erlang:element(6, Config),
erlang:element(7, Config),
none,
none,
none}.
-file("src/apiculture/key.gleam", 260).
?DOC(" Removes the prefix from a configuration.\n").
-spec disable_prefix(key_config()) -> key_config().
disable_prefix(Config) ->
{key_config,
erlang:element(2, Config),
erlang:element(3, Config),
erlang:element(4, Config),
erlang:element(5, Config),
none,
erlang:element(7, Config),
erlang:element(8, Config),
erlang:element(9, Config),
erlang:element(10, Config)}.
-file("src/apiculture/key.gleam", 265).
?DOC(" Removes only the checksum name while keeping the checksum enabled.\n").
-spec disable_checksum_name(key_config()) -> key_config().
disable_checksum_name(Config) ->
{key_config,
erlang:element(2, Config),
erlang:element(3, Config),
erlang:element(4, Config),
erlang:element(5, Config),
erlang:element(6, Config),
erlang:element(7, Config),
erlang:element(8, Config),
none,
erlang:element(10, Config)}.
-file("src/apiculture/key.gleam", 300).
?DOC(" Formats existing bytes according to a configuration.\n").
-spec from_bytes(key_config(), bitstring()) -> {ok, key()} |
{error, apiculture@error:error()}.
from_bytes(Config, Bytes) ->
{ok, build_key(Bytes, Config)}.
-file("src/apiculture/key.gleam", 627).
-spec default_import_config() -> key_config().
default_import_config() ->
new_as_config().
-file("src/apiculture/key.gleam", 638).
-spec parse_uuid_bytes(binary()) -> {ok, bitstring()} |
{error, apiculture@error:error()}.
parse_uuid_bytes(Input) ->
Normalized = begin
_pipe = Input,
_pipe@1 = string:lowercase(_pipe),
_pipe@2 = gleam@string:replace(
_pipe@1,
<<"urn:uuid:"/utf8>>,
<<""/utf8>>
),
gleam@string:replace(_pipe@2, <<"-"/utf8>>, <<""/utf8>>)
end,
case string:length(Normalized) =:= 32 of
false ->
{error, malformed_input};
true ->
case apiculture@encoding:decode(
apiculture@encoding:hex_lower(),
Normalized
) of
{ok, Bytes} ->
case erlang:byte_size(Bytes) =:= 16 of
true ->
{ok, Bytes};
false ->
{error, malformed_input}
end;
_ ->
{error, malformed_input}
end
end.
-file("src/apiculture/key.gleam", 347).
?DOC(" Parses a UUID into canonical 16-byte content.\n").
-spec bytes_from_uuid(binary()) -> {ok, bitstring()} |
{error, apiculture@error:error()}.
bytes_from_uuid(Input) ->
parse_uuid_bytes(Input).
-file("src/apiculture/key.gleam", 318).
?DOC(" Compatibility alias for `from_uuid_with_config`.\n").
-spec from_uuid_with(key_config(), binary()) -> {ok, key()} |
{error, apiculture@error:error()}.
from_uuid_with(Config, Input) ->
case bytes_from_uuid(Input) of
{ok, Bytes} ->
from_bytes(Config, Bytes);
{error, E} ->
{error, E}
end.
-file("src/apiculture/key.gleam", 305).
?DOC(" Parses and formats a UUID using the default configuration.\n").
-spec from_uuid(binary()) -> {ok, key()} | {error, apiculture@error:error()}.
from_uuid(Input) ->
from_uuid_with(default_import_config(), Input).
-file("src/apiculture/key.gleam", 310).
?DOC(" Parses and formats a UUID using a supplied configuration.\n").
-spec from_uuid_with_config(key_config(), binary()) -> {ok, key()} |
{error, apiculture@error:error()}.
from_uuid_with_config(Config, Input) ->
from_uuid_with(Config, Input).
-file("src/apiculture/key.gleam", 763).
-spec low_bits_mask(integer()) -> integer().
low_bits_mask(Bit_count) ->
case Bit_count of
0 ->
0;
_ ->
erlang:'bsl'(1, Bit_count) - 1
end.
-file("src/apiculture/key.gleam", 725).
-spec ulid_char_value(binary()) -> {ok, integer()} |
{error, apiculture@error:error()}.
ulid_char_value(Char) ->
case Char of
<<"0"/utf8>> ->
{ok, 0};
<<"O"/utf8>> ->
{ok, 0};
<<"1"/utf8>> ->
{ok, 1};
<<"I"/utf8>> ->
{ok, 1};
<<"L"/utf8>> ->
{ok, 1};
<<"2"/utf8>> ->
{ok, 2};
<<"3"/utf8>> ->
{ok, 3};
<<"4"/utf8>> ->
{ok, 4};
<<"5"/utf8>> ->
{ok, 5};
<<"6"/utf8>> ->
{ok, 6};
<<"7"/utf8>> ->
{ok, 7};
<<"8"/utf8>> ->
{ok, 8};
<<"9"/utf8>> ->
{ok, 9};
<<"A"/utf8>> ->
{ok, 10};
<<"B"/utf8>> ->
{ok, 11};
<<"C"/utf8>> ->
{ok, 12};
<<"D"/utf8>> ->
{ok, 13};
<<"E"/utf8>> ->
{ok, 14};
<<"F"/utf8>> ->
{ok, 15};
<<"G"/utf8>> ->
{ok, 16};
<<"H"/utf8>> ->
{ok, 17};
<<"J"/utf8>> ->
{ok, 18};
<<"K"/utf8>> ->
{ok, 19};
<<"M"/utf8>> ->
{ok, 20};
<<"N"/utf8>> ->
{ok, 21};
<<"P"/utf8>> ->
{ok, 22};
<<"Q"/utf8>> ->
{ok, 23};
<<"R"/utf8>> ->
{ok, 24};
<<"S"/utf8>> ->
{ok, 25};
<<"T"/utf8>> ->
{ok, 26};
<<"V"/utf8>> ->
{ok, 27};
<<"W"/utf8>> ->
{ok, 28};
<<"X"/utf8>> ->
{ok, 29};
<<"Y"/utf8>> ->
{ok, 30};
<<"Z"/utf8>> ->
{ok, 31};
_ ->
{error, malformed_input}
end.
-file("src/apiculture/key.gleam", 770).
-spec ints_to_bytes(list(integer())) -> bitstring().
ints_to_bytes(Ints) ->
case Ints of
[] ->
<<>>;
[First | Rest] ->
gleam@bit_array:append(<<First>>, ints_to_bytes(Rest))
end.
-file("src/apiculture/key.gleam", 684).
-spec decode_ulid_chars(list(binary()), integer(), integer(), list(integer())) -> {ok,
bitstring()} |
{error, apiculture@error:error()}.
decode_ulid_chars(Chars, Acc, Bit_count, Out) ->
case Chars of
[] ->
case ((erlang:length(Out) =:= 16) andalso (Bit_count =:= 0)) andalso (Acc
=:= 0) of
true ->
{ok, ints_to_bytes(lists:reverse(Out))};
false ->
{error, malformed_input}
end;
[Char | Rest] ->
case ulid_char_value(Char) of
{ok, Value} ->
Next_acc = (Acc * 32) + Value,
Next_bit_count = Bit_count + 5,
case Next_bit_count >= 8 of
true ->
Remaining_bits = Next_bit_count - 8,
Byte = begin
_pipe = Next_acc,
_pipe@1 = erlang:'bsr'(_pipe, Remaining_bits),
erlang:'band'(_pipe@1, 255)
end,
Remaining = erlang:'band'(
Next_acc,
low_bits_mask(Remaining_bits)
),
decode_ulid_chars(
Rest,
Remaining,
Remaining_bits,
[Byte | Out]
);
false ->
decode_ulid_chars(
Rest,
Next_acc,
Next_bit_count,
Out
)
end;
{error, E} ->
{error, E}
end
end.
-file("src/apiculture/key.gleam", 659).
-spec parse_ulid_bytes(binary()) -> {ok, bitstring()} |
{error, apiculture@error:error()}.
parse_ulid_bytes(Input) ->
Chars = begin
_pipe = Input,
_pipe@1 = string:uppercase(_pipe),
gleam@string:to_graphemes(_pipe@1)
end,
case erlang:length(Chars) =:= 26 of
false ->
{error, malformed_input};
true ->
case Chars of
[First | Rest] ->
case ulid_char_value(First) of
{ok, Value} ->
case Value =< 7 of
true ->
decode_ulid_chars(Rest, Value, 3, []);
false ->
{error, malformed_input}
end;
_ ->
{error, malformed_input}
end;
[] ->
{error, malformed_input}
end
end.
-file("src/apiculture/key.gleam", 352).
?DOC(" Parses a ULID into canonical 16-byte content.\n").
-spec bytes_from_ulid(binary()) -> {ok, bitstring()} |
{error, apiculture@error:error()}.
bytes_from_ulid(Input) ->
parse_ulid_bytes(Input).
-file("src/apiculture/key.gleam", 339).
?DOC(" Compatibility alias for `from_ulid_with_config`.\n").
-spec from_ulid_with(key_config(), binary()) -> {ok, key()} |
{error, apiculture@error:error()}.
from_ulid_with(Config, Input) ->
case bytes_from_ulid(Input) of
{ok, Bytes} ->
from_bytes(Config, Bytes);
{error, E} ->
{error, E}
end.
-file("src/apiculture/key.gleam", 326).
?DOC(" Parses and formats a ULID using the default configuration.\n").
-spec from_ulid(binary()) -> {ok, key()} | {error, apiculture@error:error()}.
from_ulid(Input) ->
from_ulid_with(default_import_config(), Input).
-file("src/apiculture/key.gleam", 331).
?DOC(" Parses and formats a ULID using a supplied configuration.\n").
-spec from_ulid_with_config(key_config(), binary()) -> {ok, key()} |
{error, apiculture@error:error()}.
from_ulid_with_config(Config, Input) ->
from_ulid_with(Config, Input).
-file("src/apiculture/key.gleam", 465).
-spec config_from_format(key_format()) -> key_config().
config_from_format(Format) ->
{key_config,
none,
none,
none,
{some, erlang:element(4, Format)},
erlang:element(2, Format),
{some, erlang:element(3, Format)},
erlang:element(5, Format),
erlang:element(6, Format),
erlang:element(7, Format)}.
-file("src/apiculture/key.gleam", 434).
-spec parse_checksum(bitstring(), gleam@option:option(binary()), key_format()) -> {ok,
key()} |
{error, apiculture@error:error()}.
parse_checksum(Bytes, Checksum_value, Format) ->
case {erlang:element(5, Format), Checksum_value} of
{none, none} ->
{ok, build_key(Bytes, config_from_format(Format))};
{{some, Checksum}, {some, Value}} ->
case apiculture@encoding:decode(erlang:element(4, Format), Value) of
{error, _} ->
{error, malformed_input};
{ok, Actual} ->
Expected = begin
_pipe = (erlang:element(2, Checksum))(Bytes),
truncate_checksum(_pipe, erlang:element(7, Format))
end,
case (erlang:byte_size(Actual) =:= erlang:byte_size(
Expected
))
andalso (apiculture@encoding:encode(
erlang:element(4, Format),
Actual
)
=:= Value) of
false ->
{error, malformed_input};
true ->
case Actual =:= Expected of
true ->
{ok,
build_key(
Bytes,
config_from_format(Format)
)};
false ->
{error, checksum_mismatch}
end
end
end;
{_, _} ->
{error, malformed_input}
end.
-file("src/apiculture/key.gleam", 427).
-spec valid_content_length(bitstring(), key_format()) -> boolean().
valid_content_length(Bytes, Format) ->
case erlang:element(8, Format) of
{some, Count} ->
erlang:byte_size(Bytes) =:= Count;
none ->
true
end.
-file("src/apiculture/key.gleam", 408).
-spec parse_content(binary(), gleam@option:option(binary()), key_format()) -> {ok,
key()} |
{error, apiculture@error:error()}.
parse_content(Content, Checksum_value, Format) ->
case apiculture@encoding:decode(erlang:element(4, Format), Content) of
{error, _} ->
{error, malformed_input};
{ok, Bytes} ->
case (apiculture@encoding:encode(erlang:element(4, Format), Bytes)
=:= Content)
andalso valid_content_length(Bytes, Format) of
false ->
{error, malformed_input};
true ->
parse_checksum(Bytes, Checksum_value, Format)
end
end.
-file("src/apiculture/key.gleam", 373).
-spec parse_sections(list(binary()), key_format()) -> {ok,
{binary(), gleam@option:option(binary())}} |
{error, apiculture@error:error()}.
parse_sections(Sections, Format) ->
case {erlang:element(2, Format),
erlang:element(5, Format),
erlang:element(6, Format),
Sections} of
{{some, Prefix},
{some, _},
{some, Name},
[Found_prefix, Content, Found_name, Checksum]} ->
case (Found_prefix =:= Prefix) andalso (Found_name =:= Name) of
true ->
{ok, {Content, {some, Checksum}}};
false ->
{error, malformed_input}
end;
{none, {some, _}, {some, Name@1}, [Content@1, Found_name@1, Checksum@1]} ->
case Found_name@1 =:= Name@1 of
true ->
{ok, {Content@1, {some, Checksum@1}}};
false ->
{error, malformed_input}
end;
{{some, Prefix@1},
{some, _},
none,
[Found_prefix@1, Content@2, Checksum@2]} ->
case Found_prefix@1 =:= Prefix@1 of
true ->
{ok, {Content@2, {some, Checksum@2}}};
false ->
{error, malformed_input}
end;
{none, {some, _}, none, [Content@3, Checksum@3]} ->
{ok, {Content@3, {some, Checksum@3}}};
{{some, Prefix@2}, none, _, [Found_prefix@2, Content@4]} ->
case Found_prefix@2 =:= Prefix@2 of
true ->
{ok, {Content@4, none}};
false ->
{error, malformed_input}
end;
{none, none, _, [Content@5]} ->
{ok, {Content@5, none}};
{_, _, _, _} ->
{error, malformed_input}
end.
-file("src/apiculture/key.gleam", 362).
?DOC(" Parses and verifies a serialized key using an explicit format.\n").
-spec parse_with_format(binary(), key_format()) -> {ok, key()} |
{error, apiculture@error:error()}.
parse_with_format(Input, Format) ->
case parse_sections(
gleam@string:split(Input, erlang:element(3, Format)),
Format
) of
{ok, {Content, Checksum_value}} ->
parse_content(Content, Checksum_value, Format);
{error, Error} ->
{error, Error}
end.
-file("src/apiculture/key.gleam", 357).
?DOC(" Parses and verifies the strict default serialized key format.\n").
-spec parse(binary()) -> {ok, key()} | {error, apiculture@error:error()}.
parse(Input) ->
parse_with_format(Input, default_format()).
-file("src/apiculture/key.gleam", 850).
?DOC(
" Returns the raw bytes that were used to generate the key.\n"
" Returns the raw content bytes of a finalized key.\n"
).
-spec bytes(key()) -> bitstring().
bytes(Key) ->
erlang:element(3, Key).
-file("src/apiculture/key.gleam", 855).
?DOC(" Returns the optional serialized prefix.\n").
-spec prefix_value(key()) -> gleam@option:option(binary()).
prefix_value(Key) ->
erlang:element(4, Key).
-file("src/apiculture/key.gleam", 860).
?DOC(" Returns the optional structural separator.\n").
-spec separator_value(key()) -> gleam@option:option(binary()).
separator_value(Key) ->
erlang:element(5, Key).
-file("src/apiculture/key.gleam", 865).
?DOC(" Reports whether a key has a prefix.\n").
-spec has_prefix(key()) -> boolean().
has_prefix(Key) ->
gleam@option:is_some(erlang:element(4, Key)).
-file("src/apiculture/key.gleam", 870).
?DOC(" Reports whether a key has a checksum.\n").
-spec has_checksum(key()) -> boolean().
has_checksum(Key) ->
gleam@option:is_some(erlang:element(9, Key)).
-file("src/apiculture/key.gleam", 875).
?DOC(" Returns the encoded content section without surrounding metadata.\n").
-spec content_value(key()) -> binary().
content_value(Key) ->
erlang:element(6, Key).
-file("src/apiculture/key.gleam", 880).
?DOC(" Returns the raw bytes represented by the content section.\n").
-spec content_bytes(key()) -> bitstring().
content_bytes(Key) ->
erlang:element(3, Key).
-file("src/apiculture/key.gleam", 885).
?DOC(" Returns the number of raw content bytes.\n").
-spec content_byte_count(key()) -> integer().
content_byte_count(Key) ->
erlang:byte_size(erlang:element(3, Key)).
-file("src/apiculture/key.gleam", 890).
?DOC(" Returns the number of characters in the encoded content section.\n").
-spec content_char_count(key()) -> integer().
content_char_count(Key) ->
string:length(erlang:element(6, Key)).
-file("src/apiculture/key.gleam", 895).
?DOC(" Returns the optional checksum algorithm name.\n").
-spec checksum_name(key()) -> gleam@option:option(binary()).
checksum_name(Key) ->
erlang:element(7, Key).
-file("src/apiculture/key.gleam", 900).
?DOC(" Returns the optional encoded checksum section.\n").
-spec checksum_value(key()) -> gleam@option:option(binary()).
checksum_value(Key) ->
erlang:element(8, Key).
-file("src/apiculture/key.gleam", 905).
?DOC(" Returns the optional raw checksum bytes.\n").
-spec checksum_bytes(key()) -> gleam@option:option(bitstring()).
checksum_bytes(Key) ->
erlang:element(9, Key).
-file("src/apiculture/key.gleam", 910).
?DOC(" Returns the checksum byte count, or `0` when absent.\n").
-spec checksum_byte_count(key()) -> integer().
checksum_byte_count(Key) ->
case erlang:element(9, Key) of
{some, Bytes} ->
erlang:byte_size(Bytes);
none ->
0
end.
-file("src/apiculture/key.gleam", 918).
?DOC(" Returns the encoded checksum character count, when present.\n").
-spec checksum_char_count(key()) -> gleam@option:option(integer()).
checksum_char_count(Key) ->
case erlang:element(8, Key) of
{some, Value} ->
{some, string:length(Value)};
none ->
none
end.
-file("src/apiculture/key.gleam", 926).
?DOC(" Returns all key sections grouped in one value.\n").
-spec sections(key()) -> key_sections().
sections(Key) ->
{key_sections,
erlang:element(4, Key),
erlang:element(5, Key),
erlang:element(6, Key),
erlang:element(3, Key),
erlang:element(7, Key),
erlang:element(8, Key),
erlang:element(9, Key)}.
-file("src/apiculture/key.gleam", 939).
?DOC(" Verifies the stored checksum with an explicit algorithm.\n").
-spec verify_checksum(key(), apiculture@checksum:checksum()) -> boolean().
verify_checksum(Key, Checksum) ->
case erlang:element(9, Key) of
{some, Expected} ->
begin
_pipe = (erlang:element(2, Checksum))(erlang:element(3, Key)),
truncate_checksum(_pipe, {some, erlang:byte_size(Expected)})
end
=:= Expected;
none ->
false
end.
-file("src/apiculture/key.gleam", 951).
?DOC(" Verifies the stored checksum using CRC32.\n").
-spec verify_default_checksum(key()) -> boolean().
verify_default_checksum(Key) ->
verify_checksum(Key, apiculture@checksum:crc32_checksum()).