1use crate::graphics_state::{GraphicsState, GstateEntry};
11use crate::object::EntityId;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum StoreType {
16 String,
17 Array,
18 Dict,
19}
20
21#[derive(Debug, Clone)]
23pub struct SaveRecord {
24 pub src: EntityId,
26 pub copy: EntityId,
28 pub store_type: StoreType,
30}
31
32pub struct SaveLevel {
34 pub level: u16,
36 pub save_id: u32,
38 pub records: Vec<SaveRecord>,
40 pub valid: bool,
42 pub d_stack_depth: usize,
44 pub packing_mode: bool,
46 pub vm_alloc_mode: bool,
48 pub object_format: i32,
50 pub gstate: GraphicsState,
52 pub gstate_stack: Vec<GstateEntry>,
53}
54
55pub struct SaveStack {
57 levels: Vec<SaveLevel>,
58 next_save_id: u32,
59}
60
61impl SaveStack {
62 pub fn new() -> Self {
64 Self {
65 levels: Vec::new(),
66 next_save_id: 1,
67 }
68 }
69
70 pub fn save(
72 &mut self,
73 d_stack_depth: usize,
74 packing_mode: bool,
75 vm_alloc_mode: bool,
76 object_format: i32,
77 gstate: GraphicsState,
78 gstate_stack: Vec<GstateEntry>,
79 ) -> (u16, u32) {
80 let level = (self.levels.len() + 1) as u16;
81 let save_id = self.next_save_id;
82 self.next_save_id += 1;
83 self.levels.push(SaveLevel {
84 level,
85 save_id,
86 records: Vec::new(),
87 valid: true,
88 d_stack_depth,
89 packing_mode,
90 vm_alloc_mode,
91 object_format,
92 gstate,
93 gstate_stack,
94 });
95 (level, save_id)
96 }
97
98 pub fn add_record(&mut self, record: SaveRecord) {
100 if let Some(level) = self.levels.last_mut() {
101 level.records.push(record);
102 }
103 }
104
105 pub fn restore(&mut self) -> Option<SaveLevel> {
108 self.levels.pop()
109 }
110
111 pub fn restore_to(&mut self, save_id: u32) -> Option<Vec<SaveLevel>> {
117 let idx = self.levels.iter().position(|l| l.save_id == save_id)?;
118 let popped: Vec<SaveLevel> = self.levels.drain(idx..).collect();
119 Some(popped)
120 }
121
122 pub fn current_level(&self) -> u16 {
124 self.levels.last().map(|l| l.level).unwrap_or(0)
125 }
126
127 pub fn last_save_id(&self) -> u32 {
130 self.levels.last().map(|l| l.save_id).unwrap_or(0)
131 }
132
133 pub fn is_valid(&self, save_id: u32) -> bool {
135 self.levels.iter().any(|l| l.save_id == save_id && l.valid)
136 }
137
138 pub fn depth(&self) -> usize {
140 self.levels.len()
141 }
142
143 pub fn levels_ref(&self) -> &[SaveLevel] {
145 &self.levels
146 }
147
148 pub fn invalidate_newer(&mut self, save_id: u32) {
150 let mut found = false;
151 for level in &mut self.levels {
152 if found {
153 level.valid = false;
154 }
155 if level.save_id == save_id {
156 found = true;
157 }
158 }
159 }
160}
161
162impl Default for SaveStack {
163 fn default() -> Self {
164 Self::new()
165 }
166}
167
168#[cfg(test)]
169mod tests {
170 use super::*;
171
172 #[test]
173 fn test_save_and_depth() {
174 let mut ss = SaveStack::new();
175 assert_eq!(ss.depth(), 0);
176 assert_eq!(ss.current_level(), 0);
177
178 let (level, id) = ss.save(3, false, false, 0, GraphicsState::new(), Vec::new());
179 assert_eq!(level, 1);
180 assert_eq!(id, 1);
181 assert_eq!(ss.depth(), 1);
182 assert_eq!(ss.current_level(), 1);
183 }
184
185 #[test]
186 fn test_nested_save() {
187 let mut ss = SaveStack::new();
188 let (l1, _) = ss.save(3, false, false, 0, GraphicsState::new(), Vec::new());
189 let (l2, _) = ss.save(3, false, false, 0, GraphicsState::new(), Vec::new());
190 assert_eq!(l1, 1);
191 assert_eq!(l2, 2);
192 assert_eq!(ss.depth(), 2);
193 assert_eq!(ss.current_level(), 2);
194 }
195
196 #[test]
197 fn test_restore() {
198 let mut ss = SaveStack::new();
199 let (_, id1) = ss.save(3, false, false, 0, GraphicsState::new(), Vec::new());
200 ss.add_record(SaveRecord {
201 src: EntityId(0),
202 copy: EntityId(1),
203 store_type: StoreType::String,
204 });
205
206 let level = ss.restore().unwrap();
207 assert_eq!(level.save_id, id1);
208 assert_eq!(level.records.len(), 1);
209 assert_eq!(ss.depth(), 0);
210 }
211
212 #[test]
213 fn test_is_valid() {
214 let mut ss = SaveStack::new();
215 let (_, id1) = ss.save(3, false, false, 0, GraphicsState::new(), Vec::new());
216 assert!(ss.is_valid(id1));
217 ss.restore();
218 assert!(!ss.is_valid(id1));
219 }
220
221 #[test]
222 fn test_invalidate_newer() {
223 let mut ss = SaveStack::new();
224 let (_, id1) = ss.save(3, false, false, 0, GraphicsState::new(), Vec::new());
225 let (_, id2) = ss.save(3, false, false, 0, GraphicsState::new(), Vec::new());
226 let (_, id3) = ss.save(3, false, false, 0, GraphicsState::new(), Vec::new());
227
228 ss.invalidate_newer(id1);
229 assert!(ss.is_valid(id1));
230 assert!(!ss.is_valid(id2));
231 assert!(!ss.is_valid(id3));
232 }
233
234 #[test]
235 fn test_add_record_to_current() {
236 let mut ss = SaveStack::new();
237 ss.save(3, false, false, 0, GraphicsState::new(), Vec::new());
238 ss.add_record(SaveRecord {
239 src: EntityId(0),
240 copy: EntityId(1),
241 store_type: StoreType::Array,
242 });
243 ss.add_record(SaveRecord {
244 src: EntityId(2),
245 copy: EntityId(3),
246 store_type: StoreType::Dict,
247 });
248
249 let level = ss.restore().unwrap();
250 assert_eq!(level.records.len(), 2);
251 }
252
253 #[test]
254 fn test_restore_empty() {
255 let mut ss = SaveStack::new();
256 assert!(ss.restore().is_none());
257 }
258
259 #[test]
260 fn test_d_stack_depth_snapshot() {
261 let mut ss = SaveStack::new();
262 ss.save(5, false, false, 0, GraphicsState::new(), Vec::new());
263 let level = ss.restore().unwrap();
264 assert_eq!(level.d_stack_depth, 5);
265 }
266
267 #[test]
268 fn test_unique_save_ids() {
269 let mut ss = SaveStack::new();
270 let (_, id1) = ss.save(3, false, false, 0, GraphicsState::new(), Vec::new());
271 let (_, id2) = ss.save(3, false, false, 0, GraphicsState::new(), Vec::new());
272 ss.restore();
273 let (_, id3) = ss.save(3, false, false, 0, GraphicsState::new(), Vec::new());
274 assert_ne!(id1, id2);
275 assert_ne!(id2, id3);
276 assert_ne!(id1, id3);
277 }
278
279 #[test]
280 fn test_save_level_numbers() {
281 let mut ss = SaveStack::new();
282 let (l1, _) = ss.save(3, false, false, 0, GraphicsState::new(), Vec::new());
283 let (l2, _) = ss.save(3, false, false, 0, GraphicsState::new(), Vec::new());
284 ss.restore();
285 let (l3, _) = ss.save(3, false, false, 0, GraphicsState::new(), Vec::new());
287 assert_eq!(l1, 1);
288 assert_eq!(l2, 2);
289 assert_eq!(l3, 2);
290 }
291}