use crate::{At, Checkpoint, Command, Display, Meta, Queue, Record, RecordBuilder, Signal};
#[cfg(feature = "chrono")]
use chrono::{DateTime, TimeZone};
use rustc_hash::FxHashMap;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::collections::VecDeque;
use std::fmt;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug)]
pub struct History<R, C: Command<R>, F = fn(Signal)> {
root: usize,
next: usize,
pub(crate) saved: Option<At>,
pub(crate) record: Record<R, C, F>,
pub(crate) branches: FxHashMap<usize, Branch<C>>,
}
impl<R, C: Command<R>> History<R, C> {
#[inline]
pub fn new(receiver: impl Into<R>) -> History<R, C> {
History {
root: 0,
next: 1,
saved: None,
record: Record::new(receiver),
branches: FxHashMap::default(),
}
}
}
impl<R, C: Command<R>, F: FnMut(Signal)> History<R, C, F> {
#[inline]
pub fn builder() -> HistoryBuilder<R, C, F> {
HistoryBuilder {
inner: Record::builder(),
}
}
#[inline]
pub fn reserve(&mut self, additional: usize) {
self.record.reserve(additional);
}
#[inline]
pub fn capacity(&self) -> usize {
self.record.capacity()
}
#[inline]
pub fn len(&self) -> usize {
self.record.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.record.is_empty()
}
#[inline]
pub fn limit(&self) -> usize {
self.record.limit()
}
#[inline]
pub fn set_limit(&mut self, limit: usize) -> usize {
let len = self.len();
let limit = self.record.set_limit(limit);
let diff = len - self.len();
let root = self.root();
for current in 0..diff {
self.rm_child(root, current);
}
for branch in self
.branches
.values_mut()
.filter(|branch| branch.parent.branch == root)
{
branch.parent.current -= diff;
}
limit
}
#[inline]
pub fn connect(&mut self, slot: F) -> F {
self.record.connect(slot)
}
#[inline]
pub fn can_undo(&self) -> bool {
self.record.can_undo()
}
#[inline]
pub fn can_redo(&self) -> bool {
self.record.can_redo()
}
#[inline]
pub fn set_saved(&mut self, saved: bool) {
self.record.set_saved(saved);
self.saved = None;
}
#[inline]
pub fn is_saved(&self) -> bool {
self.record.is_saved()
}
#[inline]
pub fn revert(&mut self) -> Option<Result<(), C::Error>> {
if self.record.saved.is_some() {
self.record.revert()
} else {
self.saved
.and_then(|saved| self.go_to(saved.branch, saved.current))
}
}
#[inline]
pub fn root(&self) -> usize {
self.root
}
#[inline]
pub fn current(&self) -> usize {
self.record.current()
}
#[inline]
pub fn clear(&mut self) {
let old = self.root();
self.root = 0;
self.next = 1;
self.saved = None;
self.record.clear();
self.branches.clear();
(self.record.slot)(Signal::Root { old, new: 0 });
}
#[inline]
pub fn apply(&mut self, command: C) -> Result<(), C::Error> {
self.__apply(Meta::from(command)).map(|_| ())
}
#[inline]
pub(crate) fn __apply(&mut self, meta: Meta<C>) -> std::result::Result<bool, C::Error> {
let current = self.current();
let saved = self.record.saved.filter(|&saved| saved > current);
let (merged, commands) = self.record.__apply(meta)?;
if !merged && current == self.current() {
let root = self.root();
self.rm_child(root, 0);
for branch in self
.branches
.values_mut()
.filter(|branch| branch.parent.branch == root)
{
branch.parent.current -= 1;
}
}
if !commands.is_empty() {
let old = self.root();
let new = self.next;
self.next += 1;
self.branches.insert(
old,
Branch {
parent: At {
branch: new,
current,
},
commands,
},
);
self.set_root(new, current);
match (self.record.saved, saved, self.saved) {
(Some(_), None, None) | (None, None, Some(_)) => self.swap_saved(new, old, current),
(None, Some(_), None) => {
self.record.saved = saved;
self.swap_saved(old, new, current);
}
(None, None, None) => (),
_ => unreachable!(),
}
(self.record.slot)(Signal::Root { old, new });
}
Ok(merged)
}
#[inline]
pub fn undo(&mut self) -> Option<Result<(), C::Error>> {
self.record.undo()
}
#[inline]
pub fn redo(&mut self) -> Option<Result<(), C::Error>> {
self.record.redo()
}
#[inline]
pub fn go_to(&mut self, branch: usize, current: usize) -> Option<Result<(), C::Error>> {
let root = self.root;
if root == branch {
return self.record.go_to(current);
}
for (new, branch) in self.mk_path(branch)? {
let old = self.root();
if let Err(err) = self.record.go_to(branch.parent.current).unwrap() {
return Some(Err(err));
}
for meta in branch.commands {
let current = self.current();
let saved = self.record.saved.filter(|&saved| saved > current);
let commands = match self.record.__apply(meta) {
Ok((_, commands)) => commands,
Err(err) => return Some(Err(err)),
};
if !commands.is_empty() {
self.branches.insert(
self.root,
Branch {
parent: At {
branch: new,
current,
},
commands,
},
);
self.set_root(new, current);
match (self.record.saved, saved, self.saved) {
(Some(_), None, None) | (None, None, Some(_)) => {
self.swap_saved(new, old, current);
}
(None, Some(_), None) => {
self.record.saved = saved;
self.swap_saved(old, new, current);
}
(None, None, None) => (),
_ => unreachable!(),
}
}
}
}
if let Err(err) = self.record.go_to(current)? {
return Some(Err(err));
}
(self.record.slot)(Signal::Root {
old: root,
new: self.root,
});
Some(Ok(()))
}
#[inline]
#[cfg(feature = "chrono")]
pub fn time_travel<Tz: TimeZone>(&mut self, to: &DateTime<Tz>) -> Option<Result<(), C::Error>> {
self.record.time_travel(to)
}
#[inline]
pub fn extend(&mut self, commands: impl IntoIterator<Item = C>) -> Result<(), C::Error> {
for command in commands {
self.apply(command)?;
}
Ok(())
}
#[inline]
pub fn checkpoint(&mut self) -> Checkpoint<History<R, C, F>, C> {
Checkpoint::from(self)
}
#[inline]
pub fn queue(&mut self) -> Queue<History<R, C, F>, C> {
Queue::from(self)
}
#[inline]
pub fn as_receiver(&self) -> &R {
self.record.as_receiver()
}
#[inline]
pub fn as_mut_receiver(&mut self) -> &mut R {
self.record.as_mut_receiver()
}
#[inline]
pub fn into_receiver(self) -> R {
self.record.into_receiver()
}
#[inline]
pub fn commands(&self) -> impl Iterator<Item = &C> {
self.record.commands()
}
#[inline]
fn set_root(&mut self, root: usize, current: usize) {
let old = self.root();
self.root = root;
debug_assert_ne!(old, root);
for branch in self
.branches
.values_mut()
.filter(|branch| branch.parent.branch == old && branch.parent.current <= current)
{
branch.parent.branch = root;
}
}
#[inline]
fn swap_saved(&mut self, old: usize, new: usize, current: usize) {
debug_assert_ne!(old, new);
if let Some(At { current: saved, .. }) = self
.saved
.filter(|at| at.branch == new && at.current <= current)
{
self.saved = None;
self.record.saved = Some(saved);
(self.record.slot)(Signal::Saved(true));
} else if let Some(saved) = self.record.saved {
self.saved = Some(At {
branch: old,
current: saved,
});
self.record.saved = None;
(self.record.slot)(Signal::Saved(false));
}
}
#[inline]
fn rm_child(&mut self, branch: usize, current: usize) {
let mut dead: Vec<_> = self
.branches
.iter()
.filter(|&(_, child)| child.parent == At { branch, current })
.map(|(&id, _)| id)
.collect();
while let Some(parent) = dead.pop() {
self.branches.remove(&parent).unwrap();
self.saved = self.saved.filter(|saved| saved.branch != parent);
dead.extend(
self.branches
.iter()
.filter(|&(_, child)| child.parent.branch == parent)
.map(|(&id, _)| id),
)
}
}
#[inline]
fn mk_path(&mut self, mut to: usize) -> Option<impl Iterator<Item = (usize, Branch<C>)>> {
debug_assert_ne!(self.root(), to);
let mut dest = self.branches.remove(&to)?;
let mut i = dest.parent.branch;
let mut path = vec![(to, dest)];
while i != self.root() {
dest = self.branches.remove(&i).unwrap();
to = i;
i = dest.parent.branch;
path.push((to, dest));
}
Some(path.into_iter().rev())
}
}
impl<R, C: Command<R> + ToString, F: FnMut(Signal)> History<R, C, F> {
#[inline]
pub fn to_undo_string(&self) -> Option<String> {
self.record.to_undo_string()
}
#[inline]
pub fn to_redo_string(&self) -> Option<String> {
self.record.to_redo_string()
}
#[inline]
pub fn display(&self) -> Display<Self> {
Display::from(self)
}
}
impl<R: Default, C: Command<R>> Default for History<R, C> {
#[inline]
fn default() -> History<R, C> {
History::new(R::default())
}
}
impl<R, C: Command<R>, F: FnMut(Signal)> AsRef<R> for History<R, C, F> {
#[inline]
fn as_ref(&self) -> &R {
self.as_receiver()
}
}
impl<R, C: Command<R>, F: FnMut(Signal)> AsMut<R> for History<R, C, F> {
#[inline]
fn as_mut(&mut self) -> &mut R {
self.as_mut_receiver()
}
}
impl<R, C: Command<R>> From<R> for History<R, C> {
#[inline]
fn from(receiver: R) -> Self {
History::new(receiver)
}
}
impl<R, C: Command<R>, F: FnMut(Signal)> From<Record<R, C, F>> for History<R, C, F> {
#[inline]
fn from(record: Record<R, C, F>) -> Self {
History {
root: 0,
next: 1,
saved: None,
record,
branches: FxHashMap::default(),
}
}
}
impl<R, C: Command<R> + fmt::Display, F: FnMut(Signal)> fmt::Display for History<R, C, F> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
(&self.display() as &dyn fmt::Display).fmt(f)
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug)]
pub(crate) struct Branch<C> {
pub(crate) parent: At,
pub(crate) commands: VecDeque<Meta<C>>,
}
#[derive(Debug)]
pub struct HistoryBuilder<R, C: Command<R>, F = fn(Signal)> {
inner: RecordBuilder<R, C, F>,
}
impl<R, C: Command<R>> HistoryBuilder<R, C> {
#[inline]
pub fn build(self, receiver: impl Into<R>) -> History<R, C> {
History {
root: 0,
next: 1,
saved: None,
record: self.inner.build(receiver),
branches: FxHashMap::default(),
}
}
}
impl<R, C: Command<R>, F: FnMut(Signal)> HistoryBuilder<R, C, F> {
#[inline]
pub fn capacity(mut self, capacity: usize) -> HistoryBuilder<R, C, F> {
self.inner = self.inner.capacity(capacity);
self
}
#[inline]
pub fn limit(mut self, limit: usize) -> HistoryBuilder<R, C, F> {
self.inner = self.inner.limit(limit);
self
}
#[inline]
pub fn saved(mut self, saved: bool) -> HistoryBuilder<R, C, F> {
self.inner = self.inner.saved(saved);
self
}
#[inline]
pub fn build_with_slot(self, receiver: impl Into<R>, slot: F) -> History<R, C, F> {
History {
root: 0,
next: 1,
saved: None,
record: self.inner.build_with_slot(receiver, slot),
branches: FxHashMap::default(),
}
}
}
impl<R: Default, C: Command<R>> HistoryBuilder<R, C> {
#[inline]
pub fn default(self) -> History<R, C> {
self.build(R::default())
}
}
impl<R: Default, C: Command<R>, F: FnMut(Signal)> HistoryBuilder<R, C, F> {
#[inline]
pub fn default_with_slot(self, slot: F) -> History<R, C, F> {
self.build_with_slot(R::default(), slot)
}
}
#[cfg(test)]
mod tests {
use crate::{Command, History};
#[derive(Debug)]
struct Add(char);
impl Command<String> for Add {
type Error = &'static str;
fn apply(&mut self, receiver: &mut String) -> Result<(), Self::Error> {
receiver.push(self.0);
Ok(())
}
fn undo(&mut self, receiver: &mut String) -> Result<(), Self::Error> {
self.0 = receiver.pop().ok_or("`receiver` is empty")?;
Ok(())
}
}
#[test]
fn go_to() {
let mut history = History::default();
history.apply(Add('a')).unwrap();
history.apply(Add('b')).unwrap();
history.apply(Add('c')).unwrap();
history.apply(Add('d')).unwrap();
history.apply(Add('e')).unwrap();
assert_eq!(history.as_receiver(), "abcde");
history.undo().unwrap().unwrap();
history.undo().unwrap().unwrap();
assert_eq!(history.as_receiver(), "abc");
let abcde = history.root();
history.apply(Add('f')).unwrap();
history.apply(Add('g')).unwrap();
assert_eq!(history.as_receiver(), "abcfg");
history.undo().unwrap().unwrap();
let abcfg = history.root();
history.apply(Add('h')).unwrap();
history.apply(Add('i')).unwrap();
history.apply(Add('j')).unwrap();
assert_eq!(history.as_receiver(), "abcfhij");
history.undo().unwrap().unwrap();
let abcfhij = history.root();
history.apply(Add('k')).unwrap();
assert_eq!(history.as_receiver(), "abcfhik");
history.undo().unwrap().unwrap();
let abcfhik = history.root();
history.apply(Add('l')).unwrap();
assert_eq!(history.as_receiver(), "abcfhil");
history.apply(Add('m')).unwrap();
assert_eq!(history.as_receiver(), "abcfhilm");
let abcfhilm = history.root();
history.go_to(abcde, 2).unwrap().unwrap();
history.apply(Add('n')).unwrap();
history.apply(Add('o')).unwrap();
assert_eq!(history.as_receiver(), "abno");
history.undo().unwrap().unwrap();
let abno = history.root();
history.apply(Add('p')).unwrap();
history.apply(Add('q')).unwrap();
assert_eq!(history.as_receiver(), "abnpq");
let abnpq = history.root();
history.go_to(abcde, 5).unwrap().unwrap();
assert_eq!(history.as_receiver(), "abcde");
history.go_to(abcfg, 5).unwrap().unwrap();
assert_eq!(history.as_receiver(), "abcfg");
history.go_to(abcfhij, 7).unwrap().unwrap();
assert_eq!(history.as_receiver(), "abcfhij");
history.go_to(abcfhik, 7).unwrap().unwrap();
assert_eq!(history.as_receiver(), "abcfhik");
history.go_to(abcfhilm, 8).unwrap().unwrap();
assert_eq!(history.as_receiver(), "abcfhilm");
history.go_to(abno, 4).unwrap().unwrap();
assert_eq!(history.as_receiver(), "abno");
history.go_to(abnpq, 5).unwrap().unwrap();
assert_eq!(history.as_receiver(), "abnpq");
}
}