Current section

Files

Jump to
gleam_otp src gleam@otp@actor.erl
Raw

src/gleam@otp@actor.erl

-module(gleam@otp@actor).
-compile(no_auto_import).
-export([to_erlang_start_result/1, from_erlang_start_result/1, wrap_erlang_starter/1, start_spec/1, start/2, send/2, call/3, pid/1]).
-export_type([message/1, next/1, init_result/2, self/2, spec/2, start_error/0, start_init_message/1]).
-type message(ETR) :: {message, ETR} |
{system, gleam@otp@process:system_message()}.
-type next(ETS) :: {continue, ETS} | {stop, gleam@otp@process:exit_reason()}.
-type init_result(ETT, ETU) :: {ready,
ETT,
gleam@option:option(gleam@otp@process:receiver(ETU))} |
{failed, gleam@otp@process:exit_reason()}.
-type self(ETV, ETW) :: {self,
gleam@otp@process:pid_(),
gleam@otp@process:mode(),
gleam@otp@process:pid_(),
ETV,
gleam@otp@process:receiver(message(ETW)),
gleam@otp@process:debug_state(),
fun((ETW, ETV) -> next(ETV))}.
-type spec(ETX, ETY) :: {spec,
fun(() -> init_result(ETX, ETY)),
integer(),
fun((ETY, ETX) -> next(ETX))}.
-type start_error() :: init_timeout |
{init_failed, gleam@otp@process:exit_reason()} |
{init_crashed, gleam@dynamic:dynamic()}.
-type start_init_message(EUF) :: {ack,
{ok, gleam@otp@process:sender(EUF)} |
{error, gleam@otp@process:exit_reason()}} |
{mon, gleam@otp@process:process_down()}.
-spec exit_process(gleam@otp@process:exit_reason()) -> gleam@otp@process:exit_reason().
exit_process(Reason) ->
Reason.
-spec receive_message(self(any(), EUV)) -> message(EUV).
receive_message(Self) ->
System_receiver = begin
_pipe = gleam@otp@process:system_receiver(),
gleam@otp@process:map_receiver(_pipe, fun(A) -> {system, A} end)
end,
Receiver = case erlang:element(3, Self) of
suspended ->
System_receiver;
running ->
_pipe@1 = erlang:element(6, Self),
gleam@otp@process:merge_receiver(_pipe@1, System_receiver)
end,
gleam@otp@process:receive_forever(Receiver).
-spec process_status_info(self(any(), any())) -> gleam@otp@process:status_info().
process_status_info(Self) ->
{status_info,
gleam@erlang@atom:create_from_string(<<"gleam@otp@actor"/utf8>>),
erlang:element(4, Self),
erlang:element(3, Self),
erlang:element(7, Self),
gleam@dynamic:from(erlang:element(5, Self))}.
-spec loop(self(any(), any())) -> gleam@otp@process:exit_reason().
loop(Self) ->
case receive_message(Self) of
{system, {get_state, Caller}} ->
gleam@otp@process:send(
Caller,
gleam@dynamic:from(erlang:element(5, Self))
),
loop(Self);
{system, {resume, Caller@1}} ->
gleam@otp@process:send(Caller@1, nil),
loop(erlang:setelement(3, Self, running));
{system, {suspend, Caller@2}} ->
gleam@otp@process:send(Caller@2, nil),
loop(erlang:setelement(3, Self, suspended));
{system, {get_status, Caller@3}} ->
gleam@otp@process:send(Caller@3, process_status_info(Self)),
loop(Self);
{message, Msg} ->
case (erlang:element(8, Self))(Msg, erlang:element(5, Self)) of
{stop, Reason} ->
exit_process(Reason);
{continue, State} ->
loop(erlang:setelement(5, Self, State))
end;
_@1 ->
gleam@io:println(
<<"Gleam Action: unsupported system message dropped"/utf8>>
),
loop(Self)
end.
-spec merge_extra_receiver(
gleam@otp@process:receiver(message(EZT)),
gleam@option:option(gleam@otp@process:receiver(EZT))
) -> gleam@otp@process:receiver(message(EZT)).
merge_extra_receiver(R1, R2) ->
case R2 of
none ->
R1;
{some, R2@1} ->
gleam@otp@process:merge_receiver(
R1,
gleam@otp@process:map_receiver(R2@1, fun(A) -> {message, A} end)
)
end.
-spec initialise_actor(
spec(any(), EVL),
gleam@otp@process:sender({ok, gleam@otp@process:sender(EVL)} |
{error, gleam@otp@process:exit_reason()})
) -> gleam@otp@process:exit_reason().
initialise_actor(Spec, Ack_channel) ->
{Sender, Receiver} = gleam@otp@process:new_channel(),
Receiver@1 = gleam@otp@process:map_receiver(
Receiver,
fun(A) -> {message, A} end
),
case (erlang:element(2, Spec))() of
{ready, State, Extra_receiver} ->
gleam@otp@process:send(Ack_channel, {ok, Sender}),
Self = {self,
gleam@otp@process:self(),
running,
gleam@otp@process:pid(Ack_channel),
State,
merge_extra_receiver(Receiver@1, Extra_receiver),
gleam@otp@process:debug_state([]),
erlang:element(4, Spec)},
loop(Self);
{failed, Reason} ->
gleam@otp@process:send(Ack_channel, {error, Reason}),
exit_process(Reason)
end.
-spec to_erlang_start_result(
{ok, gleam@otp@process:sender(any())} | {error, start_error()}
) -> {ok, gleam@otp@process:pid_()} | {error, gleam@dynamic:dynamic()}.
to_erlang_start_result(Res) ->
case Res of
{ok, X} ->
{ok, gleam@otp@process:pid(X)};
{error, X@1} ->
{error, gleam@dynamic:from(X@1)}
end.
-spec from_erlang_start_result({ok, gleam@otp@process:pid_()} | {error, any()}) -> {ok,
gleam@otp@process:sender(any())} |
{error, start_error()}.
from_erlang_start_result(Start) ->
case Start of
{ok, Pid} ->
{ok, gleam@otp@process:null_sender(Pid)};
{error, Error} ->
{error, {init_crashed, gleam@dynamic:from(Error)}}
end.
-spec wrap_erlang_starter(
fun(() -> {ok, gleam@otp@process:pid_()} | {error, any()})
) -> fun(() -> {ok, gleam@otp@process:sender(any())} | {error, start_error()}).
wrap_erlang_starter(Start) ->
fun() -> from_erlang_start_result(Start()) end.
-spec start_spec(spec(any(), EWJ)) -> {ok, gleam@otp@process:sender(EWJ)} |
{error, start_error()}.
start_spec(Spec) ->
{Ack_sender, Ack_receiver} = gleam@otp@process:new_channel(),
Child = gleam@otp@process:start(
fun() -> initialise_actor(Spec, Ack_sender) end
),
Receiver = begin
_pipe = Ack_receiver,
_pipe@1 = gleam@otp@process:map_receiver(_pipe, fun(A) -> {ack, A} end),
gleam@otp@process:merge_receiver(
_pipe@1,
begin
_pipe@2 = Child,
_pipe@3 = gleam@otp@process:monitor_process(_pipe@2),
gleam@otp@process:map_receiver(_pipe@3, fun(A) -> {mon, A} end)
end
)
end,
case gleam@otp@process:'receive'(Receiver, erlang:element(3, Spec)) of
{ok, {ack, {ok, Channel}}} ->
gleam@otp@process:close_channels(Receiver),
{ok, Channel};
{ok, {ack, {error, Reason}}} ->
gleam@otp@process:close_channels(Receiver),
{error, {init_failed, Reason}};
{ok, {mon, Down}} ->
gleam@otp@process:close_channels(Receiver),
{error, {init_crashed, erlang:element(3, Down)}};
{error, nil} ->
gleam@otp@process:kill(Child),
gleam@otp@process:close_channels(Receiver),
{error, init_timeout}
end.
-spec start(EWP, fun((EWQ, EWP) -> next(EWP))) -> {ok,
gleam@otp@process:sender(EWQ)} |
{error, start_error()}.
start(State, Loop) ->
start_spec({spec, fun() -> {ready, State, none} end, 5000, Loop}).
-spec send(gleam@otp@process:sender(EWV), EWV) -> gleam@otp@process:sender(EWV).
send(Channel, Msg) ->
gleam@otp@process:send(Channel, Msg).
-spec call(
gleam@otp@process:sender(EWY),
fun((gleam@otp@process:sender(EXA)) -> EWY),
integer()
) -> EXA.
call(Receiver, Make_message, Timeout) ->
gleam@otp@process:call(Receiver, Make_message, Timeout).
-spec pid(gleam@otp@process:sender(any())) -> gleam@otp@process:pid_().
pid(Sender) ->
gleam@otp@process:pid(Sender).