1use std::collections::VecDeque;
4
5use fixedbitset::FixedBitSet;
6use navi_program::{Program, TypeDescriptor};
7use serde::{Deserialize, Deserializer, Serialize, Serializer};
8
9use crate::{
10 ExecutionLimits, InputSessions, LastInfo, SymbolInfo, TimeFrame,
11 events::Event,
12 gc_serde::{SerializedObject, SerializedRawValue},
13 script_info::ScriptInfo,
14 strategy::StrategyState,
15 visuals::{Chart, Graph, GraphId},
16};
17
18pub(crate) const SNAPSHOT_VERSION: u32 = 4;
23
24#[derive(Debug, thiserror::Error)]
26#[non_exhaustive]
27pub enum SnapshotError {
28 #[error("snapshot encode error: {0}")]
30 Encode(String),
31
32 #[error("snapshot decode error: {0}")]
34 Decode(String),
35
36 #[error("snapshot version mismatch: expected {expected}, got {got}")]
38 VersionMismatch {
39 expected: u32,
41 got: u32,
43 },
44
45 #[error("invalid object reference: index {0} out of bounds")]
47 InvalidReference(u32),
48
49 #[error("object restore error: {0}")]
51 RestoreError(String),
52
53 #[error("cannot save snapshot: current bar has not been confirmed")]
58 UnconfirmedBar,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
63#[serde(rename_all = "camelCase")]
64pub(crate) enum SerializedVariableValue {
65 Series {
67 values: VecDeque<SerializedRawValue>,
68 offset: usize,
69 length: usize,
70 max_bars_back: Option<usize>,
71 #[serde(default = "default_observed_max_lookback")]
75 observed_max_lookback: usize,
76 },
77 Simple(SerializedRawValue),
79}
80
81fn default_observed_max_lookback() -> usize {
82 usize::MAX
83}
84
85#[derive(Debug, Clone, Serialize, Deserialize)]
87#[serde(rename_all = "camelCase")]
88pub(crate) struct SerializedInputValue {
89 pub(crate) value: SerializedRawValue,
90 pub(crate) is_reference_type: bool,
91 pub(crate) value_type: TypeDescriptor,
92}
93
94#[derive(Debug, Clone, Serialize, Deserialize)]
96#[serde(rename_all = "camelCase")]
97pub(crate) enum SerializedRollbackAction {
98 Var {
99 var_id: usize,
100 value: SerializedRawValue,
101 is_reference_type: bool,
102 },
103 UdtField {
104 udt: SerializedRawValue,
105 field_id: usize,
106 value: SerializedRawValue,
107 is_reference_type: bool,
108 },
109 RemoveGraph {
110 id: GraphId,
111 },
112 RestoreGraph {
113 id: GraphId,
114 graph: Graph,
115 },
116}
117
118#[derive(Serialize)]
121#[serde(rename_all = "camelCase")]
122pub(crate) struct InstanceSnapshotRef<'a> {
123 pub(crate) version: u32,
124 pub(crate) program: &'a Program,
125
126 pub(crate) bar_index: usize,
127 pub(crate) input_index: usize,
128 pub(crate) last_info: Option<LastInfo>,
129
130 pub(crate) last_bar_time: i64,
131 pub(crate) chart: &'a Chart,
132 pub(crate) events: &'a Vec<Event>,
133
134 pub(crate) strategy_state: &'a Option<Box<StrategyState>>,
135
136 pub(crate) object_table: Vec<SerializedObject>,
137
138 pub(crate) variables: Vec<SerializedVariableValue>,
139 pub(crate) inputs: Vec<SerializedInputValue>,
140 pub(crate) rollback_actions: Vec<SerializedRollbackAction>,
141 #[serde(serialize_with = "serialize_fixedbitset")]
142 pub(crate) var_initialized: &'a FixedBitSet,
143
144 pub(crate) timeframe: TimeFrame,
145 pub(crate) symbol_info: &'a SymbolInfo,
146 pub(crate) script_info: &'a ScriptInfo,
147 pub(crate) input_sessions: InputSessions,
148 pub(crate) execution_limits: ExecutionLimits,
149}
150
151#[derive(Deserialize)]
153#[serde(rename_all = "camelCase")]
154pub(crate) struct InstanceSnapshot {
155 pub(crate) version: u32,
156 pub(crate) program: Program,
157
158 pub(crate) bar_index: usize,
159 pub(crate) input_index: usize,
160 pub(crate) last_info: Option<LastInfo>,
161
162 pub(crate) last_bar_time: i64,
163 pub(crate) chart: Chart,
164 pub(crate) events: Vec<Event>,
165
166 pub(crate) strategy_state: Option<Box<StrategyState>>,
167
168 pub(crate) object_table: Vec<SerializedObject>,
169
170 pub(crate) variables: Vec<SerializedVariableValue>,
171 pub(crate) inputs: Vec<SerializedInputValue>,
172 pub(crate) rollback_actions: Vec<SerializedRollbackAction>,
173 #[serde(deserialize_with = "deserialize_fixedbitset")]
174 pub(crate) var_initialized: FixedBitSet,
175
176 pub(crate) timeframe: TimeFrame,
177 pub(crate) symbol_info: SymbolInfo,
178 pub(crate) script_info: ScriptInfo,
179 pub(crate) input_sessions: InputSessions,
180 pub(crate) execution_limits: ExecutionLimits,
181}
182
183fn serialize_fixedbitset<S: Serializer>(fbs: &FixedBitSet, ser: S) -> Result<S::Ok, S::Error> {
187 use serde::ser::SerializeSeq;
188 let blocks = fbs.as_slice();
189 let mut seq = ser.serialize_seq(Some(1 + blocks.len()))?;
190 seq.serialize_element(&(fbs.len() as u64))?;
191 for &block in blocks {
192 seq.serialize_element(&(block as u64))?;
193 }
194 seq.end()
195}
196
197fn deserialize_fixedbitset<'de, D: Deserializer<'de>>(de: D) -> Result<FixedBitSet, D::Error> {
200 use serde::de::{SeqAccess, Visitor};
201 struct FbsVisitor;
202 impl<'de> Visitor<'de> for FbsVisitor {
203 type Value = FixedBitSet;
204 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
205 f.write_str("a sequence [capacity, block…]")
206 }
207 fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<FixedBitSet, A::Error> {
208 use serde::de::Error;
209 let capacity: u64 = seq
210 .next_element()?
211 .ok_or_else(|| A::Error::invalid_length(0, &self))?;
212 let mut blocks = Vec::new();
213 while let Some(b) = seq.next_element::<u64>()? {
214 blocks.push(b as usize);
215 }
216 Ok(FixedBitSet::with_capacity_and_blocks(
217 capacity as usize,
218 blocks,
219 ))
220 }
221 }
222 de.deserialize_seq(FbsVisitor)
223}