Runtime

Runtime<M: Machine> is the embedder-driven engine: it owns the Behaviors for Model and Shared, the projected SceneBehavior, the FocusState, and the last committed frame. One Runtime per participant.

Construction

#![allow(unused)]
fn main() {
Runtime::new(machine, ctx, shared_initial)
}

Driving (host turn cycle)

MethodUse
dispatch(RuntimeEvent)keys, resize, focus/activate events
send(Msg)domain messages from the host adapter
set_shared(Shared)push a whole projection (re-projects on next sample)
set_context(Context)push app context (identity, theme)

Reading

MethodReturns
scene()&SceneBehavior<Msg>
model() / shared()current values (cloned)
focus()&FocusState
layout(bounds)LayoutNode tree
render_ops(bounds)Vec<RenderOp>
cursor(bounds)Option<(u16, u16)> (clamped to bounds)
diff(bounds)Vec<PatchOp> vs. last commit — read-only

Committing

MethodNotes
render(renderer, bounds)generic Renderer path
render_to_backend(backend, bounds)diff → backend commands → execute → sync order
render_to_backend_with_cursor(.., cursor)+ explicit cursor command
render_to_backend_auto_cursor(..)cursor from the machine
invalidate_render_state()forget the baseline (next commit re-inserts everything)

Effects

Machine::update returns Effect<Msg>:

#![allow(unused)]
fn main() {
pub enum Effect<Msg> {
    None,
    Emit(Msg),              // synchronously re-enters update (recursive)
    Batch(Vec<Effect<Msg>>),// applied in order
    RequestFocus(NodeId),   // routes through the focus dispatch path
}
}

Effects are closed and fully drained by the runtime inside send/dispatch. There is no queue, no host-visible effect stream, and no async bridge (yet — that's an open design question tracked in the embedding contract's §O3).

Threading

Runtime is single-threaded (Rc/RefCell inside the Behaviors). Drive it from one task; do async work elsewhere and surface results as send / set_shared.