Preferred template for getting around "moving from borrowed self"

Consider a template in which there are several states registered with the dispatcher, and each state knows which state should go to when it receives the corresponding event. This is a simple state transition pattern.

struct Dispatcher {
    states: HashMap<Uid, Rc<RefCell<State>>>,
}
impl Dispatcher {
    pub fn insert_state(&mut self, state_id: Uid, state: Rc<RefCell<State>>) -> Option<Rc<RefCell<State>>> {
        self.states.insert(state_id, state)
    }
    fn dispatch(&mut self, state_id: Uid, event: Event) {
        if let Some(mut state) = states.get_mut(&state_id).cloned() {
            state.handle_event(self, event);
        }
    }
}

trait State {
    fn handle_event(&mut self, &mut Dispatcher, Event);
}

struct S0 {
    state_id: Uid,
    move_only_field: Option<MOF>,
    // This is pattern that concerns me.
}
impl State for S0 {
    fn handle_event(&mut self, dispatcher: &mut Dispatcher, event: Event) {
        if event == Event::SomeEvent {
            // Do some work
            if let Some(mof) = self.mof.take() {
                let next_state = Rc::new(RefCell::new(S0 {
                    state_id: self.state_id,
                    move_only_field: mof,
                }));
                let _ = dispatcher.insert(self.state_id, next_state);
            } else {
                // log an error: BUGGY Logic somewhere
                let _ = dispatcher.remove_state(&self.state_id);
            }
        } else {
            // Do some other work, maybe transition to State S2 etc.
        }
    }
}

struct S1 {
    state_id: Uid,
    move_only_field: MOF,
}
impl State for S1 {
    fn handle_event(&mut self, dispatcher: &mut Dispatcher, event: Event) {
        // Do some work, maybe transition to State S2/S3/S4 etc.
    }
}

With a link to the inline comment above saying:

// This is pattern that concerns me.

S0::move_only_fieldshould be Optionin this template because it is selfborrowed in handle_event, but I'm not sure if this is the best way to get closer to it.

Here's how I can think of the flaws of each of them:

  • Option, : , , Option Some panic! NOP if let Some() = else, . unwrap if let Some() .
  • Rc<RefCell<>>: Inner , Rc<RefCell<>>.
  • Dispatcher, , , State, : , , , Dispatcher State . , , .
  • Default MOF : mem::replace . NOP MOF. , MOF , , , MOF.
  • handle_event self, fn handle_event(mut self, ...) -> Option<Self>: Rc<RefCell<>> Box<State> , Some . , , - / , Weak<RefCell<>> , "" .. .

? -, " " Rust?

+4
1
  1. handle_event self, fn handle_event(mut self, ...) -> Option<Self>: Rc<RefCell<>> Box<State> , - , .

, . Rc Box, : Rc::try_unwrap Rc.

, Dispatcher:

struct Dispatcher {
    states: HashMap<Uid, Rc<State>>,
}
impl Dispatcher {
    fn dispatch(&mut self, state_id: Uid, event: Event) {
        if let Some(state_ref) = self.states.remove(&state_id) {
            let state = state_ref.try_unwrap()
                .expect("Unique strong reference required");
            if let Some(next_state) = state.handle_event(event) {
                self.states.insert(state_id, next_state);
            }
        } else {
            // handle state_id not found
        }
    }
}

(: dispatch state_id . - . , state_id HashMap::insert. , Uid Copy, .)

, state_id , State , handle_event - impl Dispatcher, State Dispatcher.

impl State for S0 {
    fn handle_event(self, event: Event) -> Option<Rc<State>> {
        if event == Event::SomeEvent {
            // Do some work
            let next_state = Rc::new(S0 {
                state_id: self.state_id,
                move_only_field: self.mof,
            });
            Some(next_state)
        } else {
            // Do some other work
        }
    }
}

, , Option None.

, , - / , Weak<RefCell<>> , "" .. .

Rc, , .

" " , , , , fn handle_event(mut self, ...) -> Option<Self>, . impl State for ... , , , , . , - dispatcher.insert(state_id, next_state), . handle_event self , - .

( , , - , dispatch : , , . lookup, : Option<Rc<State>> HashMap take Option .)

+1

Source: https://habr.com/ru/post/1675932/


All Articles