Current section
Files
Jump to
Current section
Files
src/chip@group.erl
-module(chip@group).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([register/3, members/2, dispatch/3, start/0]).
-export_type([message/2, index/0, location/2, state/2]).
-opaque message(GXW, GXX) :: {grouped_subjects,
gleam@erlang@process:subject(list(gleam@erlang@process:subject(GXX))),
GXW} |
{grouped_registrant, gleam@erlang@process:subject(GXX), GXW} |
{demonitor, index()}.
-type index() :: {index,
gleam@erlang@process:pid_(),
gleam@erlang@process:process_monitor()}.
-type location(GXY, GXZ) :: {location, GXY, gleam@erlang@process:subject(GXZ)}.
-type state(GYA, GYB) :: {state,
gleam@erlang@process:subject(message(GYA, GYB)),
gleam@dict:dict(GYA, gleam@set:set(gleam@erlang@process:subject(GYB))),
gleam@dict:dict(gleam@erlang@process:pid_(), gleam@set:set(location(GYA, GYB))),
gleam@erlang@process:selector(message(GYA, GYB))}.
-spec register(
gleam@erlang@process:subject(message(GYN, GYO)),
gleam@erlang@process:subject(GYO),
GYN
) -> nil.
register(Registry, Subject, Group) ->
gleam@erlang@process:send(Registry, {grouped_registrant, Subject, Group}).
-spec members(gleam@erlang@process:subject(message(GYU, GYV)), GYU) -> list(gleam@erlang@process:subject(GYV)).
members(Registry, Group) ->
gleam@erlang@process:call(
Registry,
fun(_capture) -> {grouped_subjects, _capture, Group} end,
10
).
-spec dispatch(
gleam@erlang@process:subject(message(GYY, GYZ)),
GYY,
fun((gleam@erlang@process:subject(GYZ)) -> any())
) -> nil.
dispatch(Registry, Group, Callback) ->
Subjects = members(Registry, Group),
gleam@list:each(Subjects, fun(Subject) -> Callback(Subject) end).
-spec handle_init() -> gleam@otp@actor:init_result(state(HDL, HDK), message(HDL, HDK)).
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_group(state(GZN, GZO), GZN, gleam@erlang@process:subject(GZO)) -> state(GZN, GZO).
into_group(State, Group, Subject) ->
Add_subject = fun(Option) -> case Option of
{some, Subjects} ->
gleam@set:insert(Subjects, Subject);
none ->
gleam@set:insert(gleam@set:new(), Subject)
end end,
erlang:setelement(
3,
State,
gleam@dict:update(erlang:element(3, State), Group, Add_subject)
).
-spec into_tracker(
state(GZU, GZV),
gleam@erlang@process:pid_(),
location(GZU, GZV)
) -> state(GZU, GZV).
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(HAC, HAD),
gleam@option:option(gleam@erlang@process:selector(message(HAC, HAD)))
) -> state(HAC, HAD).
into_selector(State, Selection) ->
case Selection of
{some, Selector} ->
erlang:setelement(5, State, Selector);
none ->
State
end.
-spec remove_from_group(state(HAM, HAN), gleam@erlang@process:pid_()) -> state(HAM, HAN).
remove_from_group(State, Pid) ->
Locations@1 = 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/group"/utf8>>,
function => <<"remove_from_group"/utf8>>,
line => 228})
end,
gleam@list:fold(
Locations@1,
State,
fun(State@1, Location) ->
{location, Group, Subject} = Location,
case gleam@dict:get(erlang:element(3, State@1), Group) of
{ok, Subjects} ->
Subjects@1 = gleam@set:delete(Subjects, Subject),
Groups = gleam@dict:insert(
erlang:element(3, State@1),
Group,
Subjects@1
),
erlang:setelement(3, State@1, Groups);
{error, nil} ->
erlang:error(#{gleam_error => panic,
message => <<"Impossible state, couldn't find the group when removing."/utf8>>,
module => <<"chip/group"/utf8>>,
function => <<"remove_from_group"/utf8>>,
line => 243})
end
end
).
-spec remove_from_tracker(state(HAS, HAT), gleam@erlang@process:pid_()) -> state(HAS, HAT).
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(HBG, HBH)),
gleam@erlang@process:pid_(),
gleam@erlang@process:process_monitor()
) -> gleam@erlang@process:selector(message(HBG, HBH)).
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(HAY, HAZ), gleam@erlang@process:pid_()) -> gleam@option:option(gleam@erlang@process:selector(message(HAY, HAZ))).
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(GZG, GZH), state(GZG, GZH)) -> gleam@otp@actor:next(message(GZG, GZH), state(GZG, GZH)).
handle_message(Message, State) ->
case Message of
{grouped_subjects, Client, Group} ->
Subjects@1 = case gleam@dict:get(erlang:element(3, State), Group) of
{ok, Subjects} ->
gleam@set:to_list(Subjects);
{error, nil} ->
[]
end,
gleam@erlang@process:send(Client, Subjects@1),
gleam@otp@actor:continue(State);
{grouped_registrant, Subject, Group@1} ->
Pid = gleam@erlang@process:subject_owner(Subject),
Selection = monitor(State, Pid),
_pipe = State,
_pipe@1 = into_group(_pipe, Group@1, Subject),
_pipe@2 = into_tracker(_pipe@1, Pid, {location, Group@1, Subject}),
_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}
).