-module(gxid). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([string/1, time/1, machine_id/1, pid/1, random_number/1, to_xid/1, parse/1, start/0, generate/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 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) -> <<(erlang:'bsl'(Random_number, 8)):24/big>>. -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>>; _ -> <<""/utf8>> end. -spec encode(bitstring()) -> binary(). encode(Bit_xid) -> _assert_subject = <>, <> = case _assert_subject of <<_, _, _, _, _, _, _, _, _, _, _, _>> -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"gxid"/utf8>>, function => <<"encode"/utf8>>, line => 135}) end, Res = [encode_hex(erlang:'bsr'(B0, 3)), encode_hex( erlang:'bor'( erlang:'band'(erlang:'bsr'(B1, 6), 16#1F), erlang:'band'(erlang:'bsl'(B0, 2), 16#1F) ) ), encode_hex(erlang:'band'(erlang:'bsr'(B1, 1), 16#1F)), encode_hex( erlang:'bor'( erlang:'band'(erlang:'bsr'(B2, 4), 16#1F), erlang:'band'(erlang:'bsl'(B1, 4), 16#1F) ) ), encode_hex( erlang:'bor'( erlang:'band'(erlang:'bsr'(B3, 7), 16#1F), erlang:'band'(erlang:'bsl'(B2, 1), 16#1F) ) ), encode_hex(erlang:'band'(erlang:'bsr'(B3, 2), 16#1F)), encode_hex( erlang:'bor'( erlang:'band'(erlang:'bsr'(B4, 5), 16#1F), erlang:'band'(erlang:'bsl'(B3, 3), 16#1F) ) ), encode_hex(erlang:'band'(B4, 16#1F)), encode_hex(erlang:'bsr'(B5, 3)), encode_hex( erlang:'bor'( erlang:'band'(erlang:'bsr'(B6, 6), 16#1F), erlang:'band'(erlang:'bsl'(B5, 2), 16#1F) ) ), encode_hex(erlang:'band'(erlang:'bsr'(B6, 1), 16#1F)), encode_hex( erlang:'bor'( erlang:'band'(erlang:'bsr'(B7, 4), 16#1F), erlang:'band'(erlang:'bsl'(B6, 4), 16#1F) ) ), encode_hex( erlang:'bor'( erlang:'band'(erlang:'bsr'(B8, 7), 16#1F), erlang:'band'(erlang:'bsl'(B7, 1), 16#1F) ) ), encode_hex(erlang:'band'(erlang:'bsr'(B8, 2), 16#1F)), encode_hex( erlang:'bor'( erlang:'band'(erlang:'bsr'(B9, 5), 16#1F), erlang:'band'(erlang:'bsl'(B8, 3), 16#1F) ) ), encode_hex(erlang:'band'(B9, 16#1F)), encode_hex(erlang:'bsr'(B10, 3)), encode_hex( erlang:'bor'( erlang:'band'(erlang:'bsr'(B11, 6), 16#1F), erlang:'band'(erlang:'bsl'(B10, 2), 16#1F) ) ), encode_hex(erlang:'band'(erlang:'bsr'(B11, 1), 16#1F)), encode_hex(erlang:'band'(erlang:'bsl'(B11, 4), 16#1F))], gleam@string:join(Res, <<""/utf8>>). -spec to_xid(bitstring()) -> xid(). to_xid(Bit_xid) -> _assert_subject = <>, <> = case _assert_subject of <<_:32/big-unsigned, _:24/big-unsigned, _:16/big-unsigned, _/big-unsigned, _/big-unsigned, _/big-unsigned>> -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"gxid"/utf8>>, function => <<"to_xid"/utf8>>, line => 246}) end, {xid, Time, Mid, Pid, erlang:'bor'( erlang:'bor'(erlang:'bsl'(Rn1, 16), erlang:'bsl'(Rn2, 8)), Rn3 ), encode(Bit_xid)}. -spec handle(message(), state()) -> gleam@otp@actor:next(message(), 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_stdlib:bit_array_concat(_pipe), to_xid(_pipe@1) end ), {continue, erlang:setelement(4, State, erlang:element(4, State) + 1), none} end. -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; _ -> 0 end. -spec decode(binary()) -> bitstring(). decode(Xid) -> _assert_subject = begin _pipe = gleam@string:to_graphemes(Xid), gleam@list:map(_pipe, fun(X) -> decode_hex(X) end) end, [S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13, S14, S15, S16, S17, S18, S19] = case _assert_subject of [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"gxid"/utf8>>, function => <<"decode"/utf8>>, line => 272}) end, <<(erlang:'bor'(erlang:'bsl'(S0, 3), erlang:'bsr'(S1, 2))), (erlang:'bor'( erlang:'bor'(erlang:'bsl'(S1, 6), erlang:'bsl'(S2, 1)), erlang:'bsr'(S3, 4) )), (erlang:'bor'(erlang:'bsl'(S3, 4), erlang:'bsr'(S4, 1))), (erlang:'bor'( erlang:'bor'(erlang:'bsl'(S4, 7), erlang:'bsl'(S5, 2)), erlang:'bsr'(S6, 3) )), (erlang:'bor'(erlang:'bsl'(S6, 5), S7)), (erlang:'bor'(erlang:'bsl'(S8, 3), erlang:'bsr'(S9, 2))), (erlang:'bor'( erlang:'bor'(erlang:'bsl'(S9, 6), erlang:'bsl'(S10, 1)), erlang:'bsr'(S11, 4) )), (erlang:'bor'(erlang:'bsl'(S11, 4), erlang:'bsr'(S12, 1))), (erlang:'bor'( erlang:'bor'(erlang:'bsl'(S12, 7), erlang:'bsl'(S13, 2)), erlang:'bsr'(S14, 3) )), (erlang:'bor'(erlang:'bsl'(S14, 5), S15)), (erlang:'bor'(erlang:'bsl'(S16, 3), erlang:'bsr'(S17, 2))), (erlang:'bor'( erlang:'bor'(erlang:'bsl'(S17, 6), erlang:'bsl'(S18, 1)), erlang:'bsr'(S19, 4) ))>>. -spec parse(binary()) -> xid(). parse(Str_xid) -> _pipe = decode(Str_xid), to_xid(_pipe). -spec find_pid() -> integer(). find_pid() -> _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 => <<"gxid"/utf8>>, function => <<"find_pid"/utf8>>, line => 120}) end, Pid. -spec find_machine_id() -> integer(). find_machine_id() -> _pipe = net_adm:localhost(), gleam@list:fold(_pipe, 0, fun(Char, Acc) -> Char + Acc end). -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(16777215)}, fun handle/2 ). -spec generate(gleam@erlang@process:subject(message())) -> xid(). generate(Channel) -> gleam@otp@actor:call(Channel, fun(Field@0) -> {generate, Field@0} end, 1000).