Current section

Files

Jump to
ids src ids@cuid.erl
Raw

src/ids@cuid.erl

-module(ids@cuid).
-compile(no_auto_import).
-export([start/0, generate/1, is_cuid/1, slug/1, is_slug/1]).
-export_type([message/0, state/0, char_list/0]).
-opaque message() :: {generate, gleam@otp@process:sender(binary())} |
{generate_slug, gleam@otp@process:sender(binary())}.
-opaque state() :: {state, integer(), binary()}.
-type char_list() :: any().
-spec start() -> {ok, gleam@otp@process:sender(message())} |
{error, gleam@otp@actor:start_error()}.
start() ->
gleam@otp@actor:start({state, 0, get_fingerprint()}, fun handle_msg/2).
-spec generate(gleam@otp@process:sender(message())) -> binary().
generate(Channel) ->
gleam@otp@actor:call(Channel, fun(A) -> {generate, A} end, 1000).
-spec is_cuid(binary()) -> boolean().
is_cuid(Id) ->
gleam@string:starts_with(Id, <<"c"/utf8>>).
-spec slug(gleam@otp@process:sender(message())) -> binary().
slug(Channel) ->
gleam@otp@actor:call(Channel, fun(A) -> {generate_slug, A} end, 1000).
-spec is_slug(binary()) -> boolean().
is_slug(Slug) ->
Slug_length = gleam@string:length(Slug),
(Slug_length >= 7) andalso (Slug_length =< 10).
-spec handle_msg(message(), state()) -> gleam@otp@actor:next(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),
{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),
{continue,
erlang:setelement(2, State, new_count(erlang:element(2, State)))}
end.
-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 new_count(integer()) -> integer().
new_count(Count) ->
case Count < 1679616 of
true ->
Count + 1;
false ->
0
end.
-spec timestamp() -> binary().
timestamp() ->
Secs = gleam@erlang:system_time(millisecond),
_pipe = Secs,
gleam@int:to_base36(_pipe).
-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 get_fingerprint() -> binary().
get_fingerprint() ->
Operator = 36 * 36,
{ok, Pid@1} = case begin
_pipe = os:getpid(),
_pipe@1 = erlang:list_to_binary(_pipe),
gleam@int:parse(_pipe@1)
end of
{ok, Pid} -> {ok, Pid};
_try ->
erlang:error(#{gleam_error => assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _try,
module => <<"ids/cuid"/utf8>>,
function => <<"get_fingerprint"/utf8>>,
line => 150})
end,
Id = (case Operator of
0 -> 0;
Gleam@denominator -> Pid@1 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 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>>).