Current section

Files

Jump to
chip src chip.erl
Raw

src/chip.erl

-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(GXW, GXX) :: {all,
gleam@erlang@process:subject(list(gleam@erlang@process:subject(GXX)))} |
{named,
gleam@erlang@process:subject(list({GXW,
gleam@erlang@process:subject(GXX)}))} |
{lookup,
gleam@erlang@process:subject(list(gleam@erlang@process:subject(GXX))),
GXW} |
{register, gleam@erlang@process:subject(GXX)} |
{register_as, gleam@erlang@process:subject(GXX), GXW} |
{deregister, GXW} |
{demonitor, gleam@erlang@process:subject(GXX)} |
rebuild_selector |
{stop, gleam@erlang@process:subject(gleam@erlang@process:exit_reason())}.
-type state(GXY, GXZ) :: {state,
gleam@erlang@process:subject(message(GXY, GXZ)),
gleam@dict:dict(gleam@erlang@process:pid_(), gleam@erlang@process:process_monitor()),
gleam@set:set(gleam@erlang@process:subject(GXZ)),
gleam@dict:dict(GXY, gleam@set:set(gleam@erlang@process:subject(GXZ))),
gleam@erlang@process:selector(message(GXY, GXZ))}.
-spec all(gleam@erlang@process:subject(message(any(), GYI))) -> list(gleam@erlang@process:subject(GYI)).
all(Registry) ->
gleam@erlang@process:call(
Registry,
fun(_capture) -> {all, _capture} end,
100
).
-spec named(gleam@erlang@process:subject(message(GYO, GYP))) -> list({GYO,
gleam@erlang@process:subject(GYP)}).
named(Registry) ->
gleam@erlang@process:call(
Registry,
fun(_capture) -> {named, _capture} end,
100
).
-spec lookup(gleam@erlang@process:subject(message(GYV, GYW)), GYV) -> list(gleam@erlang@process:subject(GYW)).
lookup(Registry, Name) ->
gleam@erlang@process:call(
Registry,
fun(_capture) -> {lookup, _capture, Name} end,
100
).
-spec register(
gleam@erlang@process:subject(message(any(), GZD)),
fun(() -> {ok, gleam@erlang@process:subject(GZD)} |
{error, gleam@otp@actor:start_error()})
) -> {ok, gleam@erlang@process:subject(GZD)} |
{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(GZN, GZO)),
GZN,
fun(() -> {ok, gleam@erlang@process:subject(GZO)} |
{error, gleam@otp@actor:start_error()})
) -> {ok, gleam@erlang@process:subject(GZO)} |
{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(GZY, any())), GZY) -> 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(HAI, HAJ), message(HAI, HAJ)).
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(HBR, HBS), gleam@erlang@process:subject(HBS)) -> state(HBR, HBS).
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(HBY, gleam@set:set(gleam@erlang@process:subject(HBZ))),
HBY
) -> gleam@set:set(gleam@erlang@process:subject(HBZ)).
get_group(Named, Name) ->
case gleam@dict:get(Named, Name) of
{ok, Subjects} ->
Subjects;
{error, nil} ->
gleam@set:new()
end.
-spec delete_named(state(HBL, HBM), HBL) -> state(HBL, HBM).
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(HCM, HCN)),
gleam@erlang@process:process_monitor(),
gleam@erlang@process:subject(HCN)
) -> gleam@erlang@process:selector(message(HCM, HCN)).
receive_process_down(Selector, Monitor, Subject) ->
Handle = fun(_) -> {demonitor, Subject} end,
gleam@erlang@process:selecting_process_down(Selector, Monitor, Handle).
-spec insert(state(HAX, HAY), gleam@erlang@process:subject(HAY)) -> state(HAX, HAY).
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(HBE, HBF), gleam@erlang@process:subject(HBF), HBE) -> state(HBE, HBF).
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(HCG, HCH)) -> state(HCG, HCH).
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(HAQ, HAR), state(HAQ, HAR)) -> gleam@otp@actor:next(message(HAQ, HAR), state(HAQ, HAR)).
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}
).