use std::fmt::Debug;
use std::fmt::Formatter;
use std::fmt::Result as FmtResult;
use crate::stack::Stack;
pub struct MatrixStack<M, const N: usize, L> {
stack: Stack<M, N>,
load_matrix: L,
}
impl<M, const N: usize, L> MatrixStack<M, N, L>
where
L: FnMut(&M) + 'static,
{
pub fn new(mut load_matrix: L) -> Self
where
M: Default,
{
let default = M::default();
let () = load_matrix(&default);
Self {
stack: Stack::new_with(default),
load_matrix,
}
}
#[inline]
pub fn push<F>(&mut self, f: F)
where
M: Clone,
F: FnOnce(&mut M),
{
let () = self.stack.push();
let () = f(&mut self.stack);
let () = (self.load_matrix)(&mut self.stack);
}
#[inline]
pub fn pop(&mut self) {
let () = self.stack.pop();
let () = (self.load_matrix)(&self.stack);
}
}
impl<M, const N: usize, L> Debug for MatrixStack<M, N, L> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
f.debug_struct("MatrixStack").finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::rc::Rc;
use std::sync::atomic::AtomicIsize;
use std::sync::atomic::Ordering;
#[test]
fn push_pop() {
let top = Rc::new(AtomicIsize::new(0));
let clone = Rc::clone(&top);
let load = move |x: &isize| {
clone.store(*x, Ordering::Relaxed);
};
let mut stack = MatrixStack::<isize, 16, _>::new(load);
let () = stack.push(|x| {
assert_eq!(*x, 0);
*x = 1;
});
assert_eq!(top.load(Ordering::Relaxed), 1);
let () = stack.push(|x| {
assert_eq!(*x, 1);
*x = 2;
});
assert_eq!(top.load(Ordering::Relaxed), 2);
let () = stack.pop();
assert_eq!(top.load(Ordering::Relaxed), 1);
let () = stack.pop();
assert_eq!(top.load(Ordering::Relaxed), 0);
}
}