1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
//! An undo-redo library with static dispatch and manual command merging. //! It uses the [command pattern](https://en.wikipedia.org/wiki/Command_pattern) //! where the user modifies a receiver by applying commands on it. //! //! The library has currently two data structures that can be used to modify the receiver: //! //! * A stack that can push and pop commands to modify the receiver. //! * A record that can roll the state of the receiver forwards and backwards. #![forbid(unstable_features, bad_style)] #![deny(missing_debug_implementations, unused_import_braces, unused_qualifications, unsafe_code)] mod group; mod record; mod stack; use std::error; use std::fmt::{self, Debug, Display, Formatter}; pub use group::{Group, GroupBuilder}; pub use record::{Commands, Record, RecordBuilder, Signal}; pub use stack::Stack; /// Base functionality for all commands. pub trait Command<R> { /// The error type. type Err; /// Executes the desired command and returns `Ok` if everything went fine, and `Err` if /// something went wrong. fn exec(&mut self, receiver: &mut R) -> Result<(), Self::Err>; /// Restores the state as it was before [`exec`] was called and returns `Ok` if everything /// went fine, and `Err` if something went wrong. /// /// [`exec`]: trait.Command.html#tymethod.exec fn undo(&mut self, receiver: &mut R) -> Result<(), Self::Err>; /// Used for manual merging of two commands. /// /// Returns `Ok` if commands was merged and `Err` if not. /// /// # Examples /// ``` /// use redo::{Command, Error, Stack}; /// /// #[derive(Debug)] /// struct Add(String); /// /// impl Command<String> for Add { /// type Err = (); /// /// fn exec(&mut self, s: &mut String) -> Result<(), ()> { /// s.push_str(&self.0); /// Ok(()) /// } /// /// fn undo(&mut self, s: &mut String) -> Result<(), ()> { /// let len = s.len() - self.0.len(); /// s.truncate(len); /// Ok(()) /// } /// /// fn merge(&mut self, Add(s): Self) -> Result<(), Self> { /// self.0.push_str(&s); /// Ok(()) /// } /// } /// /// fn foo() -> Result<(), Error<String, Add>> { /// let mut stack = Stack::default(); /// /// // "a", "b", and "c" are merged. /// stack.push(Add("a".into()))?; /// stack.push(Add("b".into()))?; /// stack.push(Add("c".into()))?; /// assert_eq!(stack.len(), 1); /// assert_eq!(stack.as_receiver(), "abc"); /// /// // Calling `pop` once will undo all merged commands. /// let abc = stack.pop().unwrap()?; /// assert_eq!(stack.as_receiver(), ""); /// /// // Pushing the merged commands back on the stack will redo them. /// stack.push(abc)?; /// assert_eq!(stack.into_receiver(), "abc"); /// /// Ok(()) /// } /// # foo().unwrap(); /// ``` #[inline] fn merge(&mut self, cmd: Self) -> Result<(), Self> where Self: Sized, { Err(cmd) } } /// An error kind that holds the error and the command that caused the error. #[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash, Ord, PartialOrd)] pub struct Error<R, C: Command<R>>(pub C, pub C::Err); impl<R, C: Command<R>> Display for Error<R, C> where C::Err: Display, { #[inline] fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!(f, "{}", self.1) } } impl<R, C: Command<R>> error::Error for Error<R, C> where R: Debug, C: Debug, C::Err: error::Error, { #[inline] fn description(&self) -> &str { self.1.description() } #[inline] fn cause(&self) -> Option<&error::Error> { self.1.cause() } }