Current section
Files
Jump to
Current section
Files
src/chip.erl
-module(chip).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([all/1, lookup/2, register/2, register_as/3, deregister/2, stop/1, start/0]).
-export_type([action/2, state/2]).
-opaque action(HCK, HCL) :: {all,
gleam@erlang@process:subject(list(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(action(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(action(HCM, HCN))}.
-spec all(gleam@erlang@process:subject(action(any(), HCW))) -> list(gleam@erlang@process:subject(HCW)).
all(Registry) ->
gleam@erlang@process:call(
Registry,
fun(_capture) -> {all, _capture} end,
100
).
-spec lookup(gleam@erlang@process:subject(action(HDC, HDD)), HDC) -> list(gleam@erlang@process:subject(HDD)).
lookup(Registry, Name) ->
gleam@erlang@process:call(
Registry,
fun(_capture) -> {lookup, _capture, Name} end,
100
).
-spec register(
gleam@erlang@process:subject(action(any(), HDK)),
fun(() -> {ok, gleam@erlang@process:subject(HDK)} |
{error, gleam@otp@actor:start_error()})
) -> {ok, gleam@erlang@process:subject(HDK)} |
{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(HDU, HDV)),
HDU,
fun(() -> {ok, gleam@erlang@process:subject(HDV)} |
{error, gleam@otp@actor:start_error()})
) -> {ok, gleam@erlang@process:subject(HDV)} |
{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(HEF, any())), HEF) -> 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 handle_init() -> gleam@otp@actor:init_result(state(HEP, HEQ), action(HEP, HEQ)).
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(HFY, HFZ), gleam@erlang@process:subject(HFZ)) -> state(HFY, HFZ).
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(HGF, gleam@set:set(gleam@erlang@process:subject(HGG))),
HGF
) -> gleam@set:set(gleam@erlang@process:subject(HGG)).
get_group(Named, Name) ->
case gleam@dict:get(Named, Name) of
{ok, Subjects} ->
Subjects;
{error, nil} ->
gleam@set:new()
end.
-spec delete_named(state(HFS, HFT), HFS) -> state(HFS, HFT).
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(action(HGT, HGU)),
gleam@erlang@process:process_monitor(),
gleam@erlang@process:subject(HGU)
) -> gleam@erlang@process:selector(action(HGT, HGU)).
receive_process_down(Selector, Monitor, Subject) ->
Handle = fun(_) -> {demonitor, Subject} end,
gleam@erlang@process:selecting_process_down(Selector, Monitor, Handle).
-spec insert(state(HFE, HFF), gleam@erlang@process:subject(HFF)) -> state(HFE, HFF).
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(HFL, HFM), gleam@erlang@process:subject(HFM), HFL) -> state(HFL, HFM).
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(HGN, HGO)) -> state(HGN, HGO).
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(action(HEX, HEY), state(HEX, HEY)) -> gleam@otp@actor:next(action(HEX, HEY), state(HEX, HEY)).
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);
{lookup, Client@1, Name} ->
Subjects@1 = begin
_pipe = get_group(erlang:element(5, State), Name),
gleam@set:to_list(_pipe)
end,
gleam@erlang@process:send(Client@1, Subjects@1),
gleam@otp@actor:continue(State);
{register, Subject} ->
State@1 = insert(State, Subject),
_pipe@1 = gleam@otp@actor:continue(State@1),
gleam@otp@actor:with_selector(_pipe@1, erlang:element(6, State@1));
{register_as, Subject@1, Name@1} ->
State@2 = insert_as(State, Subject@1, Name@1),
_pipe@2 = gleam@otp@actor:continue(State@2),
gleam@otp@actor:with_selector(_pipe@2, 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@2} ->
State@4 = demonitor_subject(State, Subject@2),
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@3 = gleam@otp@actor:continue(State@5),
gleam@otp@actor:with_selector(_pipe@3, erlang:element(6, State@5));
{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_spec(
{spec, fun handle_init/0, 10, fun handle_message/2}
).