-module(scamper@actor). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/scamper/actor.gleam"). -export([start/3, send_event/3, get_state/2, get_context/2, get_machine/2]). -export_type([message/3]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC( " OTP actor wrapper for scamper FSMs.\n" "\n" " Provides a thin wrapper around `gleam/otp/actor` to run a state machine\n" " as an OTP-compatible process. Events are serialized (processed one at a\n" " time) and the pure FSM logic remains fully testable without OTP.\n" ). -opaque message(ICS, ICT, ICU) :: {send_event, ICU, gleam@erlang@process:subject({ok, scamper:machine(ICS, ICT, ICU)} | {error, scamper@error:transition_error(ICS, ICU)})} | {get_state, gleam@erlang@process:subject(ICS)} | {get_context, gleam@erlang@process:subject(ICT)} | {get_machine, gleam@erlang@process:subject(scamper:machine(ICS, ICT, ICU))}. -file("src/scamper/actor.gleam", 42). -spec handle_message(scamper:machine(IDI, IDJ, IDK), message(IDI, IDJ, IDK)) -> gleam@otp@actor:next(scamper:machine(IDI, IDJ, IDK), message(IDI, IDJ, IDK)). handle_message(Machine, Message) -> case Message of {send_event, Event, Reply_to} -> Result = scamper:transition(Machine, Event), gleam@erlang@process:send(Reply_to, Result), case Result of {ok, New_machine} -> gleam@otp@actor:continue(New_machine); {error, _} -> gleam@otp@actor:continue(Machine) end; {get_state, Reply_to@1} -> gleam@erlang@process:send( Reply_to@1, scamper:current_state(Machine) ), gleam@otp@actor:continue(Machine); {get_context, Reply_to@2} -> gleam@erlang@process:send( Reply_to@2, scamper:current_context(Machine) ), gleam@otp@actor:continue(Machine); {get_machine, Reply_to@3} -> gleam@erlang@process:send(Reply_to@3, Machine), gleam@otp@actor:continue(Machine) end. -file("src/scamper/actor.gleam", 28). ?DOC( " Start an FSM actor process.\n" " Returns the actor's subject for sending messages.\n" ). -spec start(scamper@config:config(ICV, ICW, ICX), ICV, ICW) -> {ok, gleam@otp@actor:started(gleam@erlang@process:subject(message(ICV, ICW, ICX)))} | {error, gleam@otp@actor:start_error()}. start(Config, Initial_state, Context) -> Machine = scamper:new(Config, Initial_state, Context), _pipe = gleam@otp@actor:new(Machine), _pipe@1 = gleam@otp@actor:on_message(_pipe, fun handle_message/2), gleam@otp@actor:start(_pipe@1). -file("src/scamper/actor.gleam", 72). ?DOC( " Send an event to the FSM actor and wait for the result.\n" " Times out after `timeout` milliseconds.\n" ). -spec send_event( gleam@erlang@process:subject(message(IDZ, IEA, IEB)), IEB, integer() ) -> {ok, scamper:machine(IDZ, IEA, IEB)} | {error, scamper@error:transition_error(IDZ, IEB)}. send_event(Subject, Event, Timeout) -> gleam@otp@actor:call( Subject, Timeout, fun(Reply_to) -> {send_event, Event, Reply_to} end ). -file("src/scamper/actor.gleam", 83). ?DOC(" Query the current state of the FSM actor.\n"). -spec get_state( gleam@erlang@process:subject(message(IEN, any(), any())), integer() ) -> IEN. get_state(Subject, Timeout) -> gleam@otp@actor:call( Subject, Timeout, fun(Reply_to) -> {get_state, Reply_to} end ). -file("src/scamper/actor.gleam", 93). ?DOC(" Query the current context of the FSM actor.\n"). -spec get_context( gleam@erlang@process:subject(message(any(), IEV, any())), integer() ) -> IEV. get_context(Subject, Timeout) -> gleam@otp@actor:call( Subject, Timeout, fun(Reply_to) -> {get_context, Reply_to} end ). -file("src/scamper/actor.gleam", 103). ?DOC(" Get the full machine from the actor.\n"). -spec get_machine( gleam@erlang@process:subject(message(IFB, IFC, IFD)), integer() ) -> scamper:machine(IFB, IFC, IFD). get_machine(Subject, Timeout) -> gleam@otp@actor:call( Subject, Timeout, fun(Reply_to) -> {get_machine, Reply_to} end ).