Skip to main content

Crate brink_runtime

Crate brink_runtime 

Source
Expand description

Runtime/VM for executing compiled ink stories.

The runtime takes a StoryData from the compiler, links it into an immutable Program, and executes it via Story.

use std::sync::Arc;
use brink_runtime::Step;

let (program, line_tables) = brink_runtime::link(story_data)?;
let mut story: brink_runtime::Story = brink_runtime::Story::new(Arc::new(program), line_tables);
loop {
    match story.continue_single()? {
        Step::Line(line) => print!("{}", line.text),
        Step::Done => {}
        Step::Choices(choices) => {
            let _ = choices;
            // pick a choice...
            story.choose(0)?;
        }
        Step::End => break,
        Step::Suspended => break,
    }
}

no_std + alloc: this crate builds without the standard library when the default std feature is disabled (see docs/no-std-portability.md).

Re-exports§

pub use debug_control::Breakpoint;
pub use debug_control::BreakpointId;
pub use debug_control::BreakpointSet;
pub use debug_control::DEFAULT_DEBUG_BUDGET;
pub use debug_control::DebugRunOutcome;
pub use debug_control::DebugStopReason;
pub use debug_control::StepMode;
pub use debug_control::WatchHit;
pub use debug_control::WatchpointObserver;
pub use rng::DotNetRng;
pub use rng::FastRng;
pub use rng::StoryRng;

Modules§

bench_counters
Bench-only debug counters for Arc-clone / COW-copy events (issue #821 Workstream B seed, docs/runtime-bench.md).
debug_control
Debugger control seam (D8, issue #3186): breakpoints, pause/resume, and step in/over/out — the part of the debugger epic (#452) that turns the read-only crate::DebugSnapshot (D4, #3182) into something that can actually halt and single-step a running story.
debug_session
Scripted debug sessions (#3247/#3248): the shared verb set the test harness, the CLI debugger and the studio all drive, so there is one definition of “step over” rather than three. Scripted debug sessions — the shared verb set for driving a debugger (issue #3247, extracted here by #3248).
effect_trace
Ground-truth effect-atom recorder (issue #870, T2 effects epic, docs/effects-spec.md). The effects analogue of the oracle: this module records, per executing definition scope, the atomic effects the VM actually performs — cells read, cells written, external kinds called — so brink-test-harness can assert the statically-inferred effects(def) row (brink-db::ProjectDb::effects) covers every one of them for every def a real run executed. A purely structural inter-row consistency check (caller’s row ⊇ callee’s row) cannot catch an under-report where both rows silently agree on the wrong (too-small) answer — exactly the #866 ref-param-write regression this issue is named for. This is the independent, run-the-bytecode-and-look check that closes that gap.
rng
Pluggable PRNG for story randomization.
transcript
Transcript binary serialization (.brkt format).

Structs§

BlockId
Opaque identifier grouping a run of adjacent content lines.
Budget
Caller-supplied cap on a Speculation’s VM stepping, in place of the runtime’s hardcoded STEP_LIMIT/LINE_LIMIT ceilings.
Choice
A single choice presented to the player.
ContextView
Routing view implementing ContextAccess over (&mut World, &mut FlowLocal).
DebugChoice
A pending choice and the knot it targets.
DebugFrame
One call frame, resolved to a knot/stitch path.
DebugGlobal
A global variable and its current value.
DebugLocal
One named local variable and its current value (docs/debugger-spec.md §3, D7/#3185).
DebugPosition
Precise execution position: a container index plus the byte offset of the next instruction to execute inside that container’s bytecode.
DebugRng
Story RNG state.
DebugSnapshot
A structured, read-only snapshot of the runtime’s current state.
DebugSourceLocation
The result of resolving a DebugPosition to source via the program’s DebugInfo section (D6, docs/debugger-spec.md §2.2) — see crate::Program::resolve_debug_position (D9, issue #3187). This is the “program → source” half of the studio’s Location protocol (docs/studio-shell-spec.md §6.1).
DebugVisit
A visit count for a named knot/stitch.
Element
A line’s classification — kind + an open, preset-defined data map (docs/prose-dialect-spec.md §7/§3.5b, §3.6, sitting-5 ruling item 8: “the output format bakes no scene-specific fields — element data is an open map produced by conventions and handlers”). Deliberately a String kind, not a closed enum: the vocabulary belongs to whichever preset or @[element] handler classified the line, never to the runtime.
ExternalsReport
Diagnostic record of which externals a KindTieredHandler let through live versus fell back, across the handler’s lifetime.
FallbackHandler
Default handler that always falls back to the ink function body.
FlowInstance
A single independent execution context within a story. The default flow runs from the root container; named flows can be spawned at arbitrary entry points via FlowInstance::new_at.
FlowLocal
Per-flow override layer over the shared World.
Fragment
A finalized fragment — structural output parts plus any associated tags.
FragmentRef
A borrowed view of one fragment inside a Fragments store.
Fragments
The fragment store: every finalized fragment’s parts laid end to end in ONE arena, addressed by a per-fragment span.
FrameStartView
A borrowing view over a pinned frame-start World: reads are served by reference from the shared &World, writes land in a private per-view overlay that the shared world never sees.
JournalEvent
One input that entered the VM.
KindTieredHandler
A stackable ExternalFnHandler that tiers externals by PolicyKind before delegating to a real handler.
ListDelta
Membership delta for one list-valued global.
ListMember
One active member of a list value, resolved for host-facing display. See Program::list_members.
LoadReport
What Story::load_state couldn’t apply, so a host can surface it rather than have data silently vanish. Globals whose name no longer exists are dropped (no slot to hold them) and reported here. Visit/turn counts are never dropped — counts for scopes the current program lacks are retained harmlessly (unused until/unless the scope returns), so they aren’t reported except when the miss-path alias lookup (M-3, docs/modules-spec.md §5) still can’t place them — see unresolved_renames for a named scope, or anonymous_states_dropped for an anonymous one.
ObservedContext
A ContextAccess wrapper that delegates to an inner ContextAccess implementor (typically World or the ContextView routing view) and notifies a WriteObserver on every mutation.
OutputLine
One line of story content, carried inside Step::Line.
Program
A linked, ready-to-execute program.
RecordedExternal
One recorded external-function result, captured in call order during a live run.
RecordingHandler
Wraps an ExternalFnHandler and records every inline-Resolved external result into a ReplayRecorder during a live run.
ReplayHandler
Replays recorded external results (ReplayMode::Recorded).
ReplayRecorder
An append-only, capped log of external results for one flow, plus a replay cursor. Recorded during the live run; consumed in order during replay.
ResolvedPolicy
Fast, id/slot-based resolution of a WorldPolicy against a specific Program. Built once at World creation via ResolvedPolicy::resolve; consulted on every state access (from F2.2 on) with O(1) lookups — no string matching on the hot path.
SaveState
A persistent, name-keyed snapshot of a story’s game state.
SessionJournal
One ordered log of every input that entered the VM during a session, plus a terminal fast-restore checkpoint.
SnapshotFrame
One summarized call frame.
SnapshotList
Resolved membership of a List-valued global.
Speculation
A sandboxed, self-contained speculative run over a story’s current state. See the module docs for the full picture.
StateDiff
A pure diff between two StateSnapshots (see diff).
StateSnapshot
A typed, name-resolved snapshot of a session’s game state.
Stats
Lightweight counters tracking VM activity over a story’s lifetime.
Story
Per-instance mutable state for executing stories.
StorySession
A journaling, replayable session wrapping a Story.
StorySnapshot
Owned story state that can be detached from a Program and reattached later.
ValueIter
A pull iterator over one builtin iterable’s canonical sequence — the iterate protocol’s machine form: next is next(ref Self): Option[T] with the protocol’s laws structural (the cursor only advances, so every element is yielded exactly once and exhaustion is terminal and sticky by construction).
VisitEntry
One visit/turn-count entry: a scope id and its count, plus (when the scope is a named knot/stitch) an advisory author path for human inspection. The id is the load key; path is cosmetic.
World
Shared game state that lives above individual flows.
WorldPolicy
Host-facing, name-based declaration of the world/local split.

Enums§

CommitError
Errors from commit.
DebugValue
A structured, read-only view of a runtime Value for the debugger’s locals panel (docs/debugger-spec.md §3, D7/#3185).
DivergenceFound
What was found at a divergence point instead of the recorded event.
DriveOutcome
Outcome of a single FlowInstance::drive call: either the drive reached a terminal step, or it paused on a deferred external mid-drive. Both variants carry every Step produced during this call — for AwaitingExternal, that’s the (possibly empty) run of Step::Line produced before the pause; for Terminal, the terminal step is always the last element (see FlowInstance::drive).
EvalContext
Which evaluation regime a KindTieredHandler is gating for.
EventKind
The kind + payload of a JournalEvent.
ExecMode
The dev/prod execution mode (NS-A4, docs/stdlib-spec.md §4b, ruled 2026-07-18): the knob that decides WHERE execution stops on an unordered comparand — never WHAT values are fabricated.
ExternalReplayMode
How replay obtains external values.
ExternalResult
Result of an external function handler call.
FailReason
Why replay stopped without diverging.
FunctionEval
Outcome of an engine→ink function evaluation ([FlowInstance::begin_function_eval] / resume_function_eval).
LocaleMode
Controls how missing scopes are handled when applying a locale overlay.
Mode
Execution mode of a FlowLocal, baked in at construction/fork time and read by ContextView to decide how it routes every unit.
OutputPart
A part of accumulated output.
PolicyError
Errors resolving a WorldPolicy against a Program’s symbol table.
PolicyKind
The effect category a KindTieredHandler gates on. Plain data — the consumer maps its own (richer) external classification onto this two-way split.
RanOutOfContentCause
Why execution ran out of content — the call-stack shape C#’s Story.Continue() inspects to pick one of four messages (Story.cs, the AddError calls guarding the “ran out of content” branch: it checks callStack.CanPop(PushPopType.Tunnel), then .CanPop(PushPopType.Function), then !callStack.canPop, with a final backstop for none of the above).
ReplayMode
How a replay obtains external values. Whole-flow granularity.
ReplayOutcome
Outcome of replaying a journal prefix against a program.
ReplayWarning
A non-fatal replay observation.
RuntimeError
Errors that can occur during story linking or execution.
RuntimeWarning
A non-fatal condition the VM reported while a story was running (issue #3354, RULED 2026-09-01 option C).
Scope
Where a unit of story-state lives: the shared World or a flow’s private FlowLocal.
SessionError
Errors from session-level operations (distinct from VM RuntimeErrors, which are wrapped).
SnapshotStatus
Session execution status, serde-friendly.
SpeculationStep
Outcome of a single Speculation::advance call.
Step
A single step of story output from [Story::continue_single].
StepOutcome
Outcome of a single [FlowInstance::advance] step.
StoryStatus
The current execution status of a story.

Constants§

RECORDING_CAP
Upper bound on recorded externals per flow (unbounded-growth guard). Beyond it, ReplayRecorder::record drops the result and replay falls through to the ink fallback body for the uncovered tail.
RUNTIME_WARNING_CAP
How many RuntimeWarnings one flow accumulates between drains before it stops recording them.
SAVE_FORMAT_VERSION
Current SaveState format version. Bump when the format changes (independent of the story’s own content); version lets a loader migrate.
SESSION_JOURNAL_CAP
Upper bound on journal events (unbounded-growth guard, mirroring RECORDING_CAP). Beyond it, appends are dropped and SessionJournal::truncated is set — the journal degrades honestly and restore falls back to the embedded checkpoint.
SESSION_JOURNAL_VERSION
Current SessionJournal format version.

Traits§

ContextAccess
Trait for accessing and mutating story execution state.
ExternalFnHandler
Trait for handling external function calls from ink.
WriteObserver
Observer for state mutations during story execution.

Functions§

apply_locale
Apply a locale overlay to a set of base line tables.
commit
Fold a forked child’s own-layer overrides back into its parent’s, making the child’s writes visible through parent (and, transitively, anything parent itself chains to or is later written through).
diff
Pure diff of two snapshots. a is “before”, b is “after”.
link
Link a StoryData into an executable Program.
load_state
Reconcile a SaveState into a flow’s context, returning a LoadReport of anything that couldn’t be applied. Globals are matched by name; visit/turn counts by id. Tolerant of story patches: unknown globals are reported, scopes the program no longer has retain their saved counts harmlessly in the live context. Note one deliberate change from the pre-F6.1b Story methods: such stale entries are not re-emitted by a subsequent save_state (which enumerates the current program’s containers, not the live maps) — ghost counts from older program versions no longer round-trip through saves indefinitely.
save_state
Capture a flow’s game state as a durable, name-keyed SaveState. Does not capture execution position — see the module docs.

Type Aliases§

DrainedLine
One line handed out by Story::debug_drain_buffered_lines: text, tags, and its source location (W7/#3300 provenance — same field the production road’s OutputLine::source carries).