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.
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,
));
});
}
}
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:
struct App {
runners: Vec<Box<dyn Fn(&mut App)>>,
}
impl App {
fn set_runner(&mut self, f: impl Fn(&mut App) + 'static) {
self.runners.push(Box::new(f));
}
fn run(&mut self) {
// take the runners out of self to avoid borrow & mutable borrow at the same time
let runners = std::mem::take(&mut self.runners);
for runner in runners.iter() {
// pass self into the runner so it can change app state and create windows etc
runner(self);
}
// put the runners back.
self.runners = runners;
}
fn open_window(&mut self) {}
}
trait Plugin {
fn build(&self, app: &mut App);
}
struct WinitWSIPlugin;
impl Plugin for WinitWSIPlugin {
fn build(&self, app: &mut App) {
// the closure now takes a `&mut App` as parameter
// the argument type is optional and just shown for demonstration here
app.set_runner(move |app: &mut App| {
app.open_window();
});
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.