sorting_race/services/
snapshot.rs

1//! Snapshot functionality for algorithm states
2
3use crate::models::traits::{Sorter, Telemetry};
4use crate::models::metrics::MetricsSnapshot;
5use std::time::SystemTime;
6
7/// A snapshot of the complete algorithm race state
8#[derive(Debug, Clone)]
9pub struct RaceSnapshot {
10    /// Timestamp when snapshot was taken
11    pub timestamp: SystemTime,
12    /// Snapshots of all algorithms
13    pub algorithm_snapshots: Vec<AlgorithmSnapshot>,
14    /// Current step number
15    pub step: usize,
16    /// Whether the race is complete
17    pub race_complete: bool,
18}
19
20/// Snapshot of a single algorithm's state
21#[derive(Debug, Clone)]
22pub struct AlgorithmSnapshot {
23    /// Algorithm name
24    pub name: String,
25    /// Current array state
26    pub array_state: Vec<i32>,
27    /// Telemetry data
28    pub telemetry: Telemetry,
29    /// Whether algorithm is complete
30    pub is_complete: bool,
31    /// Metrics snapshot
32    pub metrics: MetricsSnapshot,
33}
34
35/// Service for creating and managing snapshots
36#[derive(Debug, Default)]
37pub struct SnapshotService {
38    snapshots: Vec<RaceSnapshot>,
39    max_snapshots: usize,
40}
41
42impl SnapshotService {
43    /// Create a new snapshot service
44    pub fn new(max_snapshots: usize) -> Self {
45        Self {
46            snapshots: Vec::new(),
47            max_snapshots: max_snapshots.max(1),
48        }
49    }
50
51    /// Take a snapshot of the current race state
52    pub fn take_snapshot(&mut self, algorithms: &[Box<dyn Sorter>], step: usize) -> &RaceSnapshot {
53        let race_complete = algorithms.iter().all(|alg| alg.is_complete());
54        
55        let algorithm_snapshots = algorithms
56            .iter()
57            .map(|algorithm| {
58                let telemetry = algorithm.get_telemetry();
59                let metrics = crate::models::metrics::Metrics {
60                    comparisons: telemetry.total_comparisons,
61                    moves: telemetry.total_moves,
62                    execution_time_us: 0, // Stub value
63                    peak_memory_bytes: telemetry.memory_peak,
64                    current_memory_bytes: telemetry.memory_current,
65                    steps: step,
66                    array_accesses: telemetry.total_comparisons + telemetry.total_moves,
67                    recursive_calls: 0, // Stub value
68                };
69
70                AlgorithmSnapshot {
71                    name: algorithm.name().to_string(),
72                    array_state: algorithm.get_array().to_vec(),
73                    telemetry,
74                    is_complete: algorithm.is_complete(),
75                    metrics: MetricsSnapshot::new(
76                        metrics,
77                        SystemTime::now()
78                            .duration_since(SystemTime::UNIX_EPOCH)
79                            .unwrap()
80                            .as_micros() as u64,
81                        algorithm.name().to_string(),
82                    ),
83                }
84            })
85            .collect();
86
87        let snapshot = RaceSnapshot {
88            timestamp: SystemTime::now(),
89            algorithm_snapshots,
90            step,
91            race_complete,
92        };
93
94        // Add snapshot and maintain max limit
95        self.snapshots.push(snapshot);
96        if self.snapshots.len() > self.max_snapshots {
97            self.snapshots.remove(0);
98        }
99
100        self.snapshots.last().unwrap()
101    }
102
103    /// Get all snapshots
104    pub fn get_snapshots(&self) -> &[RaceSnapshot] {
105        &self.snapshots
106    }
107
108    /// Get the most recent snapshot
109    pub fn get_latest_snapshot(&self) -> Option<&RaceSnapshot> {
110        self.snapshots.last()
111    }
112
113    /// Get snapshot by index
114    pub fn get_snapshot(&self, index: usize) -> Option<&RaceSnapshot> {
115        self.snapshots.get(index)
116    }
117
118    /// Clear all snapshots
119    pub fn clear(&mut self) {
120        self.snapshots.clear();
121    }
122
123    /// Get number of snapshots
124    pub fn len(&self) -> usize {
125        self.snapshots.len()
126    }
127
128    /// Check if no snapshots exist
129    pub fn is_empty(&self) -> bool {
130        self.snapshots.is_empty()
131    }
132
133    /// Set maximum number of snapshots to keep
134    pub fn set_max_snapshots(&mut self, max: usize) {
135        self.max_snapshots = max.max(1);
136        
137        // Trim existing snapshots if necessary
138        while self.snapshots.len() > self.max_snapshots {
139            self.snapshots.remove(0);
140        }
141    }
142
143    /// Get maximum number of snapshots
144    pub fn get_max_snapshots(&self) -> usize {
145        self.max_snapshots
146    }
147}
148
149#[cfg(test)]
150mod tests {
151    use super::*;
152    use crate::services::sorters::bubble::BubbleSort;
153
154    #[test]
155    fn test_snapshot_service_creation() {
156        let service = SnapshotService::new(10);
157        assert_eq!(service.len(), 0);
158        assert!(service.is_empty());
159        assert_eq!(service.get_max_snapshots(), 10);
160    }
161
162    #[test]
163    fn test_take_snapshot() {
164        let mut service = SnapshotService::new(5);
165        let mut bubble = BubbleSort::new();
166        bubble.reset(vec![3, 1, 2]);
167
168        let algorithms: Vec<Box<dyn Sorter>> = vec![Box::new(bubble)];
169        
170        let snapshot = service.take_snapshot(&algorithms, 1);
171        assert_eq!(snapshot.step, 1);
172        assert_eq!(snapshot.algorithm_snapshots.len(), 1);
173        assert_eq!(service.len(), 1);
174    }
175
176    #[test]
177    fn test_max_snapshots_limit() {
178        let mut service = SnapshotService::new(3);
179        let bubble = BubbleSort::new();
180        let algorithms: Vec<Box<dyn Sorter>> = vec![Box::new(bubble)];
181
182        // Take more snapshots than the limit
183        for i in 0..5 {
184            service.take_snapshot(&algorithms, i);
185        }
186
187        assert_eq!(service.len(), 3); // Should not exceed max
188        
189        // Should have the last 3 snapshots (steps 2, 3, 4)
190        let snapshots = service.get_snapshots();
191        assert_eq!(snapshots[0].step, 2);
192        assert_eq!(snapshots[1].step, 3);
193        assert_eq!(snapshots[2].step, 4);
194    }
195}