1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
//! [`RunnerSnapshot`] - session state for bookmarks and save / load support.
use ;
/// A point-in-time snapshot of the dialogue session's mutable state.
///
/// Use [`Runner::snapshot`](crate::runtime::Runner::snapshot) to capture and
/// [`Runner::restore`](crate::runtime::Runner::restore) to apply.
///
/// The snapshot records:
/// - which node was active (`current_node`),
/// - how many times each node has been visited (`visits`),
/// - which `<<once>>` blocks have already fired (`once_seen`).
///
/// **Variable storage is not included** - it is the host's responsibility to
/// persist [`HashMapStorage`](crate::HashMapStorage) (or their own
/// [`VariableStorage`](crate::VariableStorage) impl) alongside the snapshot when
/// building a full save file.
///
/// With the `serde` feature, this type also derives `Serialize` / `Deserialize`
/// so you can write it to disk as JSON or another format.
///
/// # Save / load example
///
/// Both the snapshot **and** variable storage must be serialised together when
/// you persist to disk. Neither is complete without the other.
///
/// ```rust
/// # #[cfg(feature = "serde")]
/// # {
/// use bubbles::{HashMapStorage, Runner, Value, VariableStorage, compile};
///
/// let src = "title: A\n---\n<<set $gold = 10>>\nHello!\n===\n";
/// let prog = compile(src).unwrap();
///
/// // First session
/// let mut runner = Runner::new(prog.clone(), HashMapStorage::new());
/// runner.start("A").unwrap();
/// let _ = runner.next_event(); // NodeStarted
/// let _ = runner.next_event(); // (set $gold side-effect, then Line)
///
/// let snap = runner.snapshot();
/// let snap_json = serde_json::to_string(&snap).unwrap();
/// let vars_json = serde_json::to_string(runner.storage()).unwrap();
///
/// let saved_vars: HashMapStorage = serde_json::from_str(&vars_json).unwrap();
/// let saved_snap: bubbles::RunnerSnapshot = serde_json::from_str(&snap_json).unwrap();
///
/// let mut runner2 = Runner::new(prog, saved_vars);
/// runner2.restore(saved_snap).unwrap();
/// // runner2 is back at the beginning of node "A" with $gold already set.
/// # }
/// ```