openpine_vm/snapshot/
types.rs

1//! Snapshot data types for serializing VM state.
2
3use std::collections::VecDeque;
4
5use fixedbitset::FixedBitSet;
6use openpine_compiler::{instructions::TypeDescriptor, program::Program};
7use serde::{Deserialize, Serialize};
8
9use crate::{
10    ExecutionLimits, InputSessions, LastInfo, Series, SymbolInfo, TimeFrame,
11    events::Event,
12    gc_serde::{SerializedObject, SerializedRawValue},
13    quote_types::Candlestick,
14    script_info::ScriptInfo,
15    strategy::StrategyState,
16    visuals::{Chart, Graph, GraphId},
17};
18
19/// Current snapshot format version.
20///
21/// Bump this whenever the snapshot format changes. There is no backward
22/// compatibility — a version mismatch is a hard error.
23pub(crate) const SNAPSHOT_VERSION: u32 = 1;
24
25/// Errors that can occur during snapshot save/restore.
26#[derive(Debug, thiserror::Error)]
27#[non_exhaustive]
28pub enum SnapshotError {
29    /// Bincode encoding failed.
30    #[error("snapshot encode error: {0}")]
31    Encode(String),
32
33    /// Bincode decoding failed.
34    #[error("snapshot decode error: {0}")]
35    Decode(String),
36
37    /// The snapshot was created with a different format version.
38    #[error("snapshot version mismatch: expected {expected}, got {got}")]
39    VersionMismatch {
40        /// The version this build expects.
41        expected: u32,
42        /// The version found in the snapshot data.
43        got: u32,
44    },
45
46    /// A serialized object reference points outside the object table.
47    #[error("invalid object reference: index {0} out of bounds")]
48    InvalidReference(u32),
49
50    /// A GC object could not be reconstructed (e.g. unknown TypeDescriptor).
51    #[error("object restore error: {0}")]
52    RestoreError(String),
53}
54
55/// A serialized variable value.
56#[derive(Debug, Clone, Serialize, Deserialize)]
57pub(crate) enum SerializedVariableValue {
58    /// A per-bar series with offset tracking.
59    Series {
60        values: VecDeque<SerializedRawValue>,
61        offset: usize,
62        max_length: usize,
63    },
64    /// A single (non-series) value.
65    Simple(SerializedRawValue),
66}
67
68/// A serialized input value.
69#[derive(Debug, Clone, Serialize, Deserialize)]
70pub(crate) struct SerializedInputValue {
71    pub(crate) value: SerializedRawValue,
72    pub(crate) is_reference_type: bool,
73    pub(crate) value_type: TypeDescriptor,
74}
75
76/// A serialized rollback action.
77#[derive(Debug, Clone, Serialize, Deserialize)]
78pub(crate) enum SerializedRollbackAction {
79    Var {
80        var_id: usize,
81        value: SerializedRawValue,
82        is_reference_type: bool,
83    },
84    UdtField {
85        udt: SerializedRawValue,
86        field_id: usize,
87        value: SerializedRawValue,
88        is_reference_type: bool,
89    },
90    RemoveGraph {
91        id: GraphId,
92    },
93    RestoreGraph {
94        id: GraphId,
95        graph: Graph,
96    },
97}
98
99/// Borrowing view of an [`Instance`](crate::Instance)'s state, used during
100/// [`save_state`](crate::Instance::save_state) to avoid cloning heavy types.
101#[derive(Serialize)]
102pub(crate) struct InstanceSnapshotRef<'a> {
103    pub(crate) version: u32,
104    pub(crate) program: &'a Program,
105
106    pub(crate) bar_index: usize,
107    pub(crate) input_index: usize,
108    pub(crate) last_info: Option<LastInfo>,
109
110    pub(crate) candlesticks: &'a Series<Candlestick>,
111    pub(crate) chart: &'a Chart,
112    pub(crate) events: &'a Vec<Event>,
113
114    pub(crate) strategy_state: &'a Option<Box<StrategyState>>,
115
116    pub(crate) object_table: Vec<SerializedObject>,
117
118    pub(crate) variables: Vec<SerializedVariableValue>,
119    pub(crate) inputs: Vec<SerializedInputValue>,
120    pub(crate) rollback_actions: Vec<SerializedRollbackAction>,
121    pub(crate) var_initialized: &'a FixedBitSet,
122
123    pub(crate) timeframe: TimeFrame,
124    pub(crate) symbol_info: &'a SymbolInfo,
125    pub(crate) script_info: &'a ScriptInfo,
126    pub(crate) input_sessions: InputSessions,
127    pub(crate) execution_limits: ExecutionLimits,
128}
129
130/// Owned snapshot produced by deserializing the bytes from `save_state`.
131#[derive(Deserialize)]
132pub(crate) struct InstanceSnapshot {
133    pub(crate) version: u32,
134    pub(crate) program: Program,
135
136    pub(crate) bar_index: usize,
137    pub(crate) input_index: usize,
138    pub(crate) last_info: Option<LastInfo>,
139
140    pub(crate) candlesticks: Series<Candlestick>,
141    pub(crate) chart: Chart,
142    pub(crate) events: Vec<Event>,
143
144    pub(crate) strategy_state: Option<Box<StrategyState>>,
145
146    pub(crate) object_table: Vec<SerializedObject>,
147
148    pub(crate) variables: Vec<SerializedVariableValue>,
149    pub(crate) inputs: Vec<SerializedInputValue>,
150    pub(crate) rollback_actions: Vec<SerializedRollbackAction>,
151    pub(crate) var_initialized: FixedBitSet,
152
153    pub(crate) timeframe: TimeFrame,
154    pub(crate) symbol_info: SymbolInfo,
155    pub(crate) script_info: ScriptInfo,
156    pub(crate) input_sessions: InputSessions,
157    pub(crate) execution_limits: ExecutionLimits,
158}