Skip to main content

shuyi/
lib.rs

1//! Shuyi Engine, by its front door (ADR-0009 ยง6). A game depends on this
2//! crate alone and turns on the features of the modules it wants, each
3//! off by default; `docs/modules.md` lists them by concern, and `shuyi
4//! add <module>` turns one on.
5//!
6//! - [`core`], [`assets`], [`ui`], [`platform`] and [`app`]: the default
7//!   engine's crates, `shuyi-core` to `shuyi-app`, under short names
8//!   (`app`, the macroquad backend, on every target but WASI, which has no
9//!   window, and with its feature, on by default; a game on a device without
10//!   `std` turns the default features off);
11//! - [`prelude`]: what a game on the short path names, with
12//!   [`run_game`](prelude::run_game);
13//! - [`enabled_modules`]: the [`Module`] of each module turned on, which
14//!   the game installs once.
15#![cfg_attr(not(feature = "std"), no_std)]
16
17extern crate alloc;
18
19#[cfg(all(feature = "app", not(target_os = "wasi")))]
20pub use shuyi_app as app;
21pub use shuyi_assets as assets;
22pub use shuyi_core as core;
23pub use shuyi_platform as platform;
24pub use shuyi_ui as ui;
25
26use alloc::boxed::Box;
27use alloc::vec::Vec;
28
29use shuyi_ui::GameData;
30use shuyi_ui::module::Module;
31
32/// What a game on the short path names (ADR-0036): `shuyi-platform`'s
33/// prelude, and [`run_game`](shuyi_app::run_game), which runs it from a
34/// plain `main`.
35pub mod prelude {
36    #[cfg(all(feature = "app", not(target_os = "wasi")))]
37    pub use shuyi_app::run_game;
38    pub use shuyi_platform::prelude::*;
39}
40
41/// The [`Module`] of each module whose feature is on, made with its
42/// defaults, in the catalog's order: empty with no feature on. A game
43/// installs them once, with [`Game::with_modules`](shuyi_ui::Game::with_modules)
44/// or [`BasicGame::modules`](shuyi_platform::BasicGame::modules), so
45/// turning a module on needs no change to its code. A module that needs
46/// arguments is not here: the game installs it, as its README says.
47pub fn enabled_modules<G: GameData>() -> Vec<Box<dyn Module<G>>> {
48    // A module's ticket adds its line here, behind its feature:
49    // `#[cfg(feature = "<name>")] modules.push(Box::new(...));`.
50    Vec::new()
51}
52
53#[cfg(test)]
54mod tests {
55    use shuyi_ui::toy::{Toy, game};
56
57    use super::enabled_modules;
58
59    #[test]
60    fn every_module_turned_on_installs_beside_the_others() {
61        // With every feature on (CI's modules job), the engine's modules
62        // have names and states of their own: none is a `ModuleError`.
63        let modules = enabled_modules::<Toy>();
64        let names: Vec<&str> = modules.iter().map(|m| m.name()).collect();
65        let game = game()
66            .with_modules(modules)
67            .unwrap_or_else(|e| panic!("{e}"));
68        let installed: Vec<&str> = game.modules().iter().map(|m| m.name).collect();
69        assert_eq!(installed, names);
70    }
71
72    #[test]
73    #[cfg(all(feature = "app", not(target_os = "wasi")))]
74    fn the_prelude_names_the_short_path_and_run_game() {
75        use crate::prelude::{BasicGame, UiAction, run_game};
76        let _: fn(BasicGame<UiAction>) = run_game::<UiAction, ()>;
77    }
78}