use crate::{At, Edit, History, Slot};
use alloc::vec::Vec;
#[derive(Debug)]
enum CheckpointEntry {
Edit(usize),
Undo,
Redo,
}
#[derive(Debug)]
pub struct Checkpoint<'a, E, S> {
history: &'a mut History<E, S>,
entries: Vec<CheckpointEntry>,
}
impl<E, S> Checkpoint<'_, E, S> {
pub fn reserve(&mut self, additional: usize) {
self.entries.reserve(additional);
}
pub fn commit(self) {}
}
impl<E: Edit, S: Slot> Checkpoint<'_, E, S> {
pub fn edit(&mut self, target: &mut E::Target, edit: E) -> E::Output {
self.entries.push(CheckpointEntry::Edit(self.history.root));
self.history.edit(target, edit)
}
pub fn undo(&mut self, target: &mut E::Target) -> Option<E::Output> {
self.entries.push(CheckpointEntry::Undo);
self.history.undo(target)
}
pub fn redo(&mut self, target: &mut E::Target) -> Option<E::Output> {
self.entries.push(CheckpointEntry::Redo);
self.history.redo(target)
}
pub fn cancel(self, target: &mut E::Target) -> Vec<E::Output> {
self.entries
.into_iter()
.rev()
.filter_map(|entry| match entry {
CheckpointEntry::Edit(root) => {
let output = self.history.undo(target)?;
if self.history.root == root {
self.history.record.entries.pop_back();
} else {
let mut branch = self.history.branches.remove(root);
debug_assert_eq!(branch.parent, self.history.head());
let new = At::new(root, self.history.record.head());
let (_, rm_saved) = self.history.record.rm_tail();
self.history.record.entries.append(&mut branch.entries);
self.history.set_root(new, rm_saved);
}
Some(output)
}
CheckpointEntry::Undo => self.history.redo(target),
CheckpointEntry::Redo => self.history.undo(target),
})
.collect()
}
}
impl<'a, E, S> From<&'a mut History<E, S>> for Checkpoint<'a, E, S> {
fn from(history: &'a mut History<E, S>) -> Self {
Checkpoint {
history,
entries: Vec::new(),
}
}
}