use alloc::vec::Vec;
use maplike::{Get, Insert, KeyedCollection};
use crate::{Delta, Recorder, delta::ApplyDelta};
pub struct CmdDelta<Cmd, DC> {
pub cmd: Cmd,
pub delta: Delta<DC>,
}
pub struct UndoRedo<DC, Cmd = ()> {
done: Vec<CmdDelta<Cmd, DC>>,
undone: Vec<CmdDelta<Cmd, DC>>,
}
impl<Cmd, DC> UndoRedo<DC, Cmd> {
pub fn new() -> Self {
Self {
done: Vec::new(),
undone: Vec::new(),
}
}
pub fn done(&self) -> &[CmdDelta<Cmd, DC>] {
&self.done
}
pub fn undone(&self) -> &[CmdDelta<Cmd, DC>] {
&self.undone
}
}
impl<Cmd: Default, DC> UndoRedo<DC, Cmd> {
pub fn commit(&mut self, delta: Delta<DC>) {
self.cmd_commit(Default::default(), delta);
}
}
impl<Cmd, DC> UndoRedo<DC, Cmd> {
pub fn cmd_commit(&mut self, cmd: Cmd, delta: Delta<DC>) {
self.done.push(CmdDelta { cmd, delta });
self.undone.clear();
}
}
impl<Cmd, DC: KeyedCollection + Default> UndoRedo<DC, Cmd> {
pub fn delta<
K,
V,
C: KeyedCollection<Key = K, Value = V> + Get<K> + Insert<K>,
F: FnOnce(&mut Recorder<C, DC>) -> Cmd,
>(
&mut self,
collection: C,
f: F,
) -> C
where
DC: KeyedCollection<Key = K, Value = V>,
K: Clone,
V: Clone,
{
let mut recorder = Recorder::<C, DC>::new(collection);
let cmd = f(&mut recorder);
let (container, delta) = recorder.dissolve();
self.cmd_commit(cmd, delta);
container
}
}
impl<Cmd: Clone, DC: Clone> UndoRedo<DC, Cmd> {
pub fn undo(&mut self, target: &mut impl ApplyDelta<DC>) -> Option<Cmd> {
let CmdDelta { cmd, delta } = self.done.pop()?;
let reverse_delta = delta.reverse();
target.apply_delta(&reverse_delta);
self.undone.push(CmdDelta {
cmd: cmd.clone(),
delta: reverse_delta,
});
Some(cmd)
}
pub fn redo(&mut self, target: &mut impl ApplyDelta<DC>) -> Option<Cmd> {
let CmdDelta { cmd, delta } = self.undone.pop()?;
let reverse_delta = delta.reverse();
target.apply_delta(&reverse_delta);
self.done.push(CmdDelta {
cmd: cmd.clone(),
delta: reverse_delta,
});
Some(cmd)
}
}