-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) -> <>. -spec format_machine_id(integer()) -> bitstring(). format_machine_id(Mid) -> <>. -spec format_pid(integer()) -> bitstring(). format_pid(Pid) -> <>. -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) -> <> = <>, 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) -> <> = <>, {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.