techbelly/elm-zmachine/1.1.0

ZMachine.Snapshot

Save/restore snapshots for the Z-Machine.

A Snapshot captures the mutable state of a running Z-Machine so that it can be serialized to bytes and later fed back to restore execution. There are two ways to produce one:

  1. The host calls ZMachine.snapshot at any point between steps — produces an autosave snapshot tagged ResumeAt.
  2. The interpreter produces one automatically when a running story executes the save opcode — tagged ResumeByBranchTrue, meaning that on restore the save instruction's branch-on-success is taken.

For simple round-tripping, serialize with encode and reload with decode — this built-in codec covers both resume kinds but is not cross-interpreter portable. A Quetzal codec for interop with other interpreters is planned. Clients building custom schemes (transcript + notes, etc.) can use the projection functions and reconstruct a Snapshot via fromParts.

Opaque snapshot of Z-Machine state.

type alias SnapshotMeta =
{ release : Int
, serial : String
, checksum : Int
}

Story-identifying metadata stored inside a snapshot. Used to reject snapshots that belong to a different story or a different release.

= ResumeAt
| ResumeByBranchTrue
| ResumeByStoreResult

How the interpreter should resume after restoring this snapshot.

  • ResumeAt — host-initiated snapshot (autosave). Execution continues from pc as if nothing happened.
  • ResumeByBranchTrue — produced by the V3 save opcode. Execution re-runs the save instruction at pc with a success result, following its branch-on-true target.
  • ResumeByStoreResult — produced by the V5 ext_save opcode. Execution re-runs the save instruction at pc, storing a non-zero result to indicate success.
= WrongStory
{ expected : SnapshotMeta
, found : SnapshotMeta
}
| SnapshotCorrupt String

Errors returned by restore.

  • WrongStory — snapshot metadata does not match the currently-loaded story. Compare expected (current story) against found (snapshot).
  • SnapshotCorrupt — snapshot data failed an integrity check.

Capture and restore

{ memory : Memory
, pc : Int
, stack : List Int
, callStack : List CallFrame
, resumeKind : ResumeKind
}

Build a snapshot from the live pieces of a running Z-Machine. Metadata is read from the supplied memory image's header.

-> Memory
-> Result
{ memory : Memory
, pc : Int
, stack : List Int
, callStack : List CallFrame
}

Validate a snapshot against the currently-loaded story's memory and produce the pieces needed to rehydrate a running machine.

The supplied Memory must be the original image of the currently loaded story (i.e. ZMachine.originalMemory), so that metadata can be compared and the static/high memory region can be reused when rebuilding the dynamic memory image.

Inspection

meta : Snapshot -> SnapshotMeta

Story metadata recorded in the snapshot.

Which resume policy this snapshot was tagged with.

pc : Snapshot -> Int

The program counter stored in the snapshot. For a ResumeAt snapshot this is the next instruction to execute; for ResumeByBranchTrue it points at the save opcode whose branch will be re-evaluated as true.

dynamicMemory : Snapshot -> Array Int

Raw dynamic memory bytes captured in the snapshot. Length equals the dynamic memory size of the story (i.e. the header's static base).

stack : Snapshot -> List Int

The interpreter's current evaluation stack at capture time.

callStack : Snapshot -> List CallFrame

The active call frames at capture time, outermost-first.

Custom schemes

{ dynamicMemory : Array Int
, pc : Int
, stack : List Int
, callStack : List CallFrame
, resumeKind : ResumeKind
, meta : SnapshotMeta
}

Build a Snapshot directly from its constituent parts. Useful for clients implementing custom save formats: after decoding your format, call this to produce a Snapshot that can be fed to restore.

Native binary format

encode : Memory -> Snapshot -> Bytes

Encode a snapshot as bytes using the interpreter's native format.

The Memory argument is the original story memory — it is used to produce a compressed diff (XOR + run-length encoding) of dynamic memory rather than storing the full image. This typically reduces the dynamic memory payload from ~16 KB to a few hundred bytes.

Useful for storing autosaves in localStorage, a file, etc. The output is not portable between different Z-Machine interpreters; a Quetzal codec for interop is planned.

decode : Memory -> Bytes -> Result String Snapshot

Decode a snapshot from bytes produced by encode.

The Memory argument is the original story memory — it is needed to decompress the dynamic memory diff stored in the snapshot.

Returns Err with a reason string on any format error.