gur/lib.rs
1//! Wrapper types to provide undo-redo functionality.
2//!
3//! # Sample code
4//! ```
5//! use gur::prelude::*;
6//! use gur::cur::{Cur, CurBuilder};
7//!
8//! // Appication state
9//! #[derive(Clone)]
10//! struct MyState {
11//! data: String
12//! }
13//!
14//! fn main() {
15//! // Initialize
16//! let mut state: Cur<MyState> = CurBuilder::new().build(MyState{ data: "My".to_string() });
17//! assert_eq!("My", state.data);
18//!
19//! // Change state
20//! state.edit(|mut state: MyState| { state.data += "State"; state });
21//! assert_eq!("MyState", state.data);
22//!
23//! // Undo
24//! state.undo();
25//! assert_eq!("My", state.data);
26//!
27//! // Redo
28//! state.redo();
29//! assert_eq!("MyState", state.data);
30//! }
31//! ```
32//! Where [Cur\<T\>](crate::cur::Cur) is a type providing undo-redo functionality.
33//! The `MyState` is a type of user's application state.
34//! `MyState` implements the [Clone] trait required by [Cur\<T\>](crate::cur::Cur).
35//! Then the variable `state` as type `Cur<MyState>` is created to get the ability to undo-redo.
36//!
37//! The [edit](crate::interface::IEdit::edit) takes a closure to change the variable.
38//! The closure is a function that consumes a current state as internal type `MyState` and returns a new state.
39//! [undo](crate::interface::IUndoRedo::undo) can restore the previous state.
40//! The [redo](crate::interface::IUndoRedo::redo) is reverse operation of the [undo](crate::interface::IUndoRedo::undo).
41//!
42//! The [Cur\<T\>](crate::cur::Cur) implements [Deref](std::ops::Deref).
43//! So the variable can be used as like smart pointers.
44//!
45//! # `Ur` family
46//! [Ur](crate::ur::Ur) is a most basic type in this crate.
47//! Some variants are provided in this crate.
48//! The variants and their features are listed below.
49//!
50//! | Type | Requirements | Thread safety | Description |
51//! | :----------------------------- | :----------------------------------------- | :-----------: | :---------------------------------------------------------------------------- |
52//! | [Ur\<T\>](crate::ur::Ur) | `T`: [Snapshot](crate::snapshot::Snapshot) | No | A basic wrapper for types implementing [Snapshot](crate::snapshot::Snapshot). |
53//! | [Cur\<T\>](crate::cur::Cur) | `T`: [Clone] | No | Another simple wrapper for types implementing [Clone]. |
54//! | [Aur\<T\>](crate::aur::Aur) | `T`: [Snapshot](crate::snapshot::Snapshot) | Yes | [Ur\<T\>](crate::ur::Ur) + [Send] + [Sync] |
55//! | [Acur\<T\>](crate::acur::Acur) | `T`: [Clone] | Yes | [Cur\<T\>](crate::cur::Cur) + [Send] + [Sync] |
56//!
57//! ## Requirements
58//! For example, [Ur\<T\>](crate::ur::Ur) requires `T` implementing [Snapshot](crate::snapshot::Snapshot).
59//! On the other hand, [Cur\<T\>](crate::cur::Cur) requires [Clone] instead of [Snapshot](crate::snapshot::Snapshot) for simplicity.
60//!
61//! ## Thread safety
62//! Some types of them can be [Send] and [Sync] and some not.
63//! See [interface](crate::interface) for more details about thread safety.
64//!
65//! # Generative approach
66//! This section describes a basic concept of this crate.
67//! The concept is that "Undoing is regenerating (recomputing) the old state."
68//!
69//! For explanation, a sample history of changes is shown as follows,
70//! ```txt
71//! t: state
72//! c: command
73//! s: snapshot
74//!
75//! old <----------------------> new
76//! c1 c2 c3
77//! t0 -----> t1 -----> t2 -----> t3
78//! | +--------------> |
79//! | | |
80//! s0 +--------------------------+
81//! undo t3 -> t2
82//! ```
83//! Where `tx` is an application state at time point `x`,
84//! `cx` is a command to change a state `tx-1` to next `tx`,
85//! and `sx` is a snapshot of a state `tx`.
86//!
87//! The application state have changed in order of `t0`, `t1`, `t2`, and `t3`.
88//! Now, the current state is `t3`.
89//!
90//! Let us consider undoing the current state `t3` to its previous state `t2`.
91//! First, the system restores an old state from its snapshot at any point in the history.
92//! In this case, We would have to restore the state `t0` from `s0` because there is only one snapshot `s0`.
93//! Then the system reruns the commands (`c1` and `c2`) in order.
94//! Finally, the target state `t2` will be obtained.
95//!
96//! # Data structure
97//! A history is managed as chain of commands and snapshots to perform the
98//! process described above.
99//! No intermediate states are stored.
100//! ```txt
101//! c: command
102//! s: snapshot
103//!
104//! old <----------------------------------------------> new
105//! /--\ +--+ +--+ +--+ /----\ +----+ +----+
106//! |s0|--|c1|--|c2|--...--|cn|--|sn+1|--|cn+2|--|cn+3|--...
107//! \--/ +--+ +--+ +--+ \----/ +----+ +----+
108//! ```
109//! The frequency of snapshots can be customized by "trigger functions."
110//! See [crate::triggers] for more details.
111//!
112//! # Pros and Cons
113//! ## Pros
114//! The advantages of this approach are usability and robustness.
115//! There are no backward opeartions in the undoing process.
116//! So users almost never have to write additional codes for the process.
117//! If there are tests for the application state object, the correctness of undo-redo process is
118//! also guaranteed.
119//!
120//! ## Cons
121//! Users should pay attention to side effects of commands.
122//!
123//! See also ["`edit` with side effects"](crate::interface#edit-with-side-effects) for more details.
124mod agur;
125mod gur;
126mod history;
127
128pub mod acur;
129pub mod aur;
130pub mod cur;
131pub mod interface;
132pub mod metrics;
133pub mod snapshot;
134pub mod triggers;
135pub mod ur;
136
137pub mod prelude {
138 //! Re-export common members
139 pub use crate::interface::*;
140}