A little about how the plugin system should roughly work.
The Plugin trait implements the build()
method, which is called when the plugin is loaded. The build()
method takes App
struct, where App
is the application structure.
Now my code looks cumbersome. So the question is, are there any other options?
pub trait Component {
fn start(&mut self);
fn update(&mut self);
}
pub struct App {
runners: Vec<Box<dyn Fn(&mut App)>>,
components: Vec<Box<dyn Component>>,
}
&mut App
Initially, the build()
method took &mut App
, but this did not allow me to do the following:
impl Plugin for WinitWSIPlugin {
fn build(&self, app: &mut App) {
app.set_runner(move || {
// Error here
app.open_window(...);
});
}
}
As I understood the compiler did not allow me to do this, because I passed a reference to the App
structure, which may soon be irrelevant.
Rc<RefCell>
In the following implementation, I passed Rc<RefCell<App>>
, but calling borrow_mut()
to call open_window(...)
had a panic, even though I had not manually called borrow_mut()
before.
impl Plugin for WinitWSIPlugin {
fn build(&self, app: Rc<RefCell<App>>) {
app.clone().borrow().set_runner(move || {
let AppSystem::Windowed { info } = app.borrow().system();
let mut winit_windows = WinitWindows::default();
let event_loop = winit::event_loop::EventLoop::new();
/*===== Panic this =====*/
app.borrow_mut().open_window(winit_windows.create_window(
&event_loop,
app.borrow().id(),
&info,
));
});
}
}
The last revision I stopped at.
Using Mutex
in those fields of the App structure that will be used in the plugins. That way, I won't have to call borrow_mut()
even if I need to change the value. It will be enough to call borrow()
impl Plugin for WinitWSIPlugin {
fn build(&self, app: Rc<RefCell<App>>) {
app.clone().borrow().set_runner(move || {
let AppSystem::Windowed { info } = app.borrow().system();
let mut winit_windows = WinitWindows::default();
let event_loop = winit::event_loop::EventLoop::new();
app.borrow().open_window(winit_windows.create_window(
&event_loop,
app.borrow().id(),
&info,
));
for component in app.borrow().components().borrow_mut().iter_mut() {
component.init(app.clone());
}
let app = app.clone();
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
for component in app.borrow().components().borrow_mut().iter_mut() {
component.update(app.clone());
}
match event {
winit::event::Event::WindowEvent {
window_id: _,
event,
} => match event {
winit::event::WindowEvent::CloseRequested => control_flow.set_exit(),
_ => (),
},
_ => (),
}
});
});
}
}
You could get around having to share
App
(which I'm not sure will work anyways) by just passing it into the closure as a parameter: