#[cfg(feature = "display")]
use crate::Display;
use crate::{At, Checkpoint, Command, Entry, Queue, Record, RecordBuilder, Result, Signal};
use alloc::collections::{BTreeMap, VecDeque};
use alloc::string::{String, ToString};
use alloc::vec;
use alloc::vec::Vec;
#[cfg(feature = "chrono")]
use chrono::{DateTime, TimeZone};
use core::fmt;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(bound(
serialize = "C: Command + Serialize, C::Target: Serialize",
deserialize = "C: Command + Deserialize<'de>, C::Target: Deserialize<'de>"
))
)]
pub struct History<C: Command, F = fn(Signal)> {
root: usize,
next: usize,
pub(crate) saved: Option<At>,
pub(crate) record: Record<C, F>,
pub(crate) branches: BTreeMap<usize, Branch<C>>,
}
impl<C: Command> History<C> {
#[inline]
pub fn new(target: C::Target) -> History<C> {
History::from(Record::new(target))
}
#[inline]
pub fn builder() -> HistoryBuilder<C> {
HistoryBuilder::new()
}
}
impl<C: Command, F> History<C, F> {
#[inline]
pub fn reserve(&mut self, additional: usize) {
self.record.reserve(additional);
}
#[inline]
pub fn capacity(&self) -> usize {
self.record.capacity()
}
#[inline]
pub fn shrink_to_fit(&mut self) {
self.record.shrink_to_fit();
}
#[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 connect(&mut self, slot: F) -> Option<F> {
self.record.connect(slot)
}
#[inline]
pub fn connect_with<G>(self, slot: G) -> History<C, G> {
History {
root: self.root,
next: self.next,
saved: self.saved,
record: self.record.connect_with(slot),
branches: self.branches,
}
}
#[inline]
pub fn disconnect(&mut self) -> Option<F> {
self.record.disconnect()
}
#[inline]
pub fn is_saved(&self) -> bool {
self.record.is_saved()
}
#[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 branch(&self) -> usize {
self.root
}
#[inline]
pub fn current(&self) -> usize {
self.record.current()
}
#[inline]
pub fn checkpoint(&mut self) -> Checkpoint<History<C, F>, C> {
Checkpoint::from(self)
}
#[inline]
pub fn queue(&mut self) -> Queue<History<C, F>, C> {
Queue::from(self)
}
#[inline]
pub fn as_target(&self) -> &C::Target {
self.record.as_target()
}
#[inline]
pub fn as_mut_target(&mut self) -> &mut C::Target {
self.record.as_mut_target()
}
#[inline]
pub fn into_target(self) -> C::Target {
self.record.into_target()
}
}
impl<C: Command, F: FnMut(Signal)> History<C, F> {
#[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.branch();
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 set_saved(&mut self, saved: bool) {
self.record.set_saved(saved);
self.saved = None;
}
#[inline]
pub fn revert(&mut self) -> Option<Result<C>> {
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 clear(&mut self) {
let old = self.branch();
self.root = 0;
self.next = 1;
self.saved = None;
self.record.clear();
self.branches.clear();
if let Some(ref mut slot) = self.record.slot {
slot(Signal::Branch { old, new: 0 });
}
}
#[inline]
pub fn apply(&mut self, command: C) -> Result<C> {
let current = self.current();
let saved = self.record.saved.filter(|&saved| saved > current);
let (merged, commands) = self.record.__apply(Entry::from(command))?;
if !merged && current == self.current() {
let root = self.branch();
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.branch();
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!(),
}
if let Some(ref mut slot) = self.record.slot {
slot(Signal::Branch { old, new });
}
}
Ok(())
}
#[inline]
pub fn undo(&mut self) -> Option<Result<C>> {
self.record.undo()
}
#[inline]
pub fn redo(&mut self) -> Option<Result<C>> {
self.record.redo()
}
#[inline]
pub fn go_to(&mut self, branch: usize, current: usize) -> Option<Result<C>> {
let root = self.root;
if root == branch {
return self.record.go_to(current);
}
for (new, branch) in self.mk_path(branch)? {
let old = self.branch();
if let Err(err) = self.record.go_to(branch.parent.current).unwrap() {
return Some(Err(err));
}
for entry in branch.commands {
let current = self.current();
let saved = self.record.saved.filter(|&saved| saved > current);
let commands = match self.record.__apply(entry) {
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));
} else if let Some(ref mut slot) = self.record.slot {
slot(Signal::Branch {
old: root,
new: self.root,
});
}
Some(Ok(()))
}
#[inline]
#[cfg(feature = "chrono")]
pub fn time_travel(&mut self, to: &DateTime<impl TimeZone>) -> Option<Result<C>> {
self.record.time_travel(to)
}
#[inline]
pub fn extend(&mut self, commands: impl IntoIterator<Item = C>) -> Result<C> {
for command in commands {
self.apply(command)?;
}
Ok(())
}
#[inline]
fn set_root(&mut self, root: usize, current: usize) {
let old = self.branch();
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);
if let Some(ref mut slot) = self.record.slot {
slot(Signal::Saved(true));
}
} else if let Some(saved) = self.record.saved {
self.saved = Some(At {
branch: old,
current: saved,
});
self.record.saved = None;
if let Some(ref mut slot) = self.record.slot {
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.branch(), to);
let mut dest = self.branches.remove(&to)?;
let mut i = dest.parent.branch;
let mut path = vec![(to, dest)];
while i != self.branch() {
dest = self.branches.remove(&i).unwrap();
to = i;
i = dest.parent.branch;
path.push((to, dest));
}
Some(path.into_iter().rev())
}
}
impl<C: Command + ToString, F> History<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]
#[cfg(feature = "display")]
pub fn display(&self) -> Display<Self> {
Display::from(self)
}
}
impl<C: Command> Default for History<C>
where
C::Target: Default,
{
#[inline]
fn default() -> History<C> {
History::new(Default::default())
}
}
impl<C: Command, F> AsRef<C::Target> for History<C, F> {
#[inline]
fn as_ref(&self) -> &C::Target {
self.as_target()
}
}
impl<C: Command, F> AsMut<C::Target> for History<C, F> {
#[inline]
fn as_mut(&mut self) -> &mut C::Target {
self.as_mut_target()
}
}
impl<C: Command, F> From<Record<C, F>> for History<C, F> {
#[inline]
fn from(record: Record<C, F>) -> Self {
History {
root: 0,
next: 1,
saved: None,
record,
branches: BTreeMap::default(),
}
}
}
impl<C: Command, F> fmt::Debug for History<C, F>
where
C: fmt::Debug,
C::Target: fmt::Debug,
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("History")
.field("root", &self.root)
.field("next", &self.next)
.field("saved", &self.saved)
.field("record", &self.record)
.field("branches", &self.branches)
.finish()
}
}
#[cfg(feature = "display")]
impl<C: Command, F> fmt::Display for History<C, F>
where
C: fmt::Display,
C::Target: fmt::Display,
{
#[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, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub(crate) struct Branch<C> {
pub(crate) parent: At,
pub(crate) commands: VecDeque<Entry<C>>,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub struct HistoryBuilder<C: Command> {
inner: RecordBuilder<C>,
}
impl<C: Command> HistoryBuilder<C> {
#[inline]
pub fn new() -> HistoryBuilder<C> {
HistoryBuilder {
inner: Record::builder(),
}
}
#[inline]
pub fn capacity(mut self, capacity: usize) -> HistoryBuilder<C> {
self.inner = self.inner.capacity(capacity);
self
}
#[inline]
pub fn limit(mut self, limit: usize) -> HistoryBuilder<C> {
self.inner = self.inner.limit(limit);
self
}
#[inline]
pub fn saved(mut self, saved: bool) -> HistoryBuilder<C> {
self.inner = self.inner.saved(saved);
self
}
#[inline]
pub fn build(self, target: C::Target) -> History<C> {
History::from(self.inner.build(target))
}
#[inline]
pub fn build_with<F>(self, target: C::Target, slot: F) -> History<C, F> {
History::from(self.inner.build_with(target, slot))
}
}
impl<C: Command> Default for HistoryBuilder<C> {
#[inline]
fn default() -> Self {
HistoryBuilder::new()
}
}
impl<C: Command> HistoryBuilder<C>
where
C::Target: Default,
{
#[inline]
pub fn default(self) -> History<C> {
self.build(Default::default())
}
#[inline]
pub fn default_with<F>(self, slot: F) -> History<C, F> {
self.build_with(Default::default(), slot)
}
}
#[cfg(test)]
mod tests {
use crate::*;
use alloc::string::String;
struct Add(char);
impl Command for Add {
type Target = String;
type Error = &'static str;
fn apply(&mut self, target: &mut String) -> Result<Add> {
target.push(self.0);
Ok(())
}
fn undo(&mut self, target: &mut String) -> Result<Add> {
self.0 = target.pop().ok_or("`target` 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_target(), "abcde");
history.undo().unwrap().unwrap();
history.undo().unwrap().unwrap();
assert_eq!(history.as_target(), "abc");
let abcde = history.branch();
history.apply(Add('f')).unwrap();
history.apply(Add('g')).unwrap();
assert_eq!(history.as_target(), "abcfg");
history.undo().unwrap().unwrap();
let abcfg = history.branch();
history.apply(Add('h')).unwrap();
history.apply(Add('i')).unwrap();
history.apply(Add('j')).unwrap();
assert_eq!(history.as_target(), "abcfhij");
history.undo().unwrap().unwrap();
let abcfhij = history.branch();
history.apply(Add('k')).unwrap();
assert_eq!(history.as_target(), "abcfhik");
history.undo().unwrap().unwrap();
let abcfhik = history.branch();
history.apply(Add('l')).unwrap();
assert_eq!(history.as_target(), "abcfhil");
history.apply(Add('m')).unwrap();
assert_eq!(history.as_target(), "abcfhilm");
let abcfhilm = history.branch();
history.go_to(abcde, 2).unwrap().unwrap();
history.apply(Add('n')).unwrap();
history.apply(Add('o')).unwrap();
assert_eq!(history.as_target(), "abno");
history.undo().unwrap().unwrap();
let abno = history.branch();
history.apply(Add('p')).unwrap();
history.apply(Add('q')).unwrap();
assert_eq!(history.as_target(), "abnpq");
let abnpq = history.branch();
history.go_to(abcde, 5).unwrap().unwrap();
assert_eq!(history.as_target(), "abcde");
history.go_to(abcfg, 5).unwrap().unwrap();
assert_eq!(history.as_target(), "abcfg");
history.go_to(abcfhij, 7).unwrap().unwrap();
assert_eq!(history.as_target(), "abcfhij");
history.go_to(abcfhik, 7).unwrap().unwrap();
assert_eq!(history.as_target(), "abcfhik");
history.go_to(abcfhilm, 8).unwrap().unwrap();
assert_eq!(history.as_target(), "abcfhilm");
history.go_to(abno, 4).unwrap().unwrap();
assert_eq!(history.as_target(), "abno");
history.go_to(abnpq, 5).unwrap().unwrap();
assert_eq!(history.as_target(), "abnpq");
}
}