The GenServer callback module that runs a program's OTP callbacks.
Start an actor with the program value itself:
GenServer.start(Hyperlang.Actor, {spec, program, arg})
GenServer.start_link(Hyperlang.Actor, {spec, program, arg}, name: MyActor)spec is the Hyperlang.run/4 spec (%{bindings: ..., policy: ..., syscall: ...}), and every callback runs under it. arg is the guest
init/1 argument. The program must export init/1; handle_call/3,
handle_cast/2, handle_info/2, handle_continue/2, terminate/2 and
code_change/3 are used when exported. As OTP does for a callback module
without them, an actor drops a message when the program has no
handle_info/2 and runs nothing on exit when it has no terminate/2. A
missing required callback stops the actor with the typed run/4 error
(category: :export). Guest stdout from callbacks is dropped.
The actor runs exactly its program
The actor's init/1 loads program and pins its code slot in one step, so
a release or code-pool pressure before init/1 cannot leave the actor
without code or with another program's code. The pin holds until the
actor exits. It is charged to the actor's scope (spec.policy.scope, else
the actor's own default scope), which may pin at most max_code_pins
distinct slots. Hyperlang.load/1 loads a program ahead of time; it is
optional.
Limits
Every callback is one Hyperlang.run/4 in the actor process, so the
per-callback policy limits (wall_ms, max_reductions/budget,
heap_words) apply to each callback. The actor-lifetime limits (rate,
ceiling) hold for the actor's whole life, with no host wiring.
Errors
GenServer.start/3 returns {:error, {:hyperlang, error}} when init/1
stops:
category: :apiwhen the init argument is not{spec_map, %Hyperlang.Program{}, arg};category: :code_poolwithdetails.reason: :pin_limitat the scope bound, orcategory: :code_poolwhen no slot of the program'scode_poolwindow is free;- the error of the guest
init/1.
Supervision
child_spec/1 takes the same {spec, program, arg} tuple:
children = [{Hyperlang.Actor, {spec, program, arg}}]The child id is Hyperlang.Actor and the restart is :permanent, as for
any GenServer. Supervise more than one actor under one supervisor by
giving each its own id:
Supervisor.child_spec({Hyperlang.Actor, {spec, program, arg}}, id: {:counter, 1})A restarted actor runs init/1 again with the same program, so it pins
and, if needed, loads the program again.
Summary
Functions
A child specification that starts the actor with
GenServer.start_link(Hyperlang.Actor, {spec, program, arg}).
Functions
@spec child_spec({map(), Hyperlang.Program.t(), term()}) :: Supervisor.child_spec()
A child specification that starts the actor with
GenServer.start_link(Hyperlang.Actor, {spec, program, arg}).