-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}).