Current section

Files

Jump to
gleam_erlang src gleam@erlang@process.erl
Raw

src/gleam@erlang@process.erl

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