undo/
lib.rs

1//! **An undo-redo library.**
2//!
3//! An implementation of the [command pattern](https://en.wikipedia.org/wiki/Command_pattern),
4//! where all edits are done by creating objects that applies the modifications.
5//! All objects knows how to undo the changes it applies, and by using the provided data
6//! structures it is easy to undo and redo edits made to a target.
7//!
8//! See the [examples](https://github.com/evenorog/undo/tree/master/examples) for more information.
9//!
10//! # Features
11//!
12//! * [`Edit`] provides the base functionality for all edit commands. Multiple edit commands can be merged into a single edit
13//!   by implementing the [`merge`](Edit::merge) method on the edit. This allows smaller edits to be used to build
14//!   more complex operations, or smaller incremental changes to be merged into larger changes that can be undone and
15//!   redone in a single step.
16//! * [`Record`] provides basic stack based undo-redo functionality.
17//! * [`History`] provides full tree based undo-redo functionality.
18//! * Queue and checkpoint functionality is supported for both [`Record`] and [`History`].
19//! * The target can be marked as saved to disk and the user will be notified when it changes.
20//! * The amount of changes being tracked can be configured by the user so only the `N` most recent changes are stored.
21//! * Configurable display formatting using the display structures.
22//!
23//! # Examples
24//!
25//! All examples in the documentation uses the `Add`
26//! command found [here](https://github.com/evenorog/undo/blob/master/src/add.rs).
27//!
28//! # Cargo Feature Flags
29//!
30//! | Name    | Default | Enables | Description                                                     |
31//! |---------|---------|---------|-----------------------------------------------------------------|
32//! | std     | ✓       | alloc   | Enables the standard library.                                   |
33//! | alloc   |         |         | Enables the `alloc` crate.                                      |
34//! | colored |         |         | Enables colored output when visualizing the display structures. |
35//! | serde   |         |         | Enables serialization and deserialization.                      |
36
37#![doc(html_root_url = "https://docs.rs/undo")]
38#![deny(missing_docs)]
39#![forbid(unsafe_code)]
40#![cfg_attr(not(feature = "std"), no_std)]
41
42#[cfg(feature = "alloc")]
43extern crate alloc;
44
45#[cfg(doctest)]
46#[doc = include_str!("../README.md")]
47pub struct ReadmeDocTest;
48
49#[cfg(feature = "alloc")]
50mod add;
51#[cfg(feature = "alloc")]
52mod entry;
53#[cfg(feature = "alloc")]
54mod format;
55#[cfg(feature = "alloc")]
56pub mod history;
57#[cfg(feature = "alloc")]
58pub mod record;
59#[cfg(feature = "alloc")]
60mod socket;
61
62#[doc(hidden)]
63#[cfg(feature = "alloc")]
64pub use add::Add;
65#[cfg(feature = "alloc")]
66pub use entry::Entry;
67#[cfg(feature = "alloc")]
68pub use history::History;
69#[cfg(feature = "alloc")]
70pub use record::Record;
71#[cfg(feature = "alloc")]
72pub use socket::{Event, Slot};
73
74#[cfg(feature = "alloc")]
75use format::Format;
76#[cfg(feature = "serde")]
77use serde::{Deserialize, Serialize};
78
79/// Base functionality for all edit commands.
80pub trait Edit {
81    /// The target type.
82    type Target;
83    /// The output type.
84    type Output;
85
86    /// Applies the edit command on the target.
87    fn edit(&mut self, target: &mut Self::Target) -> Self::Output;
88
89    /// Restores the state of the target as it was before the edit was applied.
90    fn undo(&mut self, target: &mut Self::Target) -> Self::Output;
91
92    /// Reapplies the edit on the target.
93    ///
94    /// The default implementation uses the [`Edit::edit`] implementation.
95    fn redo(&mut self, target: &mut Self::Target) -> Self::Output {
96        self.edit(target)
97    }
98
99    /// Used for manual merging of edits. See [`Merged`] for more information.
100    fn merge(&mut self, other: Self) -> Merged<Self>
101    where
102        Self: Sized,
103    {
104        Merged::No(other)
105    }
106}
107
108/// Says if the [`Edit`] command have been merged with another command.
109#[derive(Copy, Clone, Debug)]
110pub enum Merged<E> {
111    /// The edits have been merged.
112    ///
113    /// This means that the `other` edit will not be added to the stack.
114    Yes,
115    /// The edits have not been merged.
116    ///
117    /// We need to return the `other` edit so it can be added to the stack.
118    No(E),
119    /// The two edits cancels each other out.
120    ///
121    /// This means that both edits will be removed from the stack.
122    Annul,
123}
124
125/// A position in a history tree.
126#[cfg(feature = "alloc")]
127#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
128#[derive(Copy, Clone, Debug, Eq, PartialEq)]
129pub struct At {
130    /// The root branch.
131    pub root: usize,
132    /// The index of edit.
133    pub index: usize,
134}
135
136#[cfg(feature = "alloc")]
137impl At {
138    const NIL: At = At::new(0, 0);
139
140    /// Creates a new `At` with the provided root and index.
141    pub const fn new(root: usize, index: usize) -> At {
142        At { root, index }
143    }
144
145    const fn no_root(index: usize) -> At {
146        At::new(0, index)
147    }
148}