#[derive(Debug, Clone)]
pub struct UndoStack<S> {
stack: Vec<S>,
max_depth: usize,
}
impl<S> UndoStack<S> {
pub fn new(max_depth: usize) -> Self {
Self {
stack: Vec::new(),
max_depth: max_depth.max(1),
}
}
pub fn push(&mut self, state: S) {
if self.stack.len() >= self.max_depth {
self.stack.remove(0);
}
self.stack.push(state);
}
pub fn pop(&mut self) -> Option<S> {
self.stack.pop()
}
pub fn peek(&self) -> Option<&S> {
self.stack.last()
}
pub fn len(&self) -> usize {
self.stack.len()
}
pub fn is_empty(&self) -> bool {
self.stack.is_empty()
}
pub fn clear(&mut self) {
self.stack.clear();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn push_and_pop() {
let mut undo: UndoStack<i32> = UndoStack::new(10);
undo.push(1);
undo.push(2);
undo.push(3);
assert_eq!(undo.pop(), Some(3));
assert_eq!(undo.pop(), Some(2));
assert_eq!(undo.pop(), Some(1));
assert_eq!(undo.pop(), None);
}
#[test]
fn max_depth_enforced() {
let mut undo: UndoStack<i32> = UndoStack::new(3);
undo.push(1);
undo.push(2);
undo.push(3);
undo.push(4); assert_eq!(undo.len(), 3);
assert_eq!(undo.pop(), Some(4));
assert_eq!(undo.pop(), Some(3));
assert_eq!(undo.pop(), Some(2));
assert_eq!(undo.pop(), None);
}
#[test]
fn peek_does_not_remove() {
let mut undo: UndoStack<i32> = UndoStack::new(10);
undo.push(42);
assert_eq!(undo.peek(), Some(&42));
assert_eq!(undo.len(), 1);
}
#[test]
fn clear_empties_stack() {
let mut undo: UndoStack<i32> = UndoStack::new(10);
undo.push(1);
undo.push(2);
undo.clear();
assert!(undo.is_empty());
}
}