-module(gleam@erlang@process). -compile(no_auto_import). -export([self/0, start/2, new_subject/0, subject_owner/1, send/2, 'receive'/2, new_selector/0, select/2, selecting/3, selecting_subjectless_record/4, sleep/1, sleep_forever/0, is_alive/1, monitor_process/1, selecting_process_down/3, demonitor_process/1, try_call/3, call/3]). -export_type([pid_/0, subject/1, do_not_leak/0, selector/1, process_monitor_flag/0, process_monitor/0, process_down/0, call_error/1]). -type pid_() :: any(). -opaque subject(EKU) :: {subject, pid_(), gleam@erlang:reference_()} | {gleam_phantom, EKU}. -type do_not_leak() :: any(). -type selector(Payload) :: any() | {gleam_phantom, Payload}. -type process_monitor_flag() :: process. -opaque process_monitor() :: {process_monitor, gleam@erlang:reference_()}. -type process_down() :: {process_down, pid_(), gleam@dynamic:dynamic()}. -type call_error(EKW) :: {callee_down, gleam@dynamic:dynamic()} | call_timeout | {gleam_phantom, EKW}. -spec self() -> pid_(). self() -> erlang:self(). -spec start(fun(() -> any()), boolean()) -> pid_(). start(Implementation, Link) -> case Link of true -> erlang:spawn_link(Implementation); false -> erlang:spawn(Implementation) end. -spec new_subject() -> subject(any()). new_subject() -> {subject, erlang:self(), gleam@erlang:make_reference()}. -spec subject_owner(subject(any())) -> pid_(). subject_owner(Subject) -> erlang:element(2, Subject). -spec send(subject(ELF), ELF) -> nil. send(Subject, Message) -> erlang:send( erlang:element(2, Subject), {erlang:element(3, Subject), Message} ), nil. -spec 'receive'(subject(ELH), integer()) -> {ok, ELH} | {error, nil}. 'receive'(Subject, Milliseconds) -> _pipe = gleam_erlang_ffi:new_selector(), _pipe@1 = selecting(_pipe, Subject, fun(X) -> X end), gleam_erlang_ffi:select(_pipe@1, Milliseconds). -spec new_selector() -> selector(any()). new_selector() -> gleam_erlang_ffi:new_selector(). -spec select(selector(ELN), integer()) -> {ok, ELN} | {error, nil}. select(A, B) -> gleam_erlang_ffi:select(A, B). -spec selecting(selector(ELR), subject(ELT), fun((ELT) -> ELR)) -> selector(ELR). selecting(Selector, Subject, Transform) -> Handler = fun(Message) -> Transform(erlang:element(2, Message)) end, gleam_erlang_ffi:insert_selector_handler( Selector, {erlang:element(3, Subject), 2}, Handler ). -spec selecting_subjectless_record( selector(ELW), any(), integer(), fun((gleam@dynamic:dynamic()) -> ELW) ) -> selector(ELW). selecting_subjectless_record(Selector, Tag, Size, Transform) -> gleam_erlang_ffi:insert_selector_handler(Selector, {Tag, Size}, Transform). -spec sleep(integer()) -> nil. sleep(A) -> gleam_erlang_ffi:sleep(A). -spec sleep_forever() -> nil. sleep_forever() -> gleam_erlang_ffi:sleep_forever(). -spec is_alive(pid_()) -> boolean(). is_alive(A) -> erlang:is_process_alive(A). -spec monitor_process(pid_()) -> process_monitor(). monitor_process(Pid) -> _pipe = process, _pipe@1 = erlang:monitor(_pipe, Pid), {process_monitor, _pipe@1}. -spec selecting_process_down( selector(EMF), process_monitor(), fun((process_down()) -> EMF) ) -> selector(EMF). selecting_process_down(Selector, Monitor, Mapping) -> gleam_erlang_ffi:insert_selector_handler( Selector, erlang:element(2, Monitor), Mapping ). -spec demonitor_process(process_monitor()) -> nil. demonitor_process(A) -> gleam_erlang_ffi:demonitor(A). -spec try_call(subject(EMI), fun((subject(EMK)) -> EMI), integer()) -> {ok, EMK} | {error, call_error(EMK)}. try_call(Subject, Make_request, Timeout) -> Reply_subject = new_subject(), Monitor = monitor_process(subject_owner(Subject)), send(Subject, Make_request(Reply_subject)), Result = begin _pipe = gleam_erlang_ffi:new_selector(), _pipe@1 = selecting(_pipe, Reply_subject, fun(A) -> {ok, A} end), _pipe@2 = selecting_process_down( _pipe@1, Monitor, fun(Down) -> {error, {callee_down, erlang:element(3, Down)}} end ), gleam_erlang_ffi:select(_pipe@2, Timeout) end, gleam_erlang_ffi:demonitor(Monitor), case Result of {error, nil} -> {error, call_timeout}; {ok, Res} -> Res end. -spec call(subject(EMP), fun((subject(EMR)) -> EMP), integer()) -> EMR. call(Subject, Make_request, Timeout) -> {ok, Resp@1} = case try_call(Subject, Make_request, Timeout) of {ok, Resp} -> {ok, Resp}; _try -> erlang:error(#{gleam_error => assert, message => <<"Assertion pattern match failed"/utf8>>, value => _try, module => <<"gleam/erlang/process"/utf8>>, function => <<"call"/utf8>>, line => 371}) end, Resp@1.