1#[derive(Debug, Clone)]
11pub struct UndoStack<T: Clone> {
12 history: Vec<T>,
13 index: usize,
14}
15
16impl<T: Clone> UndoStack<T> {
17 pub fn new() -> Self {
19 Self {
20 history: Vec::new(),
21 index: 0,
22 }
23 }
24
25 pub fn push(&mut self, item: T) {
29 self.history.truncate(self.index + 1);
30 self.history.push(item);
31 self.index = self.history.len().saturating_sub(1);
32 }
33
34 pub fn undo(&mut self) -> Option<&T> {
39 if self.index == 0 {
40 self.history.first()
41 } else {
42 self.index -= 1;
43 self.history.get(self.index)
44 }
45 }
46
47 pub fn redo(&mut self) -> Option<&T> {
52 if self.index + 1 < self.history.len() {
53 self.index += 1;
54 self.history.get(self.index)
55 } else {
56 None
57 }
58 }
59
60 pub fn current(&self) -> Option<&T> {
62 self.history.get(self.index)
63 }
64}
65
66impl<T: Clone> Default for UndoStack<T> {
67 fn default() -> Self {
68 Self::new()
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75
76 #[test]
77 fn current_returns_none_when_empty() {
78 let stack: UndoStack<i32> = UndoStack::new();
79 assert!(stack.current().is_none());
80 }
81
82 #[test]
83 fn redo_at_end_returns_none() {
84 let mut stack = UndoStack::new();
85 stack.push(1);
86 assert!(stack.redo().is_none());
87 }
88
89 #[test]
90 fn undo_redo_sequence() {
91 let mut stack = UndoStack::new();
92 stack.push(1);
93 stack.push(2);
94 stack.push(3);
95 assert_eq!(stack.current(), Some(&3));
96 assert_eq!(stack.undo(), Some(&2));
97 assert_eq!(stack.undo(), Some(&1));
98 assert_eq!(stack.undo(), Some(&1));
99 assert_eq!(stack.redo(), Some(&2));
100 assert_eq!(stack.redo(), Some(&3));
101 assert_eq!(stack.redo(), None);
102 }
103
104 #[test]
105 fn push_after_undo_overwrites() {
106 let mut stack = UndoStack::new();
107 stack.push(1);
108 stack.push(2);
109 stack.undo();
110 stack.push(3);
111 assert_eq!(stack.current(), Some(&3));
112 assert_eq!(stack.redo(), None);
113 }
114}