-module(glecuid@cuid2). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/glecuid/cuid2.gleam"). -export([with_counter/2, with_fingerprint/2, with_length/2, with_randomizer/2, bit_array_to_base36/1, bump_counter/1, get_global_object/0, new_counter/1, generate/1, create_fingerprint/1, is_cuid/1, new/0, create_id/0]). -export_type([generator/0, counter/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 generator() :: {generator, counter(), binary(), integer(), fun(() -> float())}. -opaque counter() :: {counter, atomic_array:atomic_array()} | {custom_counter, fun(() -> integer())}. -file("src/glecuid/cuid2.gleam", 110). ?DOC( " Sets a custom counter to be used by the `Generator`.\n" " \n" " Counter is a function that returns an incrementing `Int` \n" " every time it is called.\n" ). -spec with_counter(generator(), fun(() -> integer())) -> generator(). with_counter(G, Counter) -> {generator, {custom_counter, Counter}, erlang:element(3, G), erlang:element(4, G), erlang:element(5, G)}. -file("src/glecuid/cuid2.gleam", 119). ?DOC( " Sets a custom fingerprint to be used by the `Generator`.\n" " \n" " Fingerprint is a unique `String` to help prevent collision \n" " when generating ids in a distributed system.\n" ). -spec with_fingerprint(generator(), binary()) -> generator(). with_fingerprint(G, Fingerprint) -> {generator, erlang:element(2, G), Fingerprint, erlang:element(4, G), erlang:element(5, G)}. -file("src/glecuid/cuid2.gleam", 125). ?DOC(" Sets the length of the ids generated by the `Generator`.\n"). -spec with_length(generator(), integer()) -> generator(). with_length(G, Length) -> {generator, erlang:element(2, G), erlang:element(3, G), Length, erlang:element(5, G)}. -file("src/glecuid/cuid2.gleam", 134). ?DOC( " Sets a custom randomizer to be used by the `Generator`.\n" " \n" " Randomizer is a function that returns a random `Float` \n" " between zero (inclusive) and one (exclusive).\n" ). -spec with_randomizer(generator(), fun(() -> float())) -> generator(). with_randomizer(G, Randomizer) -> {generator, erlang:element(2, G), erlang:element(3, G), erlang:element(4, G), Randomizer}. -file("src/glecuid/cuid2.gleam", 156). -spec bit_array_to_int_loop(integer(), bitstring()) -> integer(). bit_array_to_int_loop(Accumulator, Bit_array) -> case Bit_array of <<>> -> Accumulator; <> -> _pipe = Accumulator, _pipe@1 = erlang:'bsl'(_pipe, 8), gleam@int:add(_pipe@1, X); <> -> _pipe = Accumulator, _pipe@1 = erlang:'bsl'(_pipe, 8), gleam@int:add(_pipe@1, X); <> -> _pipe = Accumulator, _pipe@1 = erlang:'bsl'(_pipe, 8), gleam@int:add(_pipe@1, X); <> -> _pipe = Accumulator, _pipe@1 = erlang:'bsl'(_pipe, 8), gleam@int:add(_pipe@1, X); <> -> _pipe = Accumulator, _pipe@1 = erlang:'bsl'(_pipe, 8), gleam@int:add(_pipe@1, X); <> -> _pipe = Accumulator, _pipe@1 = erlang:'bsl'(_pipe, 8), gleam@int:add(_pipe@1, X); <> -> _pipe = Accumulator, _pipe@1 = erlang:'bsl'(_pipe, 8), gleam@int:add(_pipe@1, X); <> -> _pipe = Accumulator, _pipe@1 = erlang:'bsl'(_pipe, 8), gleam@int:add(_pipe@1, X); <> -> _pipe@2 = Accumulator, _pipe@3 = erlang:'bsl'(_pipe@2, 8), _pipe@4 = gleam@int:add(_pipe@3, X@1), bit_array_to_int_loop(_pipe@4, Rest); _ -> Accumulator end. -file("src/glecuid/cuid2.gleam", 152). ?DOC(" Converts `BitArray` into `Int`.\n"). -spec bit_array_to_int(bitstring()) -> integer(). bit_array_to_int(Bit_array) -> bit_array_to_int_loop(0, Bit_array). -file("src/glecuid/cuid2.gleam", 144). ?DOC(false). -spec bit_array_to_base36(bitstring()) -> binary(). bit_array_to_base36(Bit_array) -> _pipe = Bit_array, _pipe@1 = bit_array_to_int(_pipe), gleam@int:to_base36(_pipe@1). -file("src/glecuid/cuid2.gleam", 187). ?DOC(false). -spec bump_counter(counter()) -> integer(). bump_counter(C) -> case C of {counter, C@1} -> case begin _pipe = C@1, atomic_array_ffi:add(_pipe, 0, 1) end of {ok, _} -> nil; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"glecuid/cuid2"/utf8>>, function => <<"bump_counter"/utf8>>, line => 190, value => _assert_fail, start => 4405, 'end' => 4451, pattern_start => 4416, pattern_end => 4421}) end, V@1 = case begin _pipe@1 = C@1, atomic_array_ffi:get(_pipe@1, 0) end of {ok, V} -> V; _assert_fail@1 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"glecuid/cuid2"/utf8>>, function => <<"bump_counter"/utf8>>, line => 191, value => _assert_fail@1, start => 4458, 'end' => 4501, pattern_start => 4469, pattern_end => 4474}) end, V@1; {custom_counter, C@2} -> C@2() end. -file("src/glecuid/cuid2.gleam", 239). ?DOC(false). -spec get_global_object() -> binary(). get_global_object() -> _pipe = erlang:self(), gleam@string:inspect(_pipe). -file("src/glecuid/cuid2.gleam", 245). ?DOC(" Hashes the input.\n"). -spec hash(binary()) -> binary(). hash(Input) -> _pipe = gleam_stdlib:identity(Input), _pipe@1 = gleam@crypto:hash(sha512, _pipe), _pipe@2 = bit_array_to_base36(_pipe@1), gleam@string:drop_start(_pipe@2, 1). -file("src/glecuid/cuid2.gleam", 269). ?DOC(" Creates a counter using the specified initial value.\n"). -spec new_counter(integer()) -> counter(). new_counter(Initial_count) -> Counter = atomic_array:new_unsigned(1), case begin _pipe = Counter, atomic_array_ffi:set(_pipe, 0, Initial_count) end of {ok, _} -> nil; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"glecuid/cuid2"/utf8>>, function => <<"new_counter"/utf8>>, line => 271, value => _assert_fail, start => 6659, 'end' => 6723, pattern_start => 6670, pattern_end => 6675}) end, {counter, Counter}. -file("src/glecuid/cuid2.gleam", 279). ?DOC( " Generates a random int between zero and the given maximum \n" " using the provided randomizer.\n" " The lower number is inclusive, the upper number is exclusive.\n" ). -spec random_int(fun(() -> float()), integer()) -> integer(). random_int(Randomizer, Max) -> _pipe = (Randomizer() * erlang:float(Max)), _pipe@1 = math:floor(_pipe), erlang:round(_pipe@1). -file("src/glecuid/cuid2.gleam", 206). -spec create_entropy_loop(binary(), integer(), fun(() -> float()), integer()) -> binary(). create_entropy_loop(Accumulator, Iteration, Randomizer, Length) -> gleam@bool:guard( Iteration >= Length, Accumulator, fun() -> _pipe@1 = (<>), create_entropy_loop(_pipe@1, Iteration + 1, Randomizer, Length) end ). -file("src/glecuid/cuid2.gleam", 202). ?DOC( " Generates a random alphanumeric string with a specified length\n" " using the provided randomizer.\n" ). -spec create_entropy(fun(() -> float()), integer()) -> binary(). create_entropy(Randomizer, Length) -> create_entropy_loop(<<""/utf8>>, 0, Randomizer, Length). -file("src/glecuid/cuid2.gleam", 288). ?DOC( " Generates a random lowercase letter using the provided \n" " randomizer.\n" ). -spec random_letter(fun(() -> float())) -> binary(). random_letter(Randomizer) -> C@1 = case begin _pipe = random_int(Randomizer, 27), _pipe@1 = gleam@int:add(_pipe, 97), gleam@string:utf_codepoint(_pipe@1) end of {ok, C} -> C; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"glecuid/cuid2"/utf8>>, function => <<"random_letter"/utf8>>, line => 289, value => _assert_fail, start => 7195, 'end' => 7293, pattern_start => 7206, pattern_end => 7211}) end, gleam_stdlib:utf_codepoint_list_to_string([C@1]). -file("src/glecuid/cuid2.gleam", 70). ?DOC( " Generates a CUIDv2 using custom generator.\n" " \n" " ## Examples\n" " \n" " ```gleam\n" " cuid2.new()\n" " |> cuid2.with_length(10)\n" " |> cuid2.with_fingerprint(\"my_machine\")\n" " |> cuid2.generate()\n" " // -> \"av77nekw5e\"\n" " ```\n" ). -spec generate(generator()) -> binary(). generate(G) -> {generator, Counter, Fingerprint, Length, Randomizer} = G, First_letter = random_letter(Randomizer), Time = begin _pipe = gleam@time@timestamp:system_time(), _pipe@1 = gleam@time@timestamp:to_unix_seconds_and_nanoseconds(_pipe), _pipe@2 = gleam@pair:first(_pipe@1), gleam@int:to_base36(_pipe@2) end, Count = begin _pipe@3 = bump_counter(Counter), gleam@int:to_base36(_pipe@3) end, Salt = create_entropy(Randomizer, Length), <>/binary, Count/binary>>/binary, Fingerprint/binary>>), _pipe@5 = hash(_pipe@4), _pipe@6 = gleam@string:slice(_pipe@5, 1, Length - 1), string:lowercase(_pipe@6) end)/binary>>. -file("src/glecuid/cuid2.gleam", 219). ?DOC(" Generates a fingerprint of the host environtment.\n"). -spec create_fingerprint(fun(() -> float())) -> binary(). create_fingerprint(Randomizer) -> <<(get_global_object())/binary, (begin _pipe = create_entropy(Randomizer, 32), _pipe@1 = hash(_pipe), gleam@string:slice(_pipe@1, 0, 32) end)/binary>>. -file("src/glecuid/cuid2.gleam", 257). ?DOC(" Determines whether or not the string is a valid CUIDv2.\n"). -spec is_cuid(binary()) -> boolean(). is_cuid(Input) -> Length = begin _pipe = Input, string:length(_pipe) end, Regex@1 = case gleam@regexp:from_string(<<"^[a-z][0-9a-z]+$"/utf8>>) of {ok, Regex} -> Regex; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"glecuid/cuid2"/utf8>>, function => <<"is_cuid"/utf8>>, line => 259, value => _assert_fail, start => 6316, 'end' => 6377, pattern_start => 6327, pattern_end => 6336}) end, case gleam@regexp:check(Regex@1, Input) of true when (2 =< Length) andalso (Length =< 32) -> true; _ -> false end. -file("src/glecuid/cuid2.gleam", 94). ?DOC(" Creates a `Generator` with default values to be customized.\n"). -spec new() -> generator(). new() -> Randomizer = fun rand:uniform/0, {generator, begin _pipe = random_int(Randomizer, 476782367), new_counter(_pipe) end, create_fingerprint(Randomizer), 24, Randomizer}. -file("src/glecuid/cuid2.gleam", 54). ?DOC( " Generates a CUIDv2 using the default generator.\n" " \n" " ## Examples\n" " \n" " ```gleam\n" " cuid2.create_id()\n" " // -> \"avu4793cnw6ljhov1s7Oxidg\" \n" " ```\n" ). -spec create_id() -> binary(). create_id() -> generate(new()).