Skip to main content

concinnity_engine/app/
driver.rs

1//! The windowed loop as a [`Driver`]: what a host holds when the loop it runs
2//! is a runtime value rather than a compile-time type.
3
4use concinnity_core::Driver;
5use concinnity_core::ecs::World;
6
7use crate::app::state::App;
8use crate::result::CnResult;
9
10impl Driver for App {
11    fn start(&mut self) -> Result<(), CnResult> {
12        App::start(self)
13    }
14
15    fn run(self: Box<Self>) -> Result<(), CnResult> {
16        (*self).run()
17    }
18
19    fn into_world(self: Box<Self>) -> World {
20        (*self).into_world()
21    }
22}
23
24#[cfg(test)]
25mod tests {
26    use super::*;
27    use crate::components::AppConfig;
28
29    // Starting through the trait reaches the windowed loop's own start, budgets
30    // and all, and the second call is refused the same way the inherent one is.
31    // A world with no GraphicsConfig starts without building a GPU.
32    #[test]
33    fn a_driver_starts_the_world_it_holds() {
34        let mut driver: Box<dyn Driver> = Box::new(App::new());
35        assert_eq!(driver.start(), Ok(()));
36        assert_eq!(driver.start(), Err(CnResult::InvalidState));
37    }
38
39    // The other way out: the world comes back as it was handed over, so a
40    // caller can put it on a different loop.
41    #[test]
42    fn a_driver_hands_its_world_back_unrun() {
43        let mut app = App::new();
44        app.world_mut().add_component(AppConfig {
45            home: String::new(),
46            max_memory_mb: 512,
47            job_threads: 2,
48        });
49
50        let driver: Box<dyn Driver> = Box::new(app);
51        let world = driver.into_world();
52        assert!(
53            world.query::<AppConfig>().next().is_some(),
54            "the world keeps its content"
55        );
56    }
57}