-module(chip). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([all/1, named/1, lookup/2, register/2, register_as/3, deregister/2, stop/1, start/0]). -export_type([message/2, state/2]). -opaque message(HCK, HCL) :: {all, gleam@erlang@process:subject(list(gleam@erlang@process:subject(HCL)))} | {named, gleam@erlang@process:subject(list({HCK, gleam@erlang@process:subject(HCL)}))} | {lookup, gleam@erlang@process:subject(list(gleam@erlang@process:subject(HCL))), HCK} | {register, gleam@erlang@process:subject(HCL)} | {register_as, gleam@erlang@process:subject(HCL), HCK} | {deregister, HCK} | {demonitor, gleam@erlang@process:subject(HCL)} | rebuild_selector | {stop, gleam@erlang@process:subject(gleam@erlang@process:exit_reason())}. -type state(HCM, HCN) :: {state, gleam@erlang@process:subject(message(HCM, HCN)), gleam@dict:dict(gleam@erlang@process:pid_(), gleam@erlang@process:process_monitor()), gleam@set:set(gleam@erlang@process:subject(HCN)), gleam@dict:dict(HCM, gleam@set:set(gleam@erlang@process:subject(HCN))), gleam@erlang@process:selector(message(HCM, HCN))}. -spec all(gleam@erlang@process:subject(message(any(), HCW))) -> list(gleam@erlang@process:subject(HCW)). all(Registry) -> gleam@erlang@process:call( Registry, fun(_capture) -> {all, _capture} end, 100 ). -spec named(gleam@erlang@process:subject(message(HDC, HDD))) -> list({HDC, gleam@erlang@process:subject(HDD)}). named(Registry) -> gleam@erlang@process:call( Registry, fun(_capture) -> {named, _capture} end, 100 ). -spec lookup(gleam@erlang@process:subject(message(HDJ, HDK)), HDJ) -> list(gleam@erlang@process:subject(HDK)). lookup(Registry, Name) -> gleam@erlang@process:call( Registry, fun(_capture) -> {lookup, _capture, Name} end, 100 ). -spec register( gleam@erlang@process:subject(message(any(), HDR)), fun(() -> {ok, gleam@erlang@process:subject(HDR)} | {error, gleam@otp@actor:start_error()}) ) -> {ok, gleam@erlang@process:subject(HDR)} | {error, gleam@otp@actor:start_error()}. register(Registry, Start) -> gleam@result:'try'( Start(), fun(Subject) -> gleam@erlang@process:send(Registry, {register, Subject}), {ok, Subject} end ). -spec register_as( gleam@erlang@process:subject(message(HEB, HEC)), HEB, fun(() -> {ok, gleam@erlang@process:subject(HEC)} | {error, gleam@otp@actor:start_error()}) ) -> {ok, gleam@erlang@process:subject(HEC)} | {error, gleam@otp@actor:start_error()}. register_as(Registry, Name, Start) -> gleam@result:'try'( Start(), fun(Subject) -> gleam@erlang@process:send(Registry, {register_as, Subject, Name}), {ok, Subject} end ). -spec deregister(gleam@erlang@process:subject(message(HEM, any())), HEM) -> nil. deregister(Registry, Name) -> gleam@erlang@process:send(Registry, {deregister, Name}). -spec stop(gleam@erlang@process:subject(message(any(), any()))) -> gleam@erlang@process:exit_reason(). stop(Registry) -> gleam@erlang@process:call( Registry, fun(_capture) -> {stop, _capture} end, 10 ). -spec handle_init() -> gleam@otp@actor:init_result(state(HEW, HEX), message(HEW, HEX)). handle_init() -> Subject = gleam@erlang@process:new_subject(), Selector = begin _pipe = gleam_erlang_ffi:new_selector(), gleam@erlang@process:selecting( _pipe, Subject, fun gleam@function:identity/1 ) end, State = {state, Subject, gleam@dict:new(), gleam@set:new(), gleam@dict:new(), Selector}, {ready, State, Selector}. -spec demonitor_subject(state(HGF, HGG), gleam@erlang@process:subject(HGG)) -> state(HGF, HGG). demonitor_subject(State, Subject) -> Pid = gleam@erlang@process:subject_owner(Subject), case gleam@dict:get(erlang:element(3, State), Pid) of {ok, Monitor} -> gleam_erlang_ffi:demonitor(Monitor), Index = gleam@dict:delete(erlang:element(3, State), Pid), Group = gleam@set:delete(erlang:element(4, State), Subject), Delete = fun(_, Subjects) -> gleam@set:delete(Subjects, Subject) end, Named = gleam@dict:map_values(erlang:element(5, State), Delete), erlang:setelement( 5, erlang:setelement(4, erlang:setelement(3, State, Index), Group), Named ); {error, nil} -> State end. -spec get_group( gleam@dict:dict(HGM, gleam@set:set(gleam@erlang@process:subject(HGN))), HGM ) -> gleam@set:set(gleam@erlang@process:subject(HGN)). get_group(Named, Name) -> case gleam@dict:get(Named, Name) of {ok, Subjects} -> Subjects; {error, nil} -> gleam@set:new() end. -spec delete_named(state(HFZ, HGA), HFZ) -> state(HFZ, HGA). delete_named(State, Name) -> Other_named = gleam@dict:delete(erlang:element(5, State), Name), Other_subjects = gleam@dict:fold( Other_named, gleam@set:new(), fun(All_subjects, _, Subjects) -> gleam@set:union(All_subjects, Subjects) end ), Subjects@1 = get_group(erlang:element(5, State), Name), Subjects_to_keep = begin _pipe = gleam@set:intersection(Subjects@1, Other_subjects), gleam@set:to_list(_pipe) end, Subjects_to_delete = begin _pipe@1 = gleam@set:drop(Subjects@1, Subjects_to_keep), gleam@set:to_list(_pipe@1) end, Pids_to_delete = begin _pipe@2 = Subjects_to_delete, gleam@list:map( _pipe@2, fun(Subject) -> gleam@erlang@process:subject_owner(Subject) end ) end, Monitors = begin _pipe@3 = erlang:element(3, State), _pipe@4 = gleam@dict:take(_pipe@3, Pids_to_delete), gleam@dict:values(_pipe@4) end, gleam@list:each(Monitors, fun gleam_erlang_ffi:demonitor/1), Index = gleam@dict:drop(erlang:element(3, State), Pids_to_delete), Group = gleam@set:drop(erlang:element(4, State), Subjects_to_delete), Named = gleam@dict:delete(erlang:element(5, State), Name), erlang:setelement( 5, erlang:setelement(4, erlang:setelement(3, State, Index), Group), Named ). -spec receive_process_down( gleam@erlang@process:selector(message(HHA, HHB)), gleam@erlang@process:process_monitor(), gleam@erlang@process:subject(HHB) ) -> gleam@erlang@process:selector(message(HHA, HHB)). receive_process_down(Selector, Monitor, Subject) -> Handle = fun(_) -> {demonitor, Subject} end, gleam@erlang@process:selecting_process_down(Selector, Monitor, Handle). -spec insert(state(HFL, HFM), gleam@erlang@process:subject(HFM)) -> state(HFL, HFM). insert(State, Subject) -> Pid = gleam@erlang@process:subject_owner(Subject), case gleam@dict:get(erlang:element(3, State), Pid) of {ok, Monitor} -> Group = gleam@set:insert(erlang:element(4, State), Subject), Selector = receive_process_down( erlang:element(6, State), Monitor, Subject ), erlang:setelement(6, erlang:setelement(4, State, Group), Selector); {error, nil} -> Monitor@1 = gleam@erlang@process:monitor_process(Pid), Index = gleam@dict:insert(erlang:element(3, State), Pid, Monitor@1), Group@1 = gleam@set:insert(erlang:element(4, State), Subject), Selector@1 = receive_process_down( erlang:element(6, State), Monitor@1, Subject ), erlang:setelement( 6, erlang:setelement( 4, erlang:setelement(3, State, Index), Group@1 ), Selector@1 ) end. -spec insert_as(state(HFS, HFT), gleam@erlang@process:subject(HFT), HFS) -> state(HFS, HFT). insert_as(State, Subject, Name) -> Subjects = begin _pipe = erlang:element(5, State), _pipe@1 = get_group(_pipe, Name), gleam@set:insert(_pipe@1, Subject) end, Named = gleam@dict:insert(erlang:element(5, State), Name, Subjects), _pipe@2 = erlang:setelement(5, State, Named), insert(_pipe@2, Subject). -spec rebuild_process_down_selectors(state(HGU, HGV)) -> state(HGU, HGV). rebuild_process_down_selectors(State) -> Self = gleam@erlang@process:new_subject(), Subjects = gleam@set:to_list(erlang:element(4, State)), Selector@1 = begin _pipe = gleam_erlang_ffi:new_selector(), _pipe@1 = gleam@erlang@process:selecting( _pipe, Self, fun gleam@function:identity/1 ), gleam@list:fold( Subjects, _pipe@1, fun(Selector, Subject) -> Pid = gleam@erlang@process:subject_owner(Subject), case gleam@dict:get(erlang:element(3, State), Pid) of {ok, Monitor} -> receive_process_down(Selector, Monitor, Subject); {error, nil} -> Selector end end ) end, erlang:setelement(6, erlang:setelement(2, State, Self), Selector@1). -spec handle_message(message(HFE, HFF), state(HFE, HFF)) -> gleam@otp@actor:next(message(HFE, HFF), state(HFE, HFF)). handle_message(Message, State) -> case Message of {all, Client} -> Subjects = gleam@set:to_list(erlang:element(4, State)), gleam@erlang@process:send(Client, Subjects), gleam@otp@actor:continue(State); {named, Client@1} -> Indexed@1 = gleam@dict:fold( erlang:element(5, State), [], fun(Acc, Key, Subjects@1) -> Indexed = begin _pipe = Subjects@1, _pipe@1 = gleam@set:to_list(_pipe), gleam@list:map( _pipe@1, fun(Subject) -> {Key, Subject} end ) end, gleam@list:append(Indexed, Acc) end ), gleam@erlang@process:send(Client@1, Indexed@1), gleam@otp@actor:continue(State); {lookup, Client@2, Name} -> Subjects@2 = begin _pipe@2 = get_group(erlang:element(5, State), Name), gleam@set:to_list(_pipe@2) end, gleam@erlang@process:send(Client@2, Subjects@2), gleam@otp@actor:continue(State); {register, Subject@1} -> State@1 = insert(State, Subject@1), _pipe@3 = gleam@otp@actor:continue(State@1), gleam@otp@actor:with_selector(_pipe@3, erlang:element(6, State@1)); {register_as, Subject@2, Name@1} -> State@2 = insert_as(State, Subject@2, Name@1), _pipe@4 = gleam@otp@actor:continue(State@2), gleam@otp@actor:with_selector(_pipe@4, erlang:element(6, State@2)); {deregister, Name@2} -> State@3 = delete_named(State, Name@2), gleam@erlang@process:send( erlang:element(2, State@3), rebuild_selector ), gleam@otp@actor:continue(State@3); {demonitor, Subject@3} -> State@4 = demonitor_subject(State, Subject@3), gleam@erlang@process:send( erlang:element(2, State@4), rebuild_selector ), gleam@otp@actor:continue(State@4); rebuild_selector -> State@5 = rebuild_process_down_selectors(State), _pipe@5 = gleam@otp@actor:continue(State@5), gleam@otp@actor:with_selector(_pipe@5, erlang:element(6, State@5)); {stop, Client@3} -> gleam@erlang@process:send(Client@3, normal), {stop, normal} 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} ).