mockforge_foundation/state_machine/
history.rs1use crate::state_machine::rules::StateMachine;
7use std::collections::VecDeque;
8
9#[derive(Debug, Clone)]
14pub struct HistoryManager {
15 undo_stack: VecDeque<StateMachine>,
17
18 redo_stack: VecDeque<StateMachine>,
20
21 max_history: usize,
23
24 current: Option<StateMachine>,
26}
27
28impl HistoryManager {
29 pub fn new() -> Self {
31 Self::with_max_history(50)
32 }
33
34 pub fn with_max_history(max_history: usize) -> Self {
36 Self {
37 undo_stack: VecDeque::new(),
38 redo_stack: VecDeque::new(),
39 max_history,
40 current: None,
41 }
42 }
43
44 pub fn push_state(&mut self, state: StateMachine) {
49 if let Some(current) = self.current.take() {
51 if self.undo_stack.len() >= self.max_history {
53 self.undo_stack.pop_front();
54 }
55 self.undo_stack.push_back(current);
56 }
57
58 self.redo_stack.clear();
60
61 self.current = Some(state);
63 }
64
65 pub fn undo(&mut self) -> Option<StateMachine> {
70 if self.undo_stack.is_empty() {
71 return None;
72 }
73
74 if let Some(current) = self.current.take() {
76 if self.redo_stack.len() >= self.max_history {
78 self.redo_stack.pop_front();
79 }
80 self.redo_stack.push_back(current);
81 }
82
83 let restored = self.undo_stack.pop_back()?;
85 self.current = Some(restored.clone());
86 Some(restored)
87 }
88
89 pub fn redo(&mut self) -> Option<StateMachine> {
94 if self.redo_stack.is_empty() {
95 return None;
96 }
97
98 if let Some(current) = self.current.take() {
100 if self.undo_stack.len() >= self.max_history {
102 self.undo_stack.pop_front();
103 }
104 self.undo_stack.push_back(current);
105 }
106
107 let restored = self.redo_stack.pop_back()?;
109 self.current = Some(restored.clone());
110 Some(restored)
111 }
112
113 pub fn can_undo(&self) -> bool {
115 !self.undo_stack.is_empty()
116 }
117
118 pub fn can_redo(&self) -> bool {
120 !self.redo_stack.is_empty()
121 }
122
123 pub fn current(&self) -> Option<&StateMachine> {
125 self.current.as_ref()
126 }
127
128 pub fn current_mut(&mut self) -> Option<&mut StateMachine> {
130 self.current.as_mut()
131 }
132
133 pub fn set_current(&mut self, state: StateMachine) {
137 self.current = Some(state);
138 }
139
140 pub fn clear(&mut self) {
142 self.undo_stack.clear();
143 self.redo_stack.clear();
144 self.current = None;
145 }
146
147 pub fn undo_count(&self) -> usize {
149 self.undo_stack.len()
150 }
151
152 pub fn redo_count(&self) -> usize {
154 self.redo_stack.len()
155 }
156
157 pub fn max_history(&self) -> usize {
159 self.max_history
160 }
161
162 pub fn set_max_history(&mut self, max_history: usize) {
166 self.max_history = max_history;
167
168 while self.undo_stack.len() > max_history {
170 self.undo_stack.pop_front();
171 }
172
173 while self.redo_stack.len() > max_history {
175 self.redo_stack.pop_front();
176 }
177 }
178}
179
180impl Default for HistoryManager {
181 fn default() -> Self {
182 Self::new()
183 }
184}
185
186#[cfg(test)]
187mod tests {
188 use super::*;
189 use crate::state_machine::rules::{StateMachine, StateTransition};
190
191 fn create_test_machine(name: &str) -> StateMachine {
192 StateMachine::new(
193 format!("resource_{}", name),
194 vec!["state1".to_string(), "state2".to_string()],
195 "state1",
196 )
197 .add_transition(StateTransition::new("state1", "state2"))
198 }
199
200 #[test]
201 fn test_history_manager_creation() {
202 let manager = HistoryManager::new();
203 assert!(!manager.can_undo());
204 assert!(!manager.can_redo());
205 }
206
207 #[test]
208 fn test_push_and_undo() {
209 let mut manager = HistoryManager::new();
210 let state1 = create_test_machine("1");
211 let state2 = create_test_machine("2");
212
213 manager.push_state(state1.clone());
214 manager.push_state(state2.clone());
215
216 assert!(manager.can_undo());
217 let restored = manager.undo().unwrap();
218 assert_eq!(restored.resource_type, state1.resource_type);
219 }
220
221 #[test]
222 fn test_undo_redo() {
223 let mut manager = HistoryManager::new();
224 let state1 = create_test_machine("1");
225 let state2 = create_test_machine("2");
226
227 manager.push_state(state1.clone());
228 manager.push_state(state2.clone());
229
230 let restored = manager.undo().unwrap();
232 assert_eq!(restored.resource_type, state1.resource_type);
233
234 let restored = manager.redo().unwrap();
236 assert_eq!(restored.resource_type, state2.resource_type);
237 }
238
239 #[test]
240 fn test_max_history() {
241 let mut manager = HistoryManager::with_max_history(3);
242
243 for i in 0..5 {
244 manager.push_state(create_test_machine(&i.to_string()));
245 }
246
247 assert_eq!(manager.undo_count(), 3);
249 }
250
251 #[test]
252 fn test_clear_redo_on_new_push() {
253 let mut manager = HistoryManager::new();
254 let state1 = create_test_machine("1");
255 let state2 = create_test_machine("2");
256 let state3 = create_test_machine("3");
257
258 manager.push_state(state1);
259 manager.push_state(state2);
260 manager.undo(); assert!(manager.can_redo());
262
263 manager.push_state(state3); assert!(!manager.can_redo());
265 }
266}