Current section

Files

Jump to
gxid src gxid.erl
Raw

src/gxid.erl

-module(gxid).
-compile(no_auto_import).
-export([string/1, time/1, machine_id/1, pid/1, random_number/1, start/0, generate/1, parse/1, to_xid/1]).
-export_type([message/0, state/0, xid/0, char_list/0]).
-opaque message() :: {generate, gleam@erlang@process:subject(xid())}.
-opaque state() :: {state, integer(), integer(), integer()}.
-opaque xid() :: {xid, integer(), integer(), integer(), integer(), binary()}.
-type char_list() :: any().
-spec string(xid()) -> binary().
string(Xid) ->
erlang:element(6, Xid).
-spec time(xid()) -> integer().
time(Xid) ->
erlang:element(2, Xid).
-spec machine_id(xid()) -> integer().
machine_id(Xid) ->
erlang:element(3, Xid).
-spec pid(xid()) -> integer().
pid(Xid) ->
erlang:element(4, Xid).
-spec random_number(xid()) -> integer().
random_number(Xid) ->
erlang:element(5, Xid).
-spec start() -> {ok, gleam@erlang@process:subject(message())} |
{error, gleam@otp@actor:start_error()}.
start() ->
gleam@otp@actor:start(
{state, find_machine_id(), find_pid(), gleam@int:random(0, 16777215)},
fun handle/2
).
-spec generate(gleam@erlang@process:subject(message())) -> xid().
generate(Channel) ->
gleam@otp@actor:call(Channel, fun(A) -> {generate, A} end, 1000).
-spec handle(message(), state()) -> gleam@otp@actor:next(state()).
handle(Msg, State) ->
case Msg of
{generate, Reply} ->
gleam@otp@actor:send(
Reply,
begin
_pipe = [format_time(os:system_time(millisecond)),
format_machine_id(erlang:element(2, State)),
format_pid(erlang:element(3, State)),
format_random_number(erlang:element(4, State))],
_pipe@1 = gleam@bit_string:concat(_pipe),
to_xid(_pipe@1)
end
),
{continue,
erlang:setelement(4, State, erlang:element(4, State) + 1)}
end.
-spec format_time(integer()) -> bitstring().
format_time(Time) ->
<<Time:32/big>>.
-spec format_machine_id(integer()) -> bitstring().
format_machine_id(Mid) ->
<<Mid:24/big>>.
-spec format_pid(integer()) -> bitstring().
format_pid(Pid) ->
<<Pid:16/big>>.
-spec format_random_number(integer()) -> bitstring().
format_random_number(Random_number) ->
<<(gleam@bitwise:shift_left(Random_number, 8)):24/big>>.
-spec find_pid() -> integer().
find_pid() ->
{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 => <<"gxid"/utf8>>,
function => <<"find_pid"/utf8>>,
line => 118})
end,
Pid@1.
-spec find_machine_id() -> integer().
find_machine_id() ->
_pipe = net_adm:localhost(),
gleam@list:fold(_pipe, 0, fun(Char, Acc) -> Char + Acc end).
-spec encode(bitstring()) -> binary().
encode(Bit_xid) ->
<<B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, B10, B11>> = <<Bit_xid/bitstring>>,
Res = [encode_hex(gleam@bitwise:shift_right(B0, 3)),
encode_hex(
gleam@bitwise:'or'(
gleam@bitwise:'and'(gleam@bitwise:shift_right(B1, 6), 16#1F),
gleam@bitwise:'and'(gleam@bitwise:shift_left(B0, 2), 16#1F)
)
),
encode_hex(
gleam@bitwise:'and'(gleam@bitwise:shift_right(B1, 1), 16#1F)
),
encode_hex(
gleam@bitwise:'or'(
gleam@bitwise:'and'(gleam@bitwise:shift_right(B2, 4), 16#1F),
gleam@bitwise:'and'(gleam@bitwise:shift_left(B1, 4), 16#1F)
)
),
encode_hex(
gleam@bitwise:'or'(
gleam@bitwise:'and'(gleam@bitwise:shift_right(B3, 7), 16#1F),
gleam@bitwise:'and'(gleam@bitwise:shift_left(B2, 1), 16#1F)
)
),
encode_hex(
gleam@bitwise:'and'(gleam@bitwise:shift_right(B3, 2), 16#1F)
),
encode_hex(
gleam@bitwise:'or'(
gleam@bitwise:'and'(gleam@bitwise:shift_right(B4, 5), 16#1F),
gleam@bitwise:'and'(gleam@bitwise:shift_left(B3, 3), 16#1F)
)
),
encode_hex(gleam@bitwise:'and'(B4, 16#1F)),
encode_hex(gleam@bitwise:shift_right(B5, 3)),
encode_hex(
gleam@bitwise:'or'(
gleam@bitwise:'and'(gleam@bitwise:shift_right(B6, 6), 16#1F),
gleam@bitwise:'and'(gleam@bitwise:shift_left(B5, 2), 16#1F)
)
),
encode_hex(
gleam@bitwise:'and'(gleam@bitwise:shift_right(B6, 1), 16#1F)
),
encode_hex(
gleam@bitwise:'or'(
gleam@bitwise:'and'(gleam@bitwise:shift_right(B7, 4), 16#1F),
gleam@bitwise:'and'(gleam@bitwise:shift_left(B6, 4), 16#1F)
)
),
encode_hex(
gleam@bitwise:'or'(
gleam@bitwise:'and'(gleam@bitwise:shift_right(B8, 7), 16#1F),
gleam@bitwise:'and'(gleam@bitwise:shift_left(B7, 1), 16#1F)
)
),
encode_hex(
gleam@bitwise:'and'(gleam@bitwise:shift_right(B8, 2), 16#1F)
),
encode_hex(
gleam@bitwise:'or'(
gleam@bitwise:'and'(gleam@bitwise:shift_right(B9, 5), 16#1F),
gleam@bitwise:'and'(gleam@bitwise:shift_left(B8, 3), 16#1F)
)
),
encode_hex(gleam@bitwise:'and'(B9, 16#1F)),
encode_hex(gleam@bitwise:shift_right(B10, 3)),
encode_hex(
gleam@bitwise:'or'(
gleam@bitwise:'and'(gleam@bitwise:shift_right(B11, 6), 16#1F),
gleam@bitwise:'and'(gleam@bitwise:shift_left(B10, 2), 16#1F)
)
),
encode_hex(
gleam@bitwise:'and'(gleam@bitwise:shift_right(B11, 1), 16#1F)
),
encode_hex(
gleam@bitwise:'and'(gleam@bitwise:shift_left(B11, 4), 16#1F)
)],
gleam@string:join(Res, <<""/utf8>>).
-spec encode_hex(integer()) -> binary().
encode_hex(I) ->
case I 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>>;
16 ->
<<"g"/utf8>>;
17 ->
<<"h"/utf8>>;
18 ->
<<"i"/utf8>>;
19 ->
<<"j"/utf8>>;
20 ->
<<"k"/utf8>>;
21 ->
<<"l"/utf8>>;
22 ->
<<"m"/utf8>>;
23 ->
<<"n"/utf8>>;
24 ->
<<"o"/utf8>>;
25 ->
<<"p"/utf8>>;
26 ->
<<"q"/utf8>>;
27 ->
<<"r"/utf8>>;
28 ->
<<"s"/utf8>>;
29 ->
<<"t"/utf8>>;
30 ->
<<"u"/utf8>>;
31 ->
<<"v"/utf8>>
end.
-spec parse(binary()) -> xid().
parse(Str_xid) ->
_pipe = decode(Str_xid),
to_xid(_pipe).
-spec to_xid(bitstring()) -> xid().
to_xid(Bit_xid) ->
<<Time:32/big-unsigned,
Mid:24/big-unsigned,
Pid:16/big-unsigned,
Rn1/big-unsigned,
Rn2/big-unsigned,
Rn3/big-unsigned>> = <<Bit_xid/bitstring>>,
{xid,
Time,
Mid,
Pid,
gleam@bitwise:'or'(
gleam@bitwise:'or'(
gleam@bitwise:shift_left(Rn1, 16),
gleam@bitwise:shift_left(Rn2, 8)
),
Rn3
),
encode(Bit_xid)}.
-spec decode(binary()) -> bitstring().
decode(Xid) ->
[S0,
S1,
S2,
S3,
S4,
S5,
S6,
S7,
S8,
S9,
S10,
S11,
S12,
S13,
S14,
S15,
S16,
S17,
S18,
S19] = begin
_pipe = gleam@string:to_graphemes(Xid),
gleam@list:map(_pipe, fun(X) -> decode_hex(X) end)
end,
<<(gleam@bitwise:'or'(
gleam@bitwise:shift_left(S0, 3),
gleam@bitwise:shift_right(S1, 2)
)),
(gleam@bitwise:'or'(
gleam@bitwise:'or'(
gleam@bitwise:shift_left(S1, 6),
gleam@bitwise:shift_left(S2, 1)
),
gleam@bitwise:shift_right(S3, 4)
)),
(gleam@bitwise:'or'(
gleam@bitwise:shift_left(S3, 4),
gleam@bitwise:shift_right(S4, 1)
)),
(gleam@bitwise:'or'(
gleam@bitwise:'or'(
gleam@bitwise:shift_left(S4, 7),
gleam@bitwise:shift_left(S5, 2)
),
gleam@bitwise:shift_right(S6, 3)
)),
(gleam@bitwise:'or'(gleam@bitwise:shift_left(S6, 5), S7)),
(gleam@bitwise:'or'(
gleam@bitwise:shift_left(S8, 3),
gleam@bitwise:shift_right(S9, 2)
)),
(gleam@bitwise:'or'(
gleam@bitwise:'or'(
gleam@bitwise:shift_left(S9, 6),
gleam@bitwise:shift_left(S10, 1)
),
gleam@bitwise:shift_right(S11, 4)
)),
(gleam@bitwise:'or'(
gleam@bitwise:shift_left(S11, 4),
gleam@bitwise:shift_right(S12, 1)
)),
(gleam@bitwise:'or'(
gleam@bitwise:'or'(
gleam@bitwise:shift_left(S12, 7),
gleam@bitwise:shift_left(S13, 2)
),
gleam@bitwise:shift_right(S14, 3)
)),
(gleam@bitwise:'or'(gleam@bitwise:shift_left(S14, 5), S15)),
(gleam@bitwise:'or'(
gleam@bitwise:shift_left(S16, 3),
gleam@bitwise:shift_right(S17, 2)
)),
(gleam@bitwise:'or'(
gleam@bitwise:'or'(
gleam@bitwise:shift_left(S17, 6),
gleam@bitwise:shift_left(S18, 1)
),
gleam@bitwise:shift_right(S19, 4)
))>>.
-spec decode_hex(binary()) -> integer().
decode_hex(S) ->
case S of
<<"0"/utf8>> ->
0;
<<"1"/utf8>> ->
1;
<<"2"/utf8>> ->
2;
<<"3"/utf8>> ->
3;
<<"4"/utf8>> ->
4;
<<"5"/utf8>> ->
5;
<<"6"/utf8>> ->
6;
<<"7"/utf8>> ->
7;
<<"8"/utf8>> ->
8;
<<"9"/utf8>> ->
9;
<<"a"/utf8>> ->
10;
<<"b"/utf8>> ->
11;
<<"c"/utf8>> ->
12;
<<"d"/utf8>> ->
13;
<<"e"/utf8>> ->
14;
<<"f"/utf8>> ->
15;
<<"g"/utf8>> ->
16;
<<"h"/utf8>> ->
17;
<<"i"/utf8>> ->
18;
<<"j"/utf8>> ->
19;
<<"k"/utf8>> ->
20;
<<"l"/utf8>> ->
21;
<<"m"/utf8>> ->
22;
<<"n"/utf8>> ->
23;
<<"o"/utf8>> ->
24;
<<"p"/utf8>> ->
25;
<<"q"/utf8>> ->
26;
<<"r"/utf8>> ->
27;
<<"s"/utf8>> ->
28;
<<"t"/utf8>> ->
29;
<<"u"/utf8>> ->
30;
<<"v"/utf8>> ->
31
end.