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
//! 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 `Command`s on it. //! //! The library has currently two data structures that can be used to modify the receiver: //! //! * A simple `Stack` that pushes and pops 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)] extern crate fnv; pub mod record; mod stack; use std::fmt::{self, Debug, Display, Formatter}; pub use record::Record; 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 redo(&mut self, receiver: &mut R) -> Result<(), Self::Err>; /// Restores the state as it was before [`redo`] was called and returns `Ok` if everything /// went fine, and `Err` if something went wrong. /// /// [`redo`]: trait.Command.html#tymethod.redo fn undo(&mut self, receiver: &mut R) -> Result<(), Self::Err>; /// Used for manual merging of two `Command`s. /// /// Returns `Some(Ok)` if the merging was successful, `Some(Err)` if something went wrong when /// trying to merge, and `None` if it did not try to merge. /// This method is called with `self` being the top command and `cmd` being the /// new command. If `None` is returned from this method, `cmd` will be pushed /// as normal. However, if the return value is `Some(x)` it will not push the command on to /// the stack since either it was merged or an error has occurred, and then the stack returns /// the `x` value. /// /// [`push`]: struct.Stack.html#method.push #[inline] fn merge(&mut self, _: &Self) -> Option<Result<(), Self::Err>> { None } } /// Custom 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>> std::error::Error for Error<R, C> where R: Debug, C: Debug, C::Err: std::error::Error, { #[inline] fn description(&self) -> &str { self.1.description() } #[inline] fn cause(&self) -> Option<&std::error::Error> { self.1.cause() } }