-module(chip@registry). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([register/3, find/2, start/0]). -export_type([message/2, index/0, state/2]). -opaque message(HJZ, HKA) :: {tag, gleam@erlang@process:subject({ok, gleam@erlang@process:subject(HKA)} | {error, nil}), HJZ} | {registrant, gleam@erlang@process:subject(HKA), HJZ} | {demonitor, index()}. -type index() :: {index, gleam@erlang@process:pid_(), gleam@erlang@process:process_monitor()}. -type state(HKB, HKC) :: {state, gleam@erlang@process:subject(message(HKB, HKC)), gleam@dict:dict(HKB, gleam@erlang@process:subject(HKC)), gleam@dict:dict(gleam@erlang@process:pid_(), gleam@set:set(HKB)), gleam@erlang@process:selector(message(HKB, HKC))}. -spec register( gleam@erlang@process:subject(message(HKO, HKP)), gleam@erlang@process:subject(HKP), HKO ) -> nil. register(Registry, Subject, Name) -> gleam@erlang@process:send(Registry, {registrant, Subject, Name}). -spec find(gleam@erlang@process:subject(message(HKV, HKW)), HKV) -> {ok, gleam@erlang@process:subject(HKW)} | {error, nil}. find(Registry, Name) -> gleam@erlang@process:call( Registry, fun(_capture) -> {tag, _capture, Name} end, 10 ). -spec handle_init() -> gleam@otp@actor:init_result(state(HOT, HOS), message(HOT, HOS)). handle_init() -> Self = gleam@erlang@process:new_subject(), State = {state, Self, gleam@dict:new(), gleam@dict:new(), begin _pipe = gleam_erlang_ffi:new_selector(), gleam@erlang@process:selecting( _pipe, Self, fun gleam@function:identity/1 ) end}, {ready, State, erlang:element(5, State)}. -spec into_names(state(HLI, HLJ), HLI, gleam@erlang@process:subject(HLJ)) -> state(HLI, HLJ). into_names(State, Name, Subject) -> erlang:setelement( 3, State, gleam@dict:insert(erlang:element(3, State), Name, Subject) ). -spec into_tracker(state(HLP, HLQ), gleam@erlang@process:pid_(), HLP) -> state(HLP, HLQ). into_tracker(State, Pid, Location) -> Add_location = fun(Option) -> case Option of {some, Locations} -> gleam@set:insert(Locations, Location); none -> gleam@set:insert(gleam@set:new(), Location) end end, erlang:setelement( 4, State, gleam@dict:update(erlang:element(4, State), Pid, Add_location) ). -spec into_selector( state(HLV, HLW), gleam@option:option(gleam@erlang@process:selector(message(HLV, HLW))) ) -> state(HLV, HLW). into_selector(State, Selection) -> case Selection of {some, Selector} -> erlang:setelement(5, State, Selector); none -> State end. -spec remove_from_group(state(HMF, HMG), gleam@erlang@process:pid_()) -> state(HMF, HMG). remove_from_group(State, Pid) -> Names = case gleam@dict:get(erlang:element(4, State), Pid) of {ok, Locations} -> gleam@set:to_list(Locations); {error, nil} -> erlang:error(#{gleam_error => panic, message => <<"Impossible state, couldn't find a pid when removing from group."/utf8>>, module => <<"chip/registry"/utf8>>, function => <<"remove_from_group"/utf8>>, line => 181}) end, gleam@list:fold( Names, State, fun(State@1, Name) -> Names@1 = gleam@dict:delete(erlang:element(3, State@1), Name), erlang:setelement(3, State@1, Names@1) end ). -spec remove_from_tracker(state(HML, HMM), gleam@erlang@process:pid_()) -> state(HML, HMM). remove_from_tracker(State, Pid) -> erlang:setelement( 4, State, gleam@dict:delete(erlang:element(4, State), Pid) ). -spec select_process_down( gleam@erlang@process:selector(message(HMZ, HNA)), gleam@erlang@process:pid_(), gleam@erlang@process:process_monitor() ) -> gleam@erlang@process:selector(message(HMZ, HNA)). select_process_down(Selector, Pid, Monitor) -> Index = {index, Pid, Monitor}, Handle = fun(_) -> {demonitor, Index} end, gleam@erlang@process:selecting_process_down(Selector, Monitor, Handle). -spec monitor(state(HMR, HMS), gleam@erlang@process:pid_()) -> gleam@option:option(gleam@erlang@process:selector(message(HMR, HMS))). monitor(State, Pid) -> case gleam@dict:get(erlang:element(4, State), Pid) of {ok, _} -> none; {error, nil} -> Monitor = gleam@erlang@process:monitor_process(Pid), Selector = select_process_down( erlang:element(5, State), Pid, Monitor ), {some, Selector} end. -spec handle_message(message(HLB, HLC), state(HLB, HLC)) -> gleam@otp@actor:next(message(HLB, HLC), state(HLB, HLC)). handle_message(Message, State) -> case Message of {tag, Client, Name} -> Result = gleam@dict:get(erlang:element(3, State), Name), gleam@erlang@process:send(Client, Result), gleam@otp@actor:continue(State); {registrant, Subject, Name@1} -> Pid = gleam@erlang@process:subject_owner(Subject), Selection = monitor(State, Pid), _pipe = State, _pipe@1 = into_names(_pipe, Name@1, Subject), _pipe@2 = into_tracker(_pipe@1, Pid, Name@1), _pipe@3 = into_selector(_pipe@2, Selection), {continue, _pipe@3, Selection}; {demonitor, {index, Pid@1, Monitor}} -> gleam_erlang_ffi:demonitor(Monitor), _pipe@4 = State, _pipe@5 = remove_from_group(_pipe@4, Pid@1), _pipe@6 = remove_from_tracker(_pipe@5, Pid@1), gleam@otp@actor:continue(_pipe@6) end. -spec start() -> {ok, gleam@erlang@process:subject(message(any(), any()))} | {error, gleam@otp@actor:start_error()}. start() -> gleam@otp@actor:start_spec( {spec, fun handle_init/0, 10, fun handle_message/2} ).