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([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(HFB, HFC, HFD) :: {register, chip(HFB, HFC, HFD)} |
{demonitor, gleam@erlang@process:process_monitor(), chip(HFB, HFC, HFD)} |
{lookup,
gleam@erlang@process:subject({ok, gleam@erlang@process:subject(HFB)} |
{error, nil}),
HFC} |
{members,
gleam@erlang@process:subject(list(gleam@erlang@process:subject(HFB)))} |
{members_at,
gleam@erlang@process:subject(list(gleam@erlang@process:subject(HFB))),
HFD}.
-opaque chip(HFE, HFF, HFG) :: {chip,
gleam@erlang@process:subject(HFE),
gleam@option:option(HFF),
gleam@option:option(HFG)}.
-type state(HFH, HFI, HFJ) :: {state,
gleam@erlang@process:selector(message(HFH, HFI, HFJ)),
gleam@set:set(gleam@erlang@process:subject(HFH)),
gleam@dict:dict(HFI, gleam@erlang@process:subject(HFH)),
gleam@dict:dict(HFJ, gleam@set:set(gleam@erlang@process:subject(HFH)))}.
-spec new(gleam@erlang@process:subject(HFZ)) -> chip(HFZ, any(), any()).
new(Subject) ->
{chip, Subject, none, none}.
-spec tag(chip(HGG, HGH, HGI), HGH) -> chip(HGG, HGH, HGI).
tag(Registrant, Tag) ->
erlang:setelement(3, Registrant, {some, Tag}).
-spec group(chip(HGP, HGQ, HGR), HGR) -> chip(HGP, HGQ, HGR).
group(Registrant, Group) ->
erlang:setelement(4, Registrant, {some, Group}).
-spec register(
gleam@erlang@process:subject(message(HGY, HGZ, HHA)),
chip(HGY, HGZ, HHA)
) -> nil.
register(Registry, Registrant) ->
gleam@erlang@process:send(Registry, {register, Registrant}).
-spec find(gleam@erlang@process:subject(message(HHH, HHI, any())), HHI) -> {ok,
gleam@erlang@process:subject(HHH)} |
{error, nil}.
find(Registry, Tag) ->
gleam@erlang@process:call(
Registry,
fun(_capture) -> {lookup, _capture, Tag} end,
10
).
-spec dispatch(
gleam@erlang@process:subject(message(HHR, any(), any())),
fun((gleam@erlang@process:subject(HHR)) -> 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(HHZ, any(), HIB)),
HIB,
fun((gleam@erlang@process:subject(HHZ)) -> 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(HIH, HII, HIJ), message(HIH, HII, HIJ)).
init() ->
Selector = gleam_erlang_ffi:new_selector(),
{ready,
{state, Selector, gleam@set:new(), gleam@dict:new(), gleam@dict:new()},
Selector}.
-spec monitor(state(HJJ, HJK, HJL), chip(HJJ, HJK, HJL)) -> state(HJJ, HJK, HJL).
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(HJV, HJW, HJX), chip(HJV, HJW, HJX)) -> state(HJV, HJW, HJX).
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(HKH, HKI, HKJ), chip(HKH, HKI, HKJ)) -> state(HKH, HKI, HKJ).
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(HKT, HKU, HKV), chip(HKT, HKU, HKV)) -> state(HKT, HKU, HKV).
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(HLF, HLG, HLH), chip(HLF, HLG, HLH)) -> state(HLF, HLG, HLH).
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(HLR, HLS, HLT), chip(HLR, HLS, HLT)) -> state(HLR, HLS, HLT).
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(HMD, HME, HMF), chip(HMD, HME, HMF)) -> state(HMD, HME, HMF).
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(HIS, HIT, HIU), state(HIS, HIT, HIU)) -> gleam@otp@actor:next(message(HIS, HIT, HIU), state(HIS, HIT, HIU)).
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}).