mf_core/
history_manager.rs1pub struct History<T: Clone> {
3 pub past: Vec<T>,
4 pub present: T,
5 pub future: Vec<T>,
6 pub latest_unfiltered: T,
7}
8
9impl<T: Clone> History<T> {
10 pub fn new(
12 past: Vec<T>,
13 present: T,
14 future: Vec<T>,
15 ) -> Self {
16 let latest_unfiltered = present.clone();
17 History { past, present, future, latest_unfiltered }
18 }
19}
20
21use crate::config::HistoryConfig;
22
23pub struct HistoryManager<T: Clone> {
25 config: HistoryConfig,
26 history: History<T>,
27}
28
29impl<T: Clone> HistoryManager<T> {
30 pub fn new(
32 initial_state: T,
33 history_limit: Option<usize>,
34 ) -> Self {
35 let mut config = HistoryConfig::default();
36 if let Some(limit) = history_limit {
37 config.max_entries = limit;
38 }
39 Self::with_config(initial_state, config)
40 }
41
42 pub fn with_config(
44 initial_state: T,
45 config: HistoryConfig,
46 ) -> Self {
47 HistoryManager {
48 config,
49 history: History::new(Vec::new(), initial_state, Vec::new()),
50 }
51 }
52 pub fn get_present(&self) -> T {
54 self.history.present.clone()
55 }
56 pub fn get_history(&self) -> &History<T> {
58 &self.history
59 }
60 pub fn get_history_length(&self) -> usize {
62 self.history.past.len() + self.history.future.len() + 1
63 }
64
65 pub fn get_config(&self) -> &HistoryConfig {
67 &self.config
68 }
69
70 pub fn update_config(
72 &mut self,
73 config: HistoryConfig,
74 ) {
75 self.config = config;
76 }
77 pub fn insert(
81 &mut self,
82 state: T,
83 ) {
84 let past = &self.history.past;
85 let length = past.len() + 1;
86
87 let past_sliced = if length >= self.config.max_entries {
89 if past.is_empty() { Vec::new() } else { past[1..].to_vec() }
90 } else {
91 past.clone()
92 };
93
94 let mut new_past = past_sliced;
96 new_past.push(self.history.latest_unfiltered.clone());
97
98 self.history = History::new(new_past, state.clone(), Vec::new());
99 self.history.latest_unfiltered = state;
100 }
101
102 pub fn jump_to_future(
108 &mut self,
109 index: usize,
110 ) {
111 if index >= self.history.future.len() {
113 return;
114 }
115
116 let mut new_past = self.history.past.clone();
118 new_past.push(self.history.latest_unfiltered.clone());
119
120 if index > 0 {
122 new_past.extend_from_slice(&self.history.future[..index]);
123 }
124
125 let new_present = self.history.future[index].clone();
126
127 let new_future = if index + 1 < self.history.future.len() {
129 self.history.future[index + 1..].to_vec()
130 } else {
131 Vec::new()
132 };
133
134 self.history = History::new(new_past, new_present, new_future);
135 }
136
137 pub fn jump_to_past(
143 &mut self,
144 index: usize,
145 ) {
146 if index >= self.history.past.len() {
148 return;
149 }
150
151 let new_past = if index > 0 {
153 self.history.past[..index].to_vec()
154 } else {
155 Vec::new()
156 };
157
158 let mut new_future = Vec::new();
160
161 if index + 1 < self.history.past.len() {
163 new_future.extend_from_slice(&self.history.past[index + 1..]);
164 }
165
166 new_future.push(self.history.latest_unfiltered.clone());
168
169 new_future.extend_from_slice(&self.history.future);
171
172 let new_present = self.history.past[index].clone();
173
174 self.history = History::new(new_past, new_present, new_future);
175 }
176
177 pub fn jump(
189 &mut self,
190 n: isize,
191 ) {
192 match n.cmp(&0) {
193 std::cmp::Ordering::Less => {
194 let past_len = self.history.past.len() as isize;
196 let target = past_len + n; if target >= 0 && (target as usize) < self.history.past.len() {
200 self.jump_to_past(target as usize);
201 }
202 },
204 std::cmp::Ordering::Equal => {
205 },
207 std::cmp::Ordering::Greater => {
208 let future_index = (n - 1) as usize; if future_index < self.history.future.len() {
213 self.jump_to_future(future_index);
214 }
215 },
217 }
218 }
219
220 pub fn clear_history(&mut self) {
222 let present = self.history.present.clone();
223 self.history = History::new(Vec::new(), present, Vec::new());
224 }
225
226 pub fn get_past_state(
231 &self,
232 index: usize,
233 ) -> Option<&T> {
234 self.history.past.get(index)
235 }
236
237 pub fn get_future_state(
242 &self,
243 index: usize,
244 ) -> Option<&T> {
245 self.history.future.get(index)
246 }
247
248 pub fn can_undo(&self) -> bool {
250 !self.history.past.is_empty()
251 }
252
253 pub fn can_redo(&self) -> bool {
255 !self.history.future.is_empty()
256 }
257
258 pub fn past_count(&self) -> usize {
260 self.history.past.len()
261 }
262
263 pub fn future_count(&self) -> usize {
265 self.history.future.len()
266 }
267
268 pub fn validate_integrity(&self) -> bool {
272 if self.config.max_entries == 0 {
274 return false;
275 }
276
277 let total_length =
279 self.history.past.len() + 1 + self.history.future.len();
280 if total_length > self.config.max_entries {
281 return false;
282 }
283
284 true
285 }
286}
287
288#[cfg(test)]
289mod tests {
290 use super::*;
291
292 #[test]
293 fn test_insert_with_limit() {
294 let mut manager = HistoryManager::with_config(
295 "initial".to_string(),
296 HistoryConfig { max_entries: 3, ..Default::default() },
297 );
298
299 manager.insert("state1".to_string());
301 manager.insert("state2".to_string());
302 manager.insert("state3".to_string()); assert_eq!(manager.past_count(), 2); assert_eq!(manager.get_present(), "state3");
306 assert!(manager.validate_integrity());
307 }
308
309 #[test]
310 fn test_jump_boundary_checks() {
311 let mut manager = HistoryManager::new("initial".to_string(), Some(10));
312
313 manager.insert("state1".to_string());
314 manager.insert("state2".to_string());
315
316 manager.jump_to_past(0); assert_eq!(manager.get_present(), "initial");
319
320 manager.jump_to_past(100); assert_eq!(manager.get_present(), "initial");
323
324 manager.jump_to_future(0); assert_eq!(manager.get_present(), "state1");
327
328 manager.jump_to_future(100); assert_eq!(manager.get_present(), "state1");
331 }
332
333 #[test]
334 fn test_safe_access_methods() {
335 let mut manager = HistoryManager::new("initial".to_string(), Some(10));
336 manager.insert("state1".to_string());
337 manager.insert("state2".to_string());
338
339 assert_eq!(manager.get_past_state(0), Some(&"initial".to_string()));
341 assert_eq!(manager.get_past_state(100), None);
342
343 manager.jump_to_past(0);
345 assert_eq!(manager.get_future_state(0), Some(&"state1".to_string()));
346 assert_eq!(manager.get_future_state(100), None);
347 }
348
349 #[test]
350 fn test_can_undo_redo() {
351 let mut manager = HistoryManager::new("initial".to_string(), Some(10));
352
353 assert!(!manager.can_undo());
355 assert!(!manager.can_redo());
356
357 manager.insert("state1".to_string());
359 assert!(manager.can_undo());
360 assert!(!manager.can_redo());
361
362 manager.jump_to_past(0);
364 assert!(!manager.can_undo());
365 assert!(manager.can_redo());
366 }
367
368 #[test]
369 fn test_jump_with_bounds() {
370 let mut manager = HistoryManager::new("initial".to_string(), Some(10));
371 manager.insert("state1".to_string());
372 manager.insert("state2".to_string());
373
374 manager.jump(-10); assert_eq!(manager.get_present(), "state2");
377
378 manager.jump(-1); assert_eq!(manager.get_present(), "state1");
380
381 manager.jump(10); assert_eq!(manager.get_present(), "state1");
383
384 manager.jump(1); assert_eq!(manager.get_present(), "state2");
386 }
387}