Reference

IrMachine

Package Trax.StateMachineNamespace Trax.StateMachineSource IrMachine.cs

The C# engine built from a machine's IR instead of from its C# code. A client that holds the host's client manifest but not the machine's assembly predicts with it, the way every other language's client builds its machine from the IR. It answers as SnapshotMachine does for the machine that exported the IR, and the conformance kit holds the two to the same codes and wire bytes.

Signature

public sealed class IrMachine
{
    public IrMachine(
        JsonObject ir,
        IReadOnlyDictionary<string, Func<JsonObject, JsonNode?, bool>>? customGuards = null,
        IReadOnlyDictionary<string, Func<JsonObject, JsonNode?, JsonObject>>? customReducers = null);
 
    public string Id { get; }
    public int Version { get; }
    public string InitialState { get; }
    public IReadOnlySet<string> CommittedStates { get; }
    public IReadOnlySet<string> EffectTriggers { get; }
    public IReadOnlySet<string> TimedStates { get; }
 
    public Snapshot CreateInitialSnapshot();
    public AdvanceResult Advance(Snapshot snapshot, string trigger, JsonNode? input = null);
    public AdvanceResult ApplyOutcome(Snapshot snapshot, string trigger, JsonNode? input = null);
    public AdvanceResult ApplyTimer(Snapshot snapshot, string trigger);
    public RehydrationResult Rehydrate(string json);
    public RehydrationResult Rehydrate(string json, bool fromServer);
    public string Serialize(Snapshot snapshot);
    public bool CanFire(Snapshot snapshot, string trigger, JsonNode? input = null);
    public IReadOnlyList<string> AvailableTriggers(Snapshot snapshot);
}

Members

MemberWhat it is
IrMachine(ir, customGuards, customReducers)Builds the machine an IR describes. The handlers bind the custom rules and reductions the IR names. An IR this engine cannot read throws ArgumentException; the differential block is ignored.
Id, Version, InitialStateThe IR's id, definition version and initial state.
CommittedStates, EffectTriggers, TimedStatesThe states marked .Committed(), which a soft autosave may not move a draft out of; the triggers whose edge runs the effect; and the states with a timer.
CreateInitialSnapshot()The snapshot a new instance begins with: the IR's initialContext, or one derived from the initial state's schema.
Advance(snapshot, trigger, input)A client's trigger, with the refusals SnapshotMachine.Advance gives, in its order.
ApplyOutcome(snapshot, trigger, input), ApplyTimer(snapshot, trigger)An invoked train's outcome (Fetching.done) and a state's timer (Review.after). The server applies both; a client uses them to replay one.
Rehydrate(json), Rehydrate(json, fromServer)Reads a snapshot. With fromServer, a custom state requirement with no handler counts as passed, since the server checked it.
Serialize(snapshot)The canonical wire, byte for byte what every engine writes.
CanFire(snapshot, trigger, input), AvailableTriggers(snapshot)Whether a trigger fires, and the triggers with an edge out of the state.

Behavior

  • Every operation is total: a refusal is an AdvanceResult.Rejected or a RehydrationResult.Error, never an exception.
  • A custom guard with no handler does not hold, and a custom reduction with none keeps the context. Neither is the server's answer, which has the handlers. The .NET client does not use such a result: an event whose prediction depended on an unhandled custom guard, custom state requirement or custom reduction is sent unpredicted, and the view shows the server's answer.
  • An IR carries no migrations, so Rehydrate refuses a snapshot of another version with VERSION_MISMATCH.

Example

var manifest = ClientManifest.Read(await File.ReadAllTextAsync("manifest.json"));
var machine = new IrMachine(manifest.Machines.Single(m => m.Id == "checkout").Ir);
 
var start = machine.CreateInitialSnapshot();
var result = machine.Advance(start, "Next");
// AdvanceResult.Rejected with GUARD_FAILED while the cart is empty

See also