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
32#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
38pub struct VmMarks {
39 pub string_data: usize,
40 pub string_entities: usize,
41 pub array_data: usize,
42 pub array_entities: usize,
43 pub dict_slots: usize,
44 pub dict_entities: usize,
45}
46
47pub struct SaveSnapshot {
53 pub d_stack_depth: usize,
55 pub packing_mode: bool,
57 pub vm_alloc_mode: bool,
59 pub object_format: i32,
61 pub gstate: GraphicsState,
63 pub gstate_stack: Vec<GstateEntry>,
64 pub gstate_store_len: usize,
71 pub marks: VmMarks,
73}
74
75pub struct SaveLevel {
77 pub level: u16,
79 pub save_id: u32,
81 pub records: Vec<SaveRecord>,
83 pub valid: bool,
85 pub d_stack_depth: usize,
87 pub packing_mode: bool,
89 pub vm_alloc_mode: bool,
91 pub object_format: i32,
93 pub gstate: GraphicsState,
95 pub gstate_stack: Vec<GstateEntry>,
96 pub gstate_store_len: usize,
103 pub marks: VmMarks,
105}
106
107pub struct SaveStack {
109 levels: Vec<SaveLevel>,
110 next_save_id: u32,
111}
112
113impl SaveStack {
114 pub fn new() -> Self {
116 Self {
117 levels: Vec::new(),
118 next_save_id: 1,
119 }
120 }
121
122 pub fn save(&mut self, snapshot: SaveSnapshot) -> (u16, u32) {
124 let SaveSnapshot {
125 d_stack_depth,
126 packing_mode,
127 vm_alloc_mode,
128 object_format,
129 gstate,
130 gstate_stack,
131 gstate_store_len,
132 marks,
133 } = snapshot;
134 let level = (self.levels.len() + 1) as u16;
135 let save_id = self.next_save_id;
136 self.next_save_id += 1;
137 self.levels.push(SaveLevel {
138 level,
139 save_id,
140 records: Vec::new(),
141 valid: true,
142 d_stack_depth,
143 packing_mode,
144 vm_alloc_mode,
145 object_format,
146 gstate,
147 gstate_stack,
148 gstate_store_len,
149 marks,
150 });
151 (level, save_id)
152 }
153
154 pub fn add_record(&mut self, record: SaveRecord) {
156 if let Some(level) = self.levels.last_mut() {
157 level.records.push(record);
158 }
159 }
160
161 pub fn restore(&mut self) -> Option<SaveLevel> {
164 self.levels.pop()
165 }
166
167 pub fn restore_to(&mut self, save_id: u32) -> Option<Vec<SaveLevel>> {
173 let idx = self.levels.iter().position(|l| l.save_id == save_id)?;
174 let popped: Vec<SaveLevel> = self.levels.drain(idx..).collect();
175 Some(popped)
176 }
177
178 pub fn current_level(&self) -> u16 {
180 self.levels.last().map(|l| l.level).unwrap_or(0)
181 }
182
183 pub fn last_save_id(&self) -> u32 {
186 self.levels.last().map(|l| l.save_id).unwrap_or(0)
187 }
188
189 pub fn is_valid(&self, save_id: u32) -> bool {
191 self.levels.iter().any(|l| l.save_id == save_id && l.valid)
192 }
193
194 pub fn depth(&self) -> usize {
196 self.levels.len()
197 }
198
199 pub fn levels_ref(&self) -> &[SaveLevel] {
201 &self.levels
202 }
203
204 pub fn invalidate_newer(&mut self, save_id: u32) {
206 let mut found = false;
207 for level in &mut self.levels {
208 if found {
209 level.valid = false;
210 }
211 if level.save_id == save_id {
212 found = true;
213 }
214 }
215 }
216}
217
218impl Default for SaveStack {
219 fn default() -> Self {
220 Self::new()
221 }
222}
223
224#[cfg(test)]
225mod tests {
226 use super::*;
227
228 #[test]
229 fn test_save_and_depth() {
230 let mut ss = SaveStack::new();
231 assert_eq!(ss.depth(), 0);
232 assert_eq!(ss.current_level(), 0);
233
234 let (level, id) = ss.save(SaveSnapshot {
235 d_stack_depth: 3,
236 packing_mode: false,
237 vm_alloc_mode: false,
238 object_format: 0,
239 gstate: GraphicsState::new(),
240 gstate_stack: Vec::new(),
241 gstate_store_len: 0,
242 marks: VmMarks::default(),
243 });
244 assert_eq!(level, 1);
245 assert_eq!(id, 1);
246 assert_eq!(ss.depth(), 1);
247 assert_eq!(ss.current_level(), 1);
248 }
249
250 #[test]
251 fn test_nested_save() {
252 let mut ss = SaveStack::new();
253 let (l1, _) = ss.save(SaveSnapshot {
254 d_stack_depth: 3,
255 packing_mode: false,
256 vm_alloc_mode: false,
257 object_format: 0,
258 gstate: GraphicsState::new(),
259 gstate_stack: Vec::new(),
260 gstate_store_len: 0,
261 marks: VmMarks::default(),
262 });
263 let (l2, _) = ss.save(SaveSnapshot {
264 d_stack_depth: 3,
265 packing_mode: false,
266 vm_alloc_mode: false,
267 object_format: 0,
268 gstate: GraphicsState::new(),
269 gstate_stack: Vec::new(),
270 gstate_store_len: 0,
271 marks: VmMarks::default(),
272 });
273 assert_eq!(l1, 1);
274 assert_eq!(l2, 2);
275 assert_eq!(ss.depth(), 2);
276 assert_eq!(ss.current_level(), 2);
277 }
278
279 #[test]
280 fn test_restore() {
281 let mut ss = SaveStack::new();
282 let (_, id1) = ss.save(SaveSnapshot {
283 d_stack_depth: 3,
284 packing_mode: false,
285 vm_alloc_mode: false,
286 object_format: 0,
287 gstate: GraphicsState::new(),
288 gstate_stack: Vec::new(),
289 gstate_store_len: 0,
290 marks: VmMarks::default(),
291 });
292 ss.add_record(SaveRecord {
293 src: EntityId(0),
294 copy: EntityId(1),
295 store_type: StoreType::String,
296 });
297
298 let level = ss.restore().unwrap();
299 assert_eq!(level.save_id, id1);
300 assert_eq!(level.records.len(), 1);
301 assert_eq!(ss.depth(), 0);
302 }
303
304 #[test]
305 fn test_is_valid() {
306 let mut ss = SaveStack::new();
307 let (_, id1) = ss.save(SaveSnapshot {
308 d_stack_depth: 3,
309 packing_mode: false,
310 vm_alloc_mode: false,
311 object_format: 0,
312 gstate: GraphicsState::new(),
313 gstate_stack: Vec::new(),
314 gstate_store_len: 0,
315 marks: VmMarks::default(),
316 });
317 assert!(ss.is_valid(id1));
318 ss.restore();
319 assert!(!ss.is_valid(id1));
320 }
321
322 #[test]
323 fn test_invalidate_newer() {
324 let mut ss = SaveStack::new();
325 let (_, id1) = ss.save(SaveSnapshot {
326 d_stack_depth: 3,
327 packing_mode: false,
328 vm_alloc_mode: false,
329 object_format: 0,
330 gstate: GraphicsState::new(),
331 gstate_stack: Vec::new(),
332 gstate_store_len: 0,
333 marks: VmMarks::default(),
334 });
335 let (_, id2) = ss.save(SaveSnapshot {
336 d_stack_depth: 3,
337 packing_mode: false,
338 vm_alloc_mode: false,
339 object_format: 0,
340 gstate: GraphicsState::new(),
341 gstate_stack: Vec::new(),
342 gstate_store_len: 0,
343 marks: VmMarks::default(),
344 });
345 let (_, id3) = ss.save(SaveSnapshot {
346 d_stack_depth: 3,
347 packing_mode: false,
348 vm_alloc_mode: false,
349 object_format: 0,
350 gstate: GraphicsState::new(),
351 gstate_stack: Vec::new(),
352 gstate_store_len: 0,
353 marks: VmMarks::default(),
354 });
355
356 ss.invalidate_newer(id1);
357 assert!(ss.is_valid(id1));
358 assert!(!ss.is_valid(id2));
359 assert!(!ss.is_valid(id3));
360 }
361
362 #[test]
363 fn test_add_record_to_current() {
364 let mut ss = SaveStack::new();
365 ss.save(SaveSnapshot {
366 d_stack_depth: 3,
367 packing_mode: false,
368 vm_alloc_mode: false,
369 object_format: 0,
370 gstate: GraphicsState::new(),
371 gstate_stack: Vec::new(),
372 gstate_store_len: 0,
373 marks: VmMarks::default(),
374 });
375 ss.add_record(SaveRecord {
376 src: EntityId(0),
377 copy: EntityId(1),
378 store_type: StoreType::Array,
379 });
380 ss.add_record(SaveRecord {
381 src: EntityId(2),
382 copy: EntityId(3),
383 store_type: StoreType::Dict,
384 });
385
386 let level = ss.restore().unwrap();
387 assert_eq!(level.records.len(), 2);
388 }
389
390 #[test]
391 fn test_restore_empty() {
392 let mut ss = SaveStack::new();
393 assert!(ss.restore().is_none());
394 }
395
396 #[test]
397 fn test_d_stack_depth_snapshot() {
398 let mut ss = SaveStack::new();
399 ss.save(SaveSnapshot {
400 d_stack_depth: 5,
401 packing_mode: false,
402 vm_alloc_mode: false,
403 object_format: 0,
404 gstate: GraphicsState::new(),
405 gstate_stack: Vec::new(),
406 gstate_store_len: 0,
407 marks: VmMarks::default(),
408 });
409 let level = ss.restore().unwrap();
410 assert_eq!(level.d_stack_depth, 5);
411 }
412
413 #[test]
414 fn test_unique_save_ids() {
415 let mut ss = SaveStack::new();
416 let (_, id1) = ss.save(SaveSnapshot {
417 d_stack_depth: 3,
418 packing_mode: false,
419 vm_alloc_mode: false,
420 object_format: 0,
421 gstate: GraphicsState::new(),
422 gstate_stack: Vec::new(),
423 gstate_store_len: 0,
424 marks: VmMarks::default(),
425 });
426 let (_, id2) = ss.save(SaveSnapshot {
427 d_stack_depth: 3,
428 packing_mode: false,
429 vm_alloc_mode: false,
430 object_format: 0,
431 gstate: GraphicsState::new(),
432 gstate_stack: Vec::new(),
433 gstate_store_len: 0,
434 marks: VmMarks::default(),
435 });
436 ss.restore();
437 let (_, id3) = ss.save(SaveSnapshot {
438 d_stack_depth: 3,
439 packing_mode: false,
440 vm_alloc_mode: false,
441 object_format: 0,
442 gstate: GraphicsState::new(),
443 gstate_stack: Vec::new(),
444 gstate_store_len: 0,
445 marks: VmMarks::default(),
446 });
447 assert_ne!(id1, id2);
448 assert_ne!(id2, id3);
449 assert_ne!(id1, id3);
450 }
451
452 #[test]
453 fn test_save_level_numbers() {
454 let mut ss = SaveStack::new();
455 let (l1, _) = ss.save(SaveSnapshot {
456 d_stack_depth: 3,
457 packing_mode: false,
458 vm_alloc_mode: false,
459 object_format: 0,
460 gstate: GraphicsState::new(),
461 gstate_stack: Vec::new(),
462 gstate_store_len: 0,
463 marks: VmMarks::default(),
464 });
465 let (l2, _) = ss.save(SaveSnapshot {
466 d_stack_depth: 3,
467 packing_mode: false,
468 vm_alloc_mode: false,
469 object_format: 0,
470 gstate: GraphicsState::new(),
471 gstate_stack: Vec::new(),
472 gstate_store_len: 0,
473 marks: VmMarks::default(),
474 });
475 ss.restore();
476 let (l3, _) = ss.save(SaveSnapshot {
478 d_stack_depth: 3,
479 packing_mode: false,
480 vm_alloc_mode: false,
481 object_format: 0,
482 gstate: GraphicsState::new(),
483 gstate_stack: Vec::new(),
484 gstate_store_len: 0,
485 marks: VmMarks::default(),
486 });
487 assert_eq!(l1, 1);
488 assert_eq!(l2, 2);
489 assert_eq!(l3, 2);
490 }
491}