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([register/3, find/2, group/3, members/2, broadcast/3, start/0]).
-export_type([message/3, index/0, subject_location/3, state/3]).
-opaque message(GXW, GXX, GXY) :: {named_subject,
gleam@erlang@process:subject({ok, gleam@erlang@process:subject(GXY)} |
{error, nil}),
GXW} |
{named_registrant, gleam@erlang@process:subject(GXY), GXW} |
{grouped_subjects,
gleam@erlang@process:subject(list(gleam@erlang@process:subject(GXY))),
GXX} |
{grouped_registrant, gleam@erlang@process:subject(GXY), GXX} |
{demonitor, index()}.
-type index() :: {index,
gleam@erlang@process:pid_(),
gleam@erlang@process:process_monitor()}.
-type subject_location(GXZ, GYA, GYB) :: {named_location, GXZ} |
{grouped_location, GYA, gleam@erlang@process:subject(GYB)}.
-type state(GYC, GYD, GYE) :: {state,
gleam@erlang@process:subject(message(GYC, GYD, GYE)),
gleam@dict:dict(GYC, gleam@erlang@process:subject(GYE)),
gleam@dict:dict(GYD, gleam@set:set(gleam@erlang@process:subject(GYE))),
gleam@dict:dict(gleam@erlang@process:pid_(), gleam@set:set(subject_location(GYC, GYD, GYE))),
gleam@erlang@process:selector(message(GYC, GYD, GYE))}.
-spec register(
gleam@erlang@process:subject(message(GYU, any(), GYW)),
gleam@erlang@process:subject(GYW),
GYU
) -> nil.
register(Registry, Subject, Name) ->
gleam@erlang@process:send(Registry, {named_registrant, Subject, Name}).
-spec find(gleam@erlang@process:subject(message(GZD, any(), GZE)), GZD) -> {ok,
gleam@erlang@process:subject(GZE)} |
{error, nil}.
find(Registry, Name) ->
gleam@erlang@process:call(
Registry,
fun(_capture) -> {named_subject, _capture, Name} end,
10
).
-spec group(
gleam@erlang@process:subject(message(any(), GZJ, GZK)),
gleam@erlang@process:subject(GZK),
GZJ
) -> nil.
group(Registry, Subject, Group) ->
gleam@erlang@process:send(Registry, {grouped_registrant, Subject, Group}).
-spec members(gleam@erlang@process:subject(message(any(), GZR, GZS)), GZR) -> list(gleam@erlang@process:subject(GZS)).
members(Registry, Group) ->
gleam@erlang@process:call(
Registry,
fun(_capture) -> {grouped_subjects, _capture, Group} end,
10
).
-spec broadcast(
gleam@erlang@process:subject(message(any(), GZW, GZX)),
GZW,
fun((gleam@erlang@process:subject(GZX)) -> any())
) -> nil.
broadcast(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(HGZ, HHB, HGY), message(HGZ, HHB, HGY)).
handle_init() ->
Self = gleam@erlang@process:new_subject(),
State = {state,
Self,
gleam@dict:new(),
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(6, State)}.
-spec into_names(state(HAP, HAQ, HAR), HAP, gleam@erlang@process:subject(HAR)) -> state(HAP, HAQ, HAR).
into_names(State, Name, Subject) ->
erlang:setelement(
3,
State,
gleam@dict:insert(erlang:element(3, State), Name, Subject)
).
-spec into_group(state(HAZ, HBA, HBB), HBA, gleam@erlang@process:subject(HBB)) -> state(HAZ, HBA, HBB).
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(
4,
State,
gleam@dict:update(erlang:element(4, State), Group, Add_subject)
).
-spec into_tracker(
state(HBJ, HBK, HBL),
gleam@erlang@process:pid_(),
subject_location(HBJ, HBK, HBL)
) -> state(HBJ, HBK, HBL).
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(
5,
State,
gleam@dict:update(erlang:element(5, State), Pid, Add_location)
).
-spec into_selector(
state(HBV, HBW, HBX),
gleam@option:option(gleam@erlang@process:selector(message(HBV, HBW, HBX)))
) -> state(HBV, HBW, HBX).
into_selector(State, Selection) ->
case Selection of
{some, Selector} ->
erlang:setelement(6, State, Selector);
none ->
State
end.
-spec remove_from_group(state(HCJ, HCK, HCL), gleam@erlang@process:pid_()) -> state(HCJ, HCK, HCL).
remove_from_group(State, Pid) ->
Locations@1 = case gleam@dict:get(erlang:element(5, 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"/utf8>>,
function => <<"remove_from_group"/utf8>>,
line => 292})
end,
gleam@list:fold(
Locations@1,
State,
fun(State@1, Location) -> case Location of
{grouped_location, Group, Subject} ->
case gleam@dict:get(erlang:element(4, State@1), Group) of
{ok, Subjects} ->
Subjects@1 = gleam@set:delete(Subjects, Subject),
Groups = gleam@dict:insert(
erlang:element(4, State@1),
Group,
Subjects@1
),
erlang:setelement(4, State@1, Groups);
{error, nil} ->
erlang:error(#{gleam_error => panic,
message => <<"Impossible state, couldn't find the group when removing."/utf8>>,
module => <<"chip"/utf8>>,
function => <<"remove_from_group"/utf8>>,
line => 307})
end;
{named_location, Name} ->
Names = gleam@dict:delete(erlang:element(3, State@1), Name),
erlang:setelement(3, State@1, Names)
end end
).
-spec remove_from_tracker(state(HCS, HCT, HCU), gleam@erlang@process:pid_()) -> state(HCS, HCT, HCU).
remove_from_tracker(State, Pid) ->
erlang:setelement(
5,
State,
gleam@dict:delete(erlang:element(5, State), Pid)
).
-spec select_process_down(
gleam@erlang@process:selector(message(HDM, HDN, HDO)),
gleam@erlang@process:pid_(),
gleam@erlang@process:process_monitor()
) -> gleam@erlang@process:selector(message(HDM, HDN, HDO)).
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(HDB, HDC, HDD), gleam@erlang@process:pid_()) -> gleam@option:option(gleam@erlang@process:selector(message(HDB, HDC, HDD))).
monitor(State, Pid) ->
case gleam@dict:get(erlang:element(5, State), Pid) of
{ok, _} ->
none;
{error, nil} ->
Monitor = gleam@erlang@process:monitor_process(Pid),
Selector = select_process_down(
erlang:element(6, State),
Pid,
Monitor
),
{some, Selector}
end.
-spec handle_message(message(HAF, HAG, HAH), state(HAF, HAG, HAH)) -> gleam@otp@actor:next(message(HAF, HAG, HAH), state(HAF, HAG, HAH)).
handle_message(Message, State) ->
case Message of
{named_subject, Client, Name} ->
Result = gleam@dict:get(erlang:element(3, State), Name),
gleam@erlang@process:send(Client, Result),
gleam@otp@actor:continue(State);
{named_registrant, Subject, Name@1} ->
Pid = gleam@erlang@process:subject_owner(Subject),
Selection = monitor(State, Pid),
_pipe = State,
_pipe@1 = into_names(_pipe, Name@1, Subject),
_pipe@2 = into_tracker(_pipe@1, Pid, {named_location, Name@1}),
_pipe@3 = into_selector(_pipe@2, Selection),
{continue, _pipe@3, Selection};
{grouped_subjects, Client@1, Group} ->
Subjects@1 = case gleam@dict:get(erlang:element(4, State), Group) of
{ok, Subjects} ->
gleam@set:to_list(Subjects);
{error, nil} ->
[]
end,
gleam@erlang@process:send(Client@1, Subjects@1),
gleam@otp@actor:continue(State);
{grouped_registrant, Subject@1, Group@1} ->
Pid@1 = gleam@erlang@process:subject_owner(Subject@1),
Selection@1 = monitor(State, Pid@1),
_pipe@4 = State,
_pipe@5 = into_group(_pipe@4, Group@1, Subject@1),
_pipe@6 = into_tracker(
_pipe@5,
Pid@1,
{grouped_location, Group@1, Subject@1}
),
_pipe@7 = into_selector(_pipe@6, Selection@1),
{continue, _pipe@7, Selection@1};
{demonitor, {index, Pid@2, Monitor}} ->
gleam_erlang_ffi:demonitor(Monitor),
_pipe@8 = State,
_pipe@9 = remove_from_group(_pipe@8, Pid@2),
_pipe@10 = remove_from_tracker(_pipe@9, Pid@2),
gleam@otp@actor:continue(_pipe@10)
end.
-spec start() -> {ok,
gleam@erlang@process:subject(message(any(), any(), any()))} |
{error, gleam@otp@actor:start_error()}.
start() ->
gleam@otp@actor:start_spec(
{spec, fun handle_init/0, 10, fun handle_message/2}
).