#![doc = include_str!("../README.md")]
use core::borrow::Borrow;
use core::cmp::min;
use core::iter::FusedIterator;
use core::ops::ControlFlow;
use core::ops::{Deref, Index};
use core::option;
use std::cmp::Ordering;
use std::fmt::Debug;
use std::hash::Hash;
use std::slice::SliceIndex;
use std::{slice, vec};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum Action {
Do,
Undo,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum CommandItem<T> {
Command(T),
Undo(usize),
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Eq)]
pub struct Commands<T> {
commands: Vec<CommandItem<T>>,
#[cfg_attr(feature = "serde", serde(skip))]
undo_cache: Vec<IndexedAction>,
}
impl<T: Debug> Debug for Commands<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Commands")
.field("commands", &self.commands)
.finish()
}
}
impl<T: PartialEq> PartialEq for Commands<T> {
fn eq(&self, other: &Self) -> bool {
self.commands == other.commands
}
}
impl<T: Hash> Hash for Commands<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.commands.hash(state);
}
}
impl<T> Default for Commands<T> {
fn default() -> Self {
Self {
commands: Default::default(),
undo_cache: Default::default(),
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum CachedAction {
Do,
Undo,
Skip,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
struct IndexedAction {
action: CachedAction,
index: usize,
}
#[derive(Debug)]
pub struct Merge<'a, T> {
pub start: IterRealized<'a, T>,
pub end: IterRealized<'a, T>,
pub command: Option<T>,
}
#[derive(Debug)]
pub struct Splice<'a, T, I: IntoIterator<Item = T>> {
pub start: IterRealized<'a, T>,
pub end: IterRealized<'a, T>,
pub commands: I,
}
#[derive(Debug)]
pub struct ActionIter<'a, T> {
commands: &'a [CommandItem<T>],
to_do: std::slice::Iter<'a, IndexedAction>,
}
impl<T> Clone for ActionIter<'_, T> {
fn clone(&self) -> Self {
Self {
commands: self.commands,
to_do: self.to_do.clone(),
}
}
}
#[derive(Debug)]
pub struct IterRealized<'a, T> {
commands: &'a [CommandItem<T>],
current: usize,
}
impl<T> Clone for IterRealized<'_, T> {
fn clone(&self) -> Self {
Self { ..*self }
}
}
impl<T> Commands<T> {
pub fn new() -> Self {
Self {
commands: vec![],
undo_cache: vec![],
}
}
pub fn capacity(&self) -> usize {
self.commands.capacity()
}
pub fn reserve(&mut self, additional: usize) {
self.commands.reserve(additional)
}
pub fn push(&mut self, command: T) {
self.commands.push(CommandItem::Command(command));
}
#[must_use = "the returned actions should be realized"]
pub fn undo(&mut self) -> ActionIter<'_, T> {
self.undo_repeat(0)
}
#[must_use = "the returned actions should be realized"]
pub fn undo_repeat(&mut self, repeat: usize) -> ActionIter<'_, T> {
let l = self.len();
match self.commands.last_mut() {
Some(CommandItem::Command(_)) => {
let count = min(repeat, l - 1);
self.commands.push(CommandItem::Undo(count));
ActionIter::undo_at_count(
&self.commands,
&mut self.undo_cache,
l - 1 - count,
count,
)
}
Some(CommandItem::Undo(i)) => {
if *i + 2 < l {
let count = min(l - *i - 3, repeat);
*i = *i + 1 + count;
let t = l - *i - 2;
ActionIter::undo_at_count(&self.commands, &mut self.undo_cache, t, count)
} else {
ActionIter::new()
}
}
None => ActionIter::new(),
}
}
#[must_use = "the returned command should be undone"]
pub fn unbuild(&mut self) -> Option<&'_ T> {
let mut it = self.iter_realized();
it.next()?;
let start = it.current;
let count = match it.next() {
Some(_) => start - it.current,
None => start + 1,
};
match self.commands.last_mut() {
Some(CommandItem::Command(_)) => {
self.commands.push(CommandItem::Undo(count - 1));
}
Some(CommandItem::Undo(i)) => *i += count,
None => unreachable!(),
}
Some(match self.commands[start] {
CommandItem::Command(ref c) => c,
_ => unreachable!(),
})
}
#[must_use = "the returned actions should be realized"]
pub fn redo(&mut self) -> ActionIter<'_, T> {
self.redo_repeat(0)
}
#[must_use = "the returned actions should be realized"]
pub fn redo_repeat(&mut self, repeat: usize) -> ActionIter<'_, T> {
let l = self.len();
match self.commands.last_mut() {
Some(CommandItem::Undo(i)) => {
if let Some(ni) = i.checked_sub(repeat.checked_add(1).unwrap()) {
let t = l - 2 - *i;
*i = ni;
ActionIter::do_at_count(&self.commands, &mut self.undo_cache, t, repeat)
} else {
let count = *i;
self.commands.pop();
ActionIter::do_at_count(&self.commands, &mut self.undo_cache, l - 2, count)
}
}
_ => ActionIter::new(),
}
}
#[must_use = "the returned actions should be realized"]
pub fn redo_all(&mut self) -> ActionIter<'_, T> {
let l = self.len();
match self.commands.last_mut() {
Some(CommandItem::Undo(i)) => {
let count = *i;
self.commands.pop();
ActionIter::do_at_count(&self.commands, &mut self.undo_cache, l - 2, count)
}
_ => ActionIter::new(),
}
}
pub fn is_undoing(&self) -> bool {
matches!(self.commands.last(), Some(CommandItem::Undo(_)))
}
pub fn current_command_index(&self) -> Option<usize> {
let mut it = self.iter_realized();
it.next()?;
Some(it.current)
}
pub fn undo_or_redo_to_index(&mut self, i: usize) -> ActionIter<'_, T> {
use CommandItem::*;
let cur_i = match self.last() {
None => return ActionIter::new(),
Some(Command(_)) => self.len() - 1,
Some(Undo(i)) => self.len() - 2 - i,
};
match i.cmp(&cur_i) {
Ordering::Greater => self.redo_repeat(i - cur_i - 1),
Ordering::Less => self.undo_repeat(cur_i - i - 1),
Ordering::Equal => ActionIter::new(),
}
}
pub fn clear(&mut self) {
self.commands.clear();
}
pub fn remove_until(&mut self, mut stop_pred: impl FnMut(&T) -> bool) {
if let Some(i) = self.commands.iter().position(move |c| match c {
CommandItem::Undo(_) => false,
CommandItem::Command(c) => stop_pred(c),
}) {
self.remove_first(i)
}
}
pub fn keep_last(&mut self, count: usize) {
let i = self.len().saturating_sub(count);
self.remove_first(i)
}
pub fn remove_first(&mut self, i: usize) {
let j = self.remove_i(i, self.commands.len());
self.commands.drain(..j);
}
fn remove_i(&self, mut i: usize, end: usize) -> usize {
let i0 = i;
for j in i0..end {
if let CommandItem::Undo(count) = self.commands[j] {
if j - count - 1 < i {
i = self.remove_i(j - count - 1, i)
}
}
}
i
}
pub fn iter_realized(&self) -> IterRealized<'_, T> {
IterRealized {
commands: &self.commands,
current: self.commands.len(),
}
}
pub fn merge<F>(&mut self, mut f: F)
where
for<'a> F:
FnMut(IterRealized<'a, T>) -> ControlFlow<Option<Merge<'a, T>>, Option<Merge<'a, T>>>,
{
use ControlFlow::*;
self.splice(|it| match f(it) {
Continue(c) => Continue(c.map(|m| m.into())),
Break(c) => Break(c.map(|m| m.into())),
})
}
pub fn splice<F, I>(&mut self, mut f: F)
where
F: for<'a> FnMut(
IterRealized<'a, T>,
)
-> ControlFlow<Option<Splice<'a, T, I>>, Option<Splice<'a, T, I>>>,
I: IntoIterator<Item = T>,
{
use ControlFlow::*;
let mut start = self.commands.len();
while start != 0 {
let it = IterRealized {
commands: &self.commands,
current: start,
};
match f(it) {
Continue(Some(m)) => {
let rev_start = m.start.current;
let rev_end = m.end.current;
let commands = m.commands;
self.do_splice(rev_start, rev_end, commands);
start = rev_end;
}
Break(Some(m)) => {
let rev_start = m.start.current;
let rev_end = m.end.current;
let commands = m.commands;
self.do_splice(rev_start, rev_end, commands);
break;
}
Break(None) => break,
Continue(None) => start -= 1,
}
}
}
fn do_splice<I>(&mut self, rev_start: usize, rev_end: usize, commands: I)
where
I: IntoIterator<Item = T>,
{
let end_i = rev_start;
let start_i = rev_end;
self.commands
.splice(start_i..end_i, commands.into_iter().map(|c| c.into()));
}
pub fn remove_all_undone(&mut self) {
self.remove_undone(|i| i)
}
pub fn remove_undone<F>(&mut self, from: F)
where
F: for<'a> FnOnce(IterRealized<'a, T>) -> IterRealized<'a, T>,
{
use CachedAction::*;
let from = from(self.iter_realized());
let mut it = IterRealized {
commands: &self.commands,
..from
};
self.undo_cache.clear();
let start = it.current;
while let Some(_) = it.next() {
self.undo_cache.push(IndexedAction {
action: Do,
index: it.current,
});
}
let mut i = 0;
let mut shift = 0;
for u in self.undo_cache.iter().rev() {
let j = u.index;
self.commands.drain(i - shift..j - shift);
shift += j - i;
i = j + 1;
}
self.commands.drain(i - shift..start - shift);
}
}
impl<T: Clone> Clone for Commands<T> {
fn clone(&self) -> Self {
Self {
commands: self.commands.clone(),
undo_cache: vec![],
}
}
fn clone_from(&mut self, source: &Self) {
self.commands.clone_from(&source.commands)
}
}
impl<T> Deref for Commands<T> {
type Target = [CommandItem<T>];
fn deref(&self) -> &Self::Target {
&self.commands
}
}
impl<T> AsRef<[CommandItem<T>]> for Commands<T> {
fn as_ref(&self) -> &[CommandItem<T>] {
self
}
}
impl<T> Borrow<[CommandItem<T>]> for Commands<T> {
fn borrow(&self) -> &[CommandItem<T>] {
self
}
}
impl<T> Extend<T> for Commands<T> {
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
self.commands.extend(iter.into_iter().map(|c| c.into()))
}
}
impl<T> FromIterator<T> for Commands<T> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
Self {
commands: iter.into_iter().map(|c| c.into()).collect(),
undo_cache: vec![],
}
}
}
impl<'a, T> IntoIterator for &'a Commands<T> {
type Item = &'a CommandItem<T>;
type IntoIter = slice::Iter<'a, CommandItem<T>>;
fn into_iter(self) -> Self::IntoIter {
self.commands.iter()
}
}
impl<T> IntoIterator for Commands<T> {
type Item = CommandItem<T>;
type IntoIter = std::vec::IntoIter<CommandItem<T>>;
fn into_iter(self) -> Self::IntoIter {
self.commands.into_iter()
}
}
impl<T, I> Index<I> for Commands<T>
where
I: SliceIndex<[CommandItem<T>]>,
{
type Output = <I as SliceIndex<[CommandItem<T>]>>::Output;
fn index(&self, index: I) -> &Self::Output {
self.commands.index(index)
}
}
impl<T> From<T> for CommandItem<T> {
fn from(value: T) -> Self {
CommandItem::Command(value)
}
}
impl<'a, T> From<Merge<'a, T>> for Splice<'a, T, option::IntoIter<T>> {
fn from(m: Merge<'a, T>) -> Self {
Splice {
start: m.start,
end: m.end,
commands: m.command.into_iter(),
}
}
}
impl<T> IterRealized<'_, T> {
pub fn index(&self) -> usize {
self.current
}
}
impl<'a, T> Iterator for IterRealized<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
use CommandItem::*;
loop {
self.current = self.current.checked_sub(1)?;
match self.commands[self.current] {
Command(ref c) => break Some(c),
Undo(i) => self.current -= i + 1,
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(self.current))
}
}
impl<T> FusedIterator for IterRealized<'_, T> {}
impl<'a, T> Iterator for ActionIter<'a, T> {
type Item = (Action, &'a T);
fn next(&mut self) -> Option<Self::Item> {
use CachedAction::*;
loop {
let a = self.to_do.next()?;
match a {
IndexedAction { action: Do, index } => {
break if let CommandItem::Command(v) = &self.commands[*index] {
Some((Action::Do, v))
} else {
unreachable!()
}
}
IndexedAction {
action: Undo,
index,
} => {
break if let CommandItem::Command(v) = &self.commands[*index] {
Some((Action::Undo, v))
} else {
unreachable!()
}
}
IndexedAction { action: Skip, .. } => (),
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.to_do.size_hint()
}
}
impl<T> FusedIterator for ActionIter<'_, T> {}
impl<T> ExactSizeIterator for ActionIter<'_, T> {}
impl IndexedAction {
fn is_reverse_of(&self, other: &Self) -> bool {
use CachedAction::*;
self.index == other.index
&& (self.action == Do && other.action == Undo
|| self.action == Undo && other.action == Do)
}
}
impl<'a, T> ActionIter<'a, T> {
fn new() -> Self {
Self {
commands: &[],
to_do: [].iter(),
}
}
fn undo_at_count(
commands: &'a [CommandItem<T>],
cache: &'a mut Vec<IndexedAction>,
i: usize,
count: usize,
) -> Self {
cache.clear();
cache_undo_indexes(commands, i + 1 + count, i, cache);
do_simplify(cache);
Self {
commands,
to_do: cache.iter(),
}
}
fn do_at_count(
commands: &'a [CommandItem<T>],
cache: &'a mut Vec<IndexedAction>,
i: usize,
count: usize,
) -> Self {
cache.clear();
cache_do_indexes(commands, i - count, i + 1, cache);
do_simplify(cache);
Self {
commands,
to_do: cache.iter(),
}
}
}
fn cache_undo_indexes<T>(
commands: &[CommandItem<T>],
undo_from: usize,
undo_to: usize,
to_do: &mut Vec<IndexedAction>,
) {
use CachedAction::*;
for i in (undo_to..undo_from).rev() {
match commands[i] {
CommandItem::Command(_) => to_do.push(IndexedAction {
action: Undo,
index: i,
}),
CommandItem::Undo(count) => cache_do_indexes(commands, i - (count + 1), i, to_do),
}
}
}
fn cache_do_indexes<T>(
commands: &[CommandItem<T>],
do_from: usize,
do_to: usize,
to_do: &mut Vec<IndexedAction>,
) {
use CachedAction::*;
for i in do_from..do_to {
match commands[i] {
CommandItem::Command(_) => to_do.push(IndexedAction {
action: Do,
index: i,
}),
CommandItem::Undo(count) => cache_undo_indexes(commands, i, i - (count + 1), to_do),
}
}
}
fn do_simplify(to_do: &mut [IndexedAction]) {
use CachedAction::*;
if to_do.len() < 2 {
return;
}
let mut analyzed = to_do.len() - 1;
let mut cursor = to_do.len() - 1;
while analyzed > 0 {
analyzed -= 1;
let action = &to_do[analyzed];
let l = to_do.len();
if cursor < to_do.len() {
if to_do[cursor].is_reverse_of(action) {
cursor += 1;
while cursor < l && to_do[cursor].action == Skip {
cursor += 1
}
} else {
to_do[analyzed + 1..cursor]
.iter_mut()
.for_each(|a| a.action = Skip);
if cursor == analyzed + 1 {
cursor = analyzed
} else {
cursor = analyzed + 1;
analyzed += 1;
}
}
} else {
to_do[analyzed + 1..]
.iter_mut()
.for_each(|a| a.action = Skip);
cursor = analyzed;
}
}
to_do[..cursor].iter_mut().for_each(|a| a.action = Skip);
}
#[cfg(test)]
mod test {
use super::CachedAction::*;
use super::IndexedAction;
#[test]
fn simplify() {
use super::do_simplify;
fn simplify(mut to_do: Vec<IndexedAction>) -> Vec<IndexedAction> {
do_simplify(&mut to_do);
to_do.iter().filter(|c| c.action != Skip).copied().collect()
}
fn _do(i: usize) -> IndexedAction {
IndexedAction {
action: Do,
index: i,
}
}
fn undo(i: usize) -> IndexedAction {
IndexedAction {
action: Undo,
index: i,
}
}
{
let v = vec![];
assert_eq!(simplify(v), vec![]);
}
{
let v = vec![_do(1)];
assert_eq!(simplify(v), vec![_do(1)]);
}
{
let v = vec![undo(1)];
assert_eq!(simplify(v), vec![undo(1)]);
}
{
let v = vec![_do(1), undo(1)];
assert_eq!(simplify(v), vec![]);
}
{
let v = vec![_do(0), _do(1), undo(1)];
assert_eq!(simplify(v), vec![_do(0)]);
}
{
let v = vec![_do(1), undo(1), _do(2)];
assert_eq!(simplify(v), vec![_do(2)]);
}
{
let v = vec![_do(0), _do(1), undo(1), _do(2)];
assert_eq!(simplify(v), vec![_do(0), _do(2)]);
}
{
let v = vec![_do(1), _do(2), undo(2), undo(1)];
assert_eq!(simplify(v), vec![]);
}
{
let v = vec![_do(0), _do(1), _do(2), undo(2), undo(1)];
assert_eq!(simplify(v), vec![_do(0)]);
}
{
let v = vec![_do(1), _do(2), undo(2), undo(1), _do(3)];
assert_eq!(simplify(v), vec![_do(3)]);
}
{
let v = vec![_do(0), _do(1), _do(2), undo(2), undo(1), _do(3)];
assert_eq!(simplify(v), vec![_do(0), _do(3)]);
}
{
let v = vec![_do(0), _do(1), _do(2), undo(2), undo(1), undo(0)];
assert_eq!(simplify(v), vec![]);
}
{
let v = vec![
_do(0),
_do(1),
_do(2),
undo(2),
undo(1),
_do(10),
undo(10),
undo(0),
];
assert_eq!(simplify(v), vec![]);
}
}
}