undo
undo copied to clipboard
Adding More Examples
Hello, I was wondering if we could possibly have an example of a more complex Undo, maybe one where we a managing the state of an app with the RefCell pattern? I tried to implement Undo Redo for this simple example but could not figure it out, do you have an approach?
use undo::{Action, History};
use std::cell::RefCell;
use std::rc::Rc;
use std::error::Error;
#[derive(Clone, Debug)]
struct AppState{
names: Vec<String>
//...
}
struct AppContainer(Rc<RefCell<AppState>>);
type BoxResult<T> = Result<T,Box<Error>>;
impl AppContainer{
fn new (inner: AppState)->AppContainer{
let cl = AppState{
names: inner.names.clone(),
};
return AppContainer(Rc::new(RefCell::new(cl)));
}
fn add_name(&self, name: String){
(self.0.borrow_mut()).names.push(name);
}
fn remove_name(&self, to_remove: String){
(self.0.borrow_mut()).names.retain(|x| *x != to_remove)
}
fn names(&self)->Vec<String>{
(self.0.borrow()).names
}
}
struct AddName(String);
impl Action for AddName{
type Target = (String, AppContainer);
type Output = ();
type Error = &'static str;
fn apply(&mut self, s: (String, &mut AppContainer)) -> undo::Result<AddName> {
s.1.add_name(s.0);
Ok(())
}
fn undo(&mut self, s: (String, &mut AppContainer)) -> undo::Result<AddName> {
s.1.remove_name(s.0);
Ok(())
}
}
//inverse of AddName
struct RemoveName(String);
impl Action for RemoveName{
type Target = (String, AppContainer);
type Output = ();
type Error = &'static str;
fn apply(&mut self, s: (String, &mut AppContainer)) -> undo::Result<RemoveName> {
s.1.remove_name(s.0);
Ok(())
}
fn undo(&mut self, s: (String, &mut AppContainer)) -> undo::Result<RemoveName> {
s.1.add_name(s.0);
Ok(())
}
}
// fn main()->undo::Result<Box<dyn Action>>{
fn main(){
type Target = (String, AppContainer);
type Output = ();
type Error = &'static str;
let initial_state = AppState{
names: vec!["name 1".to_string(), "name 2".to_string()],
};
let mut history = History::new();
let container = AppContainer::new(initial_state.clone());
history.apply(&mut container, AddName("My Name".to_string())).unwrap();
dbg!(container.names());
history.apply(&mut container, RemoveName("Name 1".to_string())).unwrap();
dbg!(container.names());
// Ok(())
}
Reddit User Kythzu was kind enough to provide me with this solution to my problem, maybe with a little clean up it could be added to the examples folder?
Also see this post on stackoverflow for another possible example.
use std::cell::RefCell;
use std::error::Error;
use std::rc::Rc;
use undo::{Action, History};
#[derive(Clone, Debug)]
struct AppState {
names: Vec<String>, //...
}
struct AppContainer(Rc<RefCell<AppState>>);
type BoxResult<T> = Result<T, Box<dyn Error>>;
impl AppContainer {
fn new(inner: AppState) -> AppContainer {
let cl = AppState {
names: inner.names.clone(),
};
return AppContainer(Rc::new(RefCell::new(cl)));
}
fn add_name(&self, name: String) {
(self.0.borrow_mut()).names.push(name);
}
fn remove_name(&self, to_remove: String) {
(self.0.borrow_mut()).names.retain(|x| *x != to_remove)
}
fn names(&self) -> Vec<String> {
(self.0.borrow()).names.clone()
}
}
struct AddName(String);
impl Action for AddName {
type Target = AppContainer;
type Output = ();
type Error = &'static str;
fn apply(&mut self, app: &mut AppContainer) -> undo::Result<AddName> {
app.add_name(self.0.clone());
Ok(())
}
fn undo(&mut self, app: &mut AppContainer) -> undo::Result<AddName> {
app.remove_name(self.0.clone());
Ok(())
}
}
//inverse of AddName
struct RemoveName(String);
impl Action for RemoveName {
type Target = AppContainer;
type Output = ();
type Error = &'static str;
fn apply(&mut self, app: &mut AppContainer) -> undo::Result<RemoveName> {
app.remove_name(self.0.clone());
Ok(())
}
fn undo(&mut self, app: &mut AppContainer) -> undo::Result<RemoveName> {
app.add_name(self.0.clone());
Ok(())
}
}
fn main() -> BoxResult<()> {
let initial_state = AppState {
names: vec!["name 1".to_string(), "name 2".to_string()],
};
let mut history = History::new();
let mut container = AppContainer::new(initial_state.clone());
history
.apply(&mut container, AddName("My Name".to_string()))?;
dbg!(container.names());
history
.undo(&mut container).unwrap()?;
dbg!(container.names());
Ok(())
}
Hi! I will hopefully be able to add more and better examples/documentations at some point when i have the time and the libraries are more stable.
I'll keep these examples in mind for an example with global target and history state!