-module(ids@cuid). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([generate/1, is_cuid/1, slug/1, is_slug/1, start/0]). -export_type([message/0, state/0, char_list/0]). -opaque message() :: {generate, gleam@erlang@process:subject(binary())} | {generate_slug, gleam@erlang@process:subject(binary())}. -opaque state() :: {state, integer(), binary()}. -type char_list() :: any(). -spec generate(gleam@erlang@process:subject(message())) -> binary(). generate(Channel) -> gleam@otp@actor:call(Channel, fun(Field@0) -> {generate, Field@0} end, 1000). -spec is_cuid(binary()) -> boolean(). is_cuid(Id) -> gleam@string:starts_with(Id, <<"c"/utf8>>). -spec slug(gleam@erlang@process:subject(message())) -> binary(). slug(Channel) -> gleam@otp@actor:call( Channel, fun(Field@0) -> {generate_slug, Field@0} end, 1000 ). -spec is_slug(binary()) -> boolean(). is_slug(Slug) -> Slug_length = gleam@string:length(Slug), (Slug_length >= 7) andalso (Slug_length =< 10). -spec format_id(list(binary())) -> binary(). format_id(Id_data) -> _pipe = Id_data, _pipe@1 = gleam@string:concat(_pipe), gleam@string:lowercase(_pipe@1). -spec timestamp() -> binary(). timestamp() -> Secs = os:system_time(millisecond), _pipe = Secs, gleam@int:to_base36(_pipe). -spec get_fingerprint() -> binary(). get_fingerprint() -> Operator = 36 * 36, _assert_subject = begin _pipe = os:getpid(), _pipe@1 = erlang:list_to_binary(_pipe), gleam@int:parse(_pipe@1) end, {ok, Pid} = 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 => <<"ids/cuid"/utf8>>, function => <<"get_fingerprint"/utf8>>, line => 150}) end, Id = (case Operator of 0 -> 0; Gleam@denominator -> Pid rem Gleam@denominator end) * Operator, Localhost = net_adm:localhost(), Sum = begin _pipe@2 = Localhost, gleam@list:fold(_pipe@2, 0, fun(Char, Acc) -> Char + Acc end) end, Hostid = case Operator of 0 -> 0; Gleam@denominator@1 -> ((Sum + gleam@list:length(Localhost)) + 36) rem Gleam@denominator@1 end, _pipe@3 = Id + Hostid, gleam@int:to_base36(_pipe@3). -spec format_count(integer()) -> binary(). format_count(Num) -> _pipe = Num, _pipe@1 = gleam@int:to_base36(_pipe), gleam@string:pad_left(_pipe@1, 4, <<"0"/utf8>>). -spec new_count(integer()) -> integer(). new_count(Count) -> case Count < 1679616 of true -> Count + 1; false -> 0 end. -spec random_block() -> binary(). random_block() -> _pipe = rand:uniform(1679616 - 1), _pipe@1 = gleam@int:to_base36(_pipe), gleam@string:pad_left(_pipe@1, 4, <<"0"/utf8>>). -spec handle_msg(message(), state()) -> gleam@otp@actor:next(message(), state()). handle_msg(Msg, State) -> case Msg of {generate, Reply} -> Id = format_id( [<<"c"/utf8>>, timestamp(), format_count(erlang:element(2, State)), erlang:element(3, State), random_block(), random_block()] ), gleam@otp@actor:send(Reply, Id), gleam@otp@actor:continue( erlang:setelement(2, State, new_count(erlang:element(2, State))) ); {generate_slug, Reply@1} -> Slug = format_id( [begin _pipe = timestamp(), gleam@string:slice(_pipe, -2, 2) end, begin _pipe@1 = format_count(erlang:element(2, State)), gleam@string:slice(_pipe@1, -4, 4) end, gleam@string:concat( [gleam@string:slice(erlang:element(3, State), 0, 1), gleam@string:slice(erlang:element(3, State), -1, 1)] ), begin _pipe@2 = random_block(), gleam@string:slice(_pipe@2, -2, 2) end] ), gleam@otp@actor:send(Reply@1, Slug), gleam@otp@actor:continue( erlang:setelement(2, State, new_count(erlang:element(2, State))) ) end. -spec start() -> {ok, gleam@erlang@process:subject(message())} | {error, gleam@otp@actor:start_error()}. start() -> gleam@otp@actor:start({state, 0, get_fingerprint()}, fun handle_msg/2).