-module(chip). -compile([no_auto_import, nowarn_unused_vars]). -export([all/1, lookup/2, register/2, register_as/3, deregister/2, stop/1, start/0]). -export_type([action/2, state/2]). -opaque action(GVS, GVT) :: {all, gleam@erlang@process:subject(list(gleam@erlang@process:subject(GVT)))} | {lookup, gleam@erlang@process:subject(list(gleam@erlang@process:subject(GVT))), GVS} | {register, gleam@erlang@process:subject(GVT)} | {register_as, gleam@erlang@process:subject(GVT), GVS} | {deregister, GVS} | {demonitor, gleam@erlang@process:subject(GVT)} | {stop, gleam@erlang@process:subject(gleam@erlang@process:exit_reason())}. -type state(GVU, GVV) :: {state, gleam@map:map_(gleam@erlang@process:subject(GVU), gleam@erlang@process:process_monitor()), gleam@map:map_(GVV, gleam@set:set(gleam@erlang@process:subject(GVU))), gleam@erlang@process:selector(action(GVV, GVU))}. -spec all(gleam@erlang@process:subject(action(any(), GWE))) -> list(gleam@erlang@process:subject(GWE)). all(Registry) -> gleam@erlang@process:call( Registry, fun(_capture) -> {all, _capture} end, 100 ). -spec lookup(gleam@erlang@process:subject(action(GWK, GWL)), GWK) -> list(gleam@erlang@process:subject(GWL)). lookup(Registry, Name) -> gleam@erlang@process:call( Registry, fun(_capture) -> {lookup, _capture, Name} end, 100 ). -spec register( gleam@erlang@process:subject(action(any(), GWS)), fun(() -> {ok, gleam@erlang@process:subject(GWS)} | {error, gleam@otp@actor:start_error()}) ) -> {ok, gleam@erlang@process:subject(GWS)} | {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(action(GXC, GXD)), GXC, fun(() -> {ok, gleam@erlang@process:subject(GXD)} | {error, gleam@otp@actor:start_error()}) ) -> {ok, gleam@erlang@process:subject(GXD)} | {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(action(GXN, any())), GXN) -> nil. deregister(Registry, Name) -> gleam@erlang@process:send(Registry, {deregister, Name}). -spec stop(gleam@erlang@process:subject(action(any(), any()))) -> gleam@erlang@process:exit_reason(). stop(Registry) -> gleam@erlang@process:call( Registry, fun(_capture) -> {stop, _capture} end, 10 ). -spec demonitor_subject(state(GYY, GYZ), gleam@erlang@process:subject(GYY)) -> state(GYY, GYZ). demonitor_subject(State, Subject) -> case gleam@map:get(erlang:element(2, State), Subject) of {ok, Monitor} -> gleam_erlang_ffi:demonitor(Monitor), Group = gleam@map:delete(erlang:element(2, State), Subject), Named = gleam@map:map_values( erlang:element(3, State), fun(_, Subjects) -> gleam@set:delete(Subjects, Subject) end ), State@1 = erlang:setelement( 3, erlang:setelement(2, State, Group), Named ), State@1; {error, nil} -> State end. -spec get_name( gleam@map:map_(GZF, gleam@set:set(gleam@erlang@process:subject(GZG))), GZF ) -> gleam@set:set(gleam@erlang@process:subject(GZG)). get_name(Named, Name) -> case gleam@map:get(Named, Name) of {ok, Subjects} -> Subjects; {error, nil} -> gleam@set:new() end. -spec delete_named(state(GYS, GYT), GYT) -> state(GYS, GYT). delete_named(State, Name) -> Other_named = gleam@map:delete(erlang:element(3, State), Name), Other_subjects = gleam@map:fold( Other_named, gleam@set:new(), fun(All_subjects, _, Subjects) -> gleam@set:union(All_subjects, Subjects) end ), Subjects@1 = get_name(erlang:element(3, 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, Monitors = begin _pipe@2 = erlang:element(2, State), _pipe@3 = gleam@map:take(_pipe@2, Subjects_to_delete), gleam@map:values(_pipe@3) end, gleam@list:each(Monitors, fun gleam_erlang_ffi:demonitor/1), Group = gleam@map:drop(erlang:element(2, State), Subjects_to_delete), Named = gleam@map:delete(erlang:element(3, State), Name), erlang:setelement(3, erlang:setelement(2, State, Group), Named). -spec capture_process_down( gleam@erlang@process:selector(action(GZN, GZO)), gleam@erlang@process:process_monitor(), gleam@erlang@process:subject(GZO) ) -> gleam@erlang@process:selector(action(GZN, GZO)). capture_process_down(Selector, Monitor, Subject) -> Handle = fun(_) -> {demonitor, Subject} end, gleam@erlang@process:selecting_process_down(Selector, Monitor, Handle). -spec insert( state(GYE, GYF), gleam@erlang@process:subject(GYE), gleam@erlang@process:process_monitor() ) -> state(GYE, GYF). insert(State, Subject, Monitor) -> Group = gleam@map:insert(erlang:element(2, State), Subject, Monitor), Selector = capture_process_down(erlang:element(4, State), Monitor, Subject), erlang:setelement(4, erlang:setelement(2, State, Group), Selector). -spec insert_as( state(GYL, GYM), gleam@erlang@process:subject(GYL), gleam@erlang@process:process_monitor(), GYM ) -> state(GYL, GYM). insert_as(State, Subject, Monitor, Name) -> Subjects = begin _pipe = erlang:element(3, State), _pipe@1 = get_name(_pipe, Name), gleam@set:insert(_pipe@1, Subject) end, Named = gleam@map:insert(erlang:element(3, State), Name, Subjects), _pipe@2 = erlang:setelement(3, State, Named), insert(_pipe@2, Subject, Monitor). -spec handle_message(action(GXX, GXY), state(GXY, GXX)) -> gleam@otp@actor:next(action(GXX, GXY), state(GXY, GXX)). handle_message(Message, State) -> case Message of {all, Client} -> Subjects = gleam@map:keys(erlang:element(2, State)), gleam@erlang@process:send(Client, Subjects), gleam@otp@actor:continue(State); {lookup, Client@1, Name} -> Subjects@1 = begin _pipe = erlang:element(3, State), _pipe@1 = get_name(_pipe, Name), gleam@set:to_list(_pipe@1) end, gleam@erlang@process:send(Client@1, Subjects@1), gleam@otp@actor:continue(State); {register, Subject} -> Monitor = begin _pipe@2 = Subject, _pipe@3 = gleam@erlang@process:subject_owner(_pipe@2), gleam@erlang@process:monitor_process(_pipe@3) end, State@1 = insert(State, Subject, Monitor), _pipe@4 = gleam@otp@actor:continue(State@1), gleam@otp@actor:with_selector(_pipe@4, erlang:element(4, State@1)); {register_as, Subject@1, Name@1} -> Monitor@1 = begin _pipe@5 = Subject@1, _pipe@6 = gleam@erlang@process:subject_owner(_pipe@5), gleam@erlang@process:monitor_process(_pipe@6) end, State@2 = insert_as(State, Subject@1, Monitor@1, Name@1), _pipe@7 = gleam@otp@actor:continue(State@2), gleam@otp@actor:with_selector(_pipe@7, erlang:element(4, State@2)); {deregister, Name@2} -> State@3 = begin _pipe@8 = State, delete_named(_pipe@8, Name@2) end, _pipe@9 = gleam@otp@actor:continue(State@3), gleam@otp@actor:with_selector(_pipe@9, erlang:element(4, State@3)); {demonitor, Subject@2} -> State@4 = begin _pipe@10 = State, demonitor_subject(_pipe@10, Subject@2) end, _pipe@11 = gleam@otp@actor:continue(State@4), gleam@otp@actor:with_selector(_pipe@11, erlang:element(4, State@4)); {stop, Client@2} -> gleam@erlang@process:send(Client@2, normal), {stop, normal} end. -spec start() -> {ok, gleam@erlang@process:subject(action(any(), any()))} | {error, gleam@otp@actor:start_error()}. start() -> gleam@otp@actor:start( {state, gleam@map:new(), gleam@map:new(), gleam_erlang_ffi:new_selector()}, fun handle_message/2 ).