I am building a TUI application in Rust and I wish to broadcast keypress events for different parts of the application to listen to. Initially, I create a struct that handles the events:
use std::rc::Rc;
use crate::global::cursor::CursorAction;
use crate::global::state::State;
pub trait Observer {
fn on_keypress(&mut self, cursor_action: &CursorAction, old_state: &State);
}
#[derive(Default)]
pub struct EventHandler {
listeners: Vec<Rc<dyn Observer>>
}
impl EventHandler {
pub fn register(&mut self, observer: Rc<dyn Observer>) {
self.listeners.push(observer);
}
pub fn notify(&mut self, cursor_action: &CursorAction, old_state: &State) {
for listener in &mut self.listeners {
listener.on_keypress(cursor_action, old_state);
}
}
}
And to register this state, I do this in the src/lib.rs
file:
use std::error::Error;
use std::ops::Deref;
use std::rc::Rc;
use crate::event_handler::{EventHandler, Observer};
use crate::global::state::State;
mod terminal;
mod global;
mod domain;
mod event_handler;
pub fn start() -> Result<(), Box<dyn Error>> {
let mut event_handler = EventHandler::default();
let mut state: Rc<dyn Observer> = Rc::new(State::default());
event_handler.register(Rc::clone(&state));
init(&mut state);
let mut terminal = terminal::setup_terminal()?;
terminal::run(&mut terminal, &mut state, event_handler)?;
terminal::restore_terminal(&mut terminal)?;
Ok(())
}
fn init(state: &mut Rc<State>) {
let raw_files = domain::retrieve_files();
state.set_files(raw_files);
}
However, I get an error:
init(&mut state);
---- ^^^^^^^^^^ expected `&mut Rc<State>`, found `&mut Rc<dyn Observer>`
When I have impl Observer for State
defined. I am failing to implement this pattern in Rust and believe that it is quite difficult to do it. How do I make this implementation work? Is there any alternate approach to using this pattern?