oxihuman_core/
checkpoint_store.rs1#![allow(dead_code)]
4
5#[allow(dead_code)]
7#[derive(Debug, Clone)]
8pub struct Checkpoint {
9 pub name: String,
10 pub data: Vec<u8>,
11 pub timestamp: u64,
12}
13
14#[allow(dead_code)]
15#[derive(Debug, Clone)]
16pub struct CheckpointStore {
17 checkpoints: Vec<Checkpoint>,
18 max_checkpoints: usize,
19 clock: u64,
20}
21
22#[allow(dead_code)]
23impl CheckpointStore {
24 pub fn new(max_checkpoints: usize) -> Self {
25 Self {
26 checkpoints: Vec::new(),
27 max_checkpoints: max_checkpoints.max(1),
28 clock: 0,
29 }
30 }
31
32 pub fn advance_clock(&mut self, dt: u64) {
33 self.clock += dt;
34 }
35
36 pub fn save(&mut self, name: &str, data: Vec<u8>) {
37 if let Some(cp) = self.checkpoints.iter_mut().find(|c| c.name == name) {
38 cp.data = data;
39 cp.timestamp = self.clock;
40 return;
41 }
42 if self.checkpoints.len() >= self.max_checkpoints {
43 self.checkpoints.remove(0);
44 }
45 self.checkpoints.push(Checkpoint {
46 name: name.to_string(),
47 data,
48 timestamp: self.clock,
49 });
50 }
51
52 pub fn restore(&self, name: &str) -> Option<&[u8]> {
53 self.checkpoints
54 .iter()
55 .find(|c| c.name == name)
56 .map(|c| c.data.as_slice())
57 }
58
59 pub fn remove(&mut self, name: &str) -> bool {
60 let before = self.checkpoints.len();
61 self.checkpoints.retain(|c| c.name != name);
62 self.checkpoints.len() < before
63 }
64
65 pub fn count(&self) -> usize {
66 self.checkpoints.len()
67 }
68
69 pub fn names(&self) -> Vec<&str> {
70 self.checkpoints.iter().map(|c| c.name.as_str()).collect()
71 }
72
73 pub fn latest(&self) -> Option<&Checkpoint> {
74 self.checkpoints.iter().max_by_key(|c| c.timestamp)
75 }
76
77 pub fn oldest(&self) -> Option<&Checkpoint> {
78 self.checkpoints.iter().min_by_key(|c| c.timestamp)
79 }
80
81 pub fn total_bytes(&self) -> usize {
82 self.checkpoints.iter().map(|c| c.data.len()).sum()
83 }
84
85 pub fn contains(&self, name: &str) -> bool {
86 self.checkpoints.iter().any(|c| c.name == name)
87 }
88
89 pub fn clear(&mut self) {
90 self.checkpoints.clear();
91 }
92
93 pub fn max_checkpoints(&self) -> usize {
94 self.max_checkpoints
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101
102 #[test]
103 fn test_new() {
104 let cs = CheckpointStore::new(5);
105 assert_eq!(cs.count(), 0);
106 assert_eq!(cs.max_checkpoints(), 5);
107 }
108
109 #[test]
110 fn test_save_and_restore() {
111 let mut cs = CheckpointStore::new(5);
112 cs.save("cp1", vec![1, 2, 3]);
113 assert_eq!(cs.restore("cp1"), Some([1u8, 2, 3].as_slice()));
114 }
115
116 #[test]
117 fn test_overwrite() {
118 let mut cs = CheckpointStore::new(5);
119 cs.save("cp1", vec![1]);
120 cs.save("cp1", vec![2]);
121 assert_eq!(cs.restore("cp1"), Some([2u8].as_slice()));
122 assert_eq!(cs.count(), 1);
123 }
124
125 #[test]
126 fn test_max_eviction() {
127 let mut cs = CheckpointStore::new(2);
128 cs.save("a", vec![1]);
129 cs.save("b", vec![2]);
130 cs.save("c", vec![3]);
131 assert_eq!(cs.count(), 2);
132 assert!(!cs.contains("a"));
133 assert!(cs.contains("c"));
134 }
135
136 #[test]
137 fn test_remove() {
138 let mut cs = CheckpointStore::new(5);
139 cs.save("a", vec![1]);
140 assert!(cs.remove("a"));
141 assert!(!cs.remove("a"));
142 }
143
144 #[test]
145 fn test_latest() {
146 let mut cs = CheckpointStore::new(5);
147 cs.save("a", vec![1]);
148 cs.advance_clock(10);
149 cs.save("b", vec![2]);
150 assert_eq!(cs.latest().expect("should succeed").name, "b");
151 }
152
153 #[test]
154 fn test_oldest() {
155 let mut cs = CheckpointStore::new(5);
156 cs.save("a", vec![1]);
157 cs.advance_clock(10);
158 cs.save("b", vec![2]);
159 assert_eq!(cs.oldest().expect("should succeed").name, "a");
160 }
161
162 #[test]
163 fn test_total_bytes() {
164 let mut cs = CheckpointStore::new(5);
165 cs.save("a", vec![1, 2]);
166 cs.save("b", vec![3, 4, 5]);
167 assert_eq!(cs.total_bytes(), 5);
168 }
169
170 #[test]
171 fn test_names() {
172 let mut cs = CheckpointStore::new(5);
173 cs.save("x", vec![1]);
174 cs.save("y", vec![2]);
175 assert_eq!(cs.names().len(), 2);
176 }
177
178 #[test]
179 fn test_clear() {
180 let mut cs = CheckpointStore::new(5);
181 cs.save("a", vec![1]);
182 cs.clear();
183 assert_eq!(cs.count(), 0);
184 }
185}