Current section

Files

Jump to
ids src ids@ulid.erl
Raw

src/ids@ulid.erl

-module(ids@ulid).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([monotonic_generate/1, monotonic_from_timestamp/2, decode/1, from_parts/2, from_timestamp/1, generate/0, start/0]).
-export_type([message/0, state/0]).
-opaque message() :: {generate,
gleam@erlang@process:subject({ok, binary()} | {error, binary()})} |
{generate_from_timestamp,
integer(),
gleam@erlang@process:subject({ok, binary()} | {error, binary()})}.
-opaque state() :: {state, integer(), bitstring()}.
-file("/Users/rvcas/thelab/me/ids/src/ids/ulid.gleam", 56).
-spec monotonic_generate(gleam@erlang@process:subject(message())) -> {ok,
binary()} |
{error, binary()}.
monotonic_generate(Channel) ->
gleam@otp@actor:call(Channel, fun(Field@0) -> {generate, Field@0} end, 1000).
-file("/Users/rvcas/thelab/me/ids/src/ids/ulid.gleam", 70).
-spec monotonic_from_timestamp(
gleam@erlang@process:subject(message()),
integer()
) -> {ok, binary()} | {error, binary()}.
monotonic_from_timestamp(Channel, Timestamp) ->
gleam@otp@actor:call(
Channel,
fun(Subject) -> {generate_from_timestamp, Timestamp, Subject} end,
1000
).
-file("/Users/rvcas/thelab/me/ids/src/ids/ulid.gleam", 119).
-spec decode(binary()) -> {ok, {integer(), bitstring()}} | {error, binary()}.
decode(Ulid) ->
case ids@base32:decode(Ulid, <<"0123456789ABCDEFGHJKMNPQRSTVWXYZ"/utf8>>) of
{ok, <<Timestamp:48/unsigned, Randomness:80/bitstring>>} ->
{ok, {Timestamp, Randomness}};
_ ->
{error,
<<"Error: Decoding failed. Is a valid ULID being supplied?"/utf8>>}
end.
-file("/Users/rvcas/thelab/me/ids/src/ids/ulid.gleam", 97).
-spec from_parts(integer(), bitstring()) -> {ok, binary()} | {error, binary()}.
from_parts(Timestamp, Randomness) ->
case {Timestamp, Randomness} of
{Time, <<Rand:80/bitstring>>} when Time =< 281474976710655 ->
_pipe = <<Timestamp:48, Rand/bitstring>>,
_pipe@1 = ids@base32:encode(
_pipe,
<<"0123456789ABCDEFGHJKMNPQRSTVWXYZ"/utf8>>
),
{ok, _pipe@1};
{_, _} ->
Error = gleam@string:concat(
[<<"Error: The timestamp is too large or randomness isn't 80 bits. Please use an Unix timestamp smaller than "/utf8>>,
erlang:integer_to_binary(281474976710655),
<<"."/utf8>>]
),
{error, Error}
end.
-file("/Users/rvcas/thelab/me/ids/src/ids/ulid.gleam", 92).
-spec from_timestamp(integer()) -> {ok, binary()} | {error, binary()}.
from_timestamp(Timestamp) ->
from_parts(Timestamp, crypto:strong_rand_bytes(10)).
-file("/Users/rvcas/thelab/me/ids/src/ids/ulid.gleam", 82).
-spec generate() -> binary().
generate() ->
Timestamp = os:system_time(millisecond),
case from_timestamp(Timestamp) of
{ok, Ulid} ->
Ulid;
_ ->
erlang:error(#{gleam_error => panic,
message => <<"Error: Couldn't generate ULID."/utf8>>,
module => <<"ids/ulid"/utf8>>,
function => <<"generate"/utf8>>,
line => 87})
end.
-file("/Users/rvcas/thelab/me/ids/src/ids/ulid.gleam", 142).
-spec generate_response_ulid(
integer(),
gleam@erlang@process:subject({ok, binary()} | {error, binary()}),
state()
) -> gleam@otp@actor:next(message(), state()).
generate_response_ulid(Timestamp, Reply, State) ->
case erlang:element(2, State) =:= Timestamp of
true ->
Randomness = begin
_pipe = erlang:element(3, State),
_pipe@1 = binary:decode_unsigned(_pipe),
_pipe@2 = gleam@int:add(_pipe@1, 1),
binary:encode_unsigned(_pipe@2)
end,
case from_parts(Timestamp, Randomness) of
{ok, Ulid} ->
gleam@otp@actor:send(Reply, {ok, Ulid});
_ ->
gleam@otp@actor:send(
Reply,
{error, <<"Error: Couldn't generate ULID."/utf8>>}
)
end,
gleam@otp@actor:continue({state, Timestamp, Randomness});
false ->
Randomness@1 = crypto:strong_rand_bytes(10),
case from_parts(Timestamp, Randomness@1) of
{ok, Ulid@1} ->
gleam@otp@actor:send(Reply, {ok, Ulid@1});
_ ->
gleam@otp@actor:send(
Reply,
{error, <<"Error: Couldn't generate ULID."/utf8>>}
)
end,
gleam@otp@actor:continue({state, Timestamp, Randomness@1})
end.
-file("/Users/rvcas/thelab/me/ids/src/ids/ulid.gleam", 128).
-spec handle_msg(message(), state()) -> gleam@otp@actor:next(message(), state()).
handle_msg(Msg, State) ->
case Msg of
{generate, Reply} ->
_pipe = os:system_time(millisecond),
generate_response_ulid(_pipe, Reply, State);
{generate_from_timestamp, Timestamp, Reply@1} ->
_pipe@1 = Timestamp,
generate_response_ulid(_pipe@1, Reply@1, State)
end.
-file("/Users/rvcas/thelab/me/ids/src/ids/ulid.gleam", 42).
-spec start() -> {ok, gleam@erlang@process:subject(message())} |
{error, gleam@otp@actor:start_error()}.
start() ->
gleam@otp@actor:start({state, 0, <<>>}, fun handle_msg/2).