Skip to content

Adding More Examples #10

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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