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([new/1, tag/2, group/2, register/2, find/2, dispatch/2, dispatch_group/3, start/0]).
-export_type([message/3, chip/3, state/3]).
-opaque message(GXW, GXX, GXY) :: {register, chip(GXW, GXX, GXY)} |
{demonitor, gleam@erlang@process:process_monitor(), chip(GXW, GXX, GXY)} |
{lookup,
gleam@erlang@process:subject({ok, gleam@erlang@process:subject(GXW)} |
{error, nil}),
GXX} |
{members,
gleam@erlang@process:subject(list(gleam@erlang@process:subject(GXW)))} |
{members_at,
gleam@erlang@process:subject(list(gleam@erlang@process:subject(GXW))),
GXY}.
-opaque chip(GXZ, GYA, GYB) :: {chip,
gleam@erlang@process:subject(GXZ),
gleam@option:option(GYA),
gleam@option:option(GYB)}.
-type state(GYC, GYD, GYE) :: {state,
gleam@erlang@process:selector(message(GYC, GYD, GYE)),
gleam@set:set(gleam@erlang@process:subject(GYC)),
gleam@dict:dict(GYD, gleam@erlang@process:subject(GYC)),
gleam@dict:dict(GYE, gleam@set:set(gleam@erlang@process:subject(GYC)))}.
-spec new(gleam@erlang@process:subject(GYU)) -> chip(GYU, any(), any()).
new(Subject) ->
{chip, Subject, none, none}.
-spec tag(chip(GZB, GZC, GZD), GZC) -> chip(GZB, GZC, GZD).
tag(Registrant, Tag) ->
erlang:setelement(3, Registrant, {some, Tag}).
-spec group(chip(GZK, GZL, GZM), GZM) -> chip(GZK, GZL, GZM).
group(Registrant, Group) ->
erlang:setelement(4, Registrant, {some, Group}).
-spec register(
gleam@erlang@process:subject(message(GZT, GZU, GZV)),
chip(GZT, GZU, GZV)
) -> nil.
register(Registry, Registrant) ->
gleam@erlang@process:send(Registry, {register, Registrant}).
-spec find(gleam@erlang@process:subject(message(HAC, HAD, any())), HAD) -> {ok,
gleam@erlang@process:subject(HAC)} |
{error, nil}.
find(Registry, Tag) ->
gleam@erlang@process:call(
Registry,
fun(_capture) -> {lookup, _capture, Tag} end,
10
).
-spec dispatch(
gleam@erlang@process:subject(message(HAM, any(), any())),
fun((gleam@erlang@process:subject(HAM)) -> any())
) -> nil.
dispatch(Registry, Callback) ->
Subjects = gleam@erlang@process:call(
Registry,
fun(_capture) -> {members, _capture} end,
10
),
gleam@list:each(Subjects, Callback).
-spec dispatch_group(
gleam@erlang@process:subject(message(HAU, any(), HAW)),
HAW,
fun((gleam@erlang@process:subject(HAU)) -> any())
) -> nil.
dispatch_group(Registry, Group, Callback) ->
Subjects = gleam@erlang@process:call(
Registry,
fun(_capture) -> {members_at, _capture, Group} end,
10
),
gleam@list:each(Subjects, Callback).
-spec init() -> gleam@otp@actor:init_result(state(HBC, HBD, HBE), message(HBC, HBD, HBE)).
init() ->
Selector = gleam_erlang_ffi:new_selector(),
{ready,
{state, Selector, gleam@set:new(), gleam@dict:new(), gleam@dict:new()},
Selector}.
-spec monitor(state(HCE, HCF, HCG), chip(HCE, HCF, HCG)) -> state(HCE, HCF, HCG).
monitor(State, Registrant) ->
Pid = gleam@erlang@process:subject_owner(erlang:element(2, Registrant)),
Monitor = gleam@erlang@process:monitor_process(Pid),
On_process_down = fun(_) -> {demonitor, Monitor, Registrant} end,
Selector = begin
_pipe = erlang:element(2, State),
gleam@erlang@process:selecting_process_down(
_pipe,
Monitor,
On_process_down
)
end,
erlang:setelement(2, State, Selector).
-spec into_registered(state(HCQ, HCR, HCS), chip(HCQ, HCR, HCS)) -> state(HCQ, HCR, HCS).
into_registered(State, Registrant) ->
Subjects = erlang:element(3, State),
Subject = erlang:element(2, Registrant),
erlang:setelement(3, State, gleam@set:insert(Subjects, Subject)).
-spec into_tagged(state(HDC, HDD, HDE), chip(HDC, HDD, HDE)) -> state(HDC, HDD, HDE).
into_tagged(State, Registrant) ->
case Registrant of
{chip, Subject, {some, Tag}, _} ->
Subjects = erlang:element(4, State),
Tagged = gleam@dict:insert(Subjects, Tag, Subject),
erlang:setelement(4, State, Tagged);
{chip, _, none, _} ->
State
end.
-spec into_grouped(state(HDO, HDP, HDQ), chip(HDO, HDP, HDQ)) -> state(HDO, HDP, HDQ).
into_grouped(State, Registrant) ->
Add_subject = fun(Option) -> case Option of
{some, Subjects} ->
gleam@set:insert(Subjects, erlang:element(2, Registrant));
none ->
gleam@set:insert(gleam@set:new(), erlang:element(2, Registrant))
end end,
case Registrant of
{chip, _, _, {some, Group}} ->
Grouped = gleam@dict:update(
erlang:element(5, State),
Group,
Add_subject
),
erlang:setelement(5, State, Grouped);
{chip, _, _, none} ->
State
end.
-spec remove_from_registered(state(HEA, HEB, HEC), chip(HEA, HEB, HEC)) -> state(HEA, HEB, HEC).
remove_from_registered(State, Registrant) ->
Registered = gleam@set:delete(
erlang:element(3, State),
erlang:element(2, Registrant)
),
erlang:setelement(3, State, Registered).
-spec remove_from_tagged(state(HEM, HEN, HEO), chip(HEM, HEN, HEO)) -> state(HEM, HEN, HEO).
remove_from_tagged(State, Registrant) ->
case Registrant of
{chip, _, {some, Tag}, _} ->
Tagged = gleam@dict:delete(erlang:element(4, State), Tag),
erlang:setelement(4, State, Tagged);
{chip, _, none, _} ->
State
end.
-spec remove_from_grouped(state(HEY, HEZ, HFA), chip(HEY, HEZ, HFA)) -> state(HEY, HEZ, HFA).
remove_from_grouped(State, Registrant) ->
case Registrant of
{chip, _, _, {some, Group}} ->
case gleam@dict:get(erlang:element(5, State), Group) of
{ok, Subjects} ->
Subjects@1 = gleam@set:delete(
Subjects,
erlang:element(2, Registrant)
),
Grouped = gleam@dict:insert(
erlang:element(5, State),
Group,
Subjects@1
),
erlang:setelement(5, State, Grouped);
{error, nil} ->
erlang:error(#{gleam_error => panic,
message => <<"Impossible state, group was not found on remove_from_grouped."/utf8>>,
module => <<"chip"/utf8>>,
function => <<"remove_from_grouped"/utf8>>,
line => 375})
end;
{chip, _, _, none} ->
State
end.
-spec loop(message(HBN, HBO, HBP), state(HBN, HBO, HBP)) -> gleam@otp@actor:next(message(HBN, HBO, HBP), state(HBN, HBO, HBP)).
loop(Message, State) ->
case Message of
{register, Registrant} ->
State@1 = monitor(State, Registrant),
State@2 = begin
_pipe = State@1,
_pipe@1 = monitor(_pipe, Registrant),
_pipe@2 = into_registered(_pipe@1, Registrant),
_pipe@3 = into_tagged(_pipe@2, Registrant),
into_grouped(_pipe@3, Registrant)
end,
{continue, State@2, {some, erlang:element(2, State@2)}};
{demonitor, Monitor, Registrant@1} ->
gleam_erlang_ffi:demonitor(Monitor),
_pipe@4 = State,
_pipe@5 = remove_from_registered(_pipe@4, Registrant@1),
_pipe@6 = remove_from_tagged(_pipe@5, Registrant@1),
_pipe@7 = remove_from_grouped(_pipe@6, Registrant@1),
{continue, _pipe@7, none};
{lookup, Client, Tag} ->
Result = gleam@dict:get(erlang:element(4, State), Tag),
gleam@erlang@process:send(Client, Result),
{continue, State, none};
{members, Client@1} ->
Subjects = gleam@set:to_list(erlang:element(3, State)),
gleam@erlang@process:send(Client@1, Subjects),
{continue, State, none};
{members_at, Client@2, Group} ->
Subjects@2 = case gleam@dict:get(erlang:element(5, State), Group) of
{ok, Subjects@1} ->
gleam@set:to_list(Subjects@1);
{error, nil} ->
[]
end,
gleam@erlang@process:send(Client@2, Subjects@2),
{continue, State, none}
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 init/0, 10, fun loop/2}).