-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; <> -> 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, <<<>/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} -> <<<<<>/binary, Separator/binary>>/binary, Checksum_value/binary>>; none -> <> end, {key_sections_parts, <>, 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(<>, 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()).