Skip to content

Adding More Examples #10

@wyhinton

Description

@wyhinton

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(())
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions