Skip to main content

laterite_core/
module.rs

1//! Module registration.
2//!
3//! Both framework crates and application feature crates expose a [`Module`];
4//! the binary assembles the registry at startup. Registration surfaces grow
5//! as the framework does (navigation, permissions, settings, and event
6//! listeners arrive with their crates); the trait stays minimal until a
7//! caller needs more.
8
9/// A registerable unit of the application.
10pub trait Module: Send + Sync + 'static {
11    /// Stable identifier, e.g. `"auth"`.
12    fn name(&self) -> &'static str;
13}
14
15/// Ordered collection of registered modules.
16#[derive(Default)]
17pub struct ModuleRegistry {
18    modules: Vec<Box<dyn Module>>,
19}
20
21impl ModuleRegistry {
22    pub fn new() -> Self {
23        Self::default()
24    }
25
26    /// Registers a module. Order is preserved and meaningful: foundational
27    /// modules register first.
28    pub fn register(&mut self, module: impl Module) -> &mut Self {
29        self.modules.push(Box::new(module));
30        self
31    }
32
33    pub fn iter(&self) -> impl Iterator<Item = &dyn Module> + '_ {
34        self.modules.iter().map(|m| m.as_ref())
35    }
36
37    pub fn len(&self) -> usize {
38        self.modules.len()
39    }
40
41    pub fn is_empty(&self) -> bool {
42        self.modules.is_empty()
43    }
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49
50    struct A;
51    struct B;
52
53    impl Module for A {
54        fn name(&self) -> &'static str {
55            "a"
56        }
57    }
58
59    impl Module for B {
60        fn name(&self) -> &'static str {
61            "b"
62        }
63    }
64
65    #[test]
66    fn preserves_registration_order() {
67        let mut registry = ModuleRegistry::new();
68        registry.register(A).register(B);
69        let names: Vec<_> = registry.iter().map(|m| m.name()).collect();
70        assert_eq!(names, ["a", "b"]);
71    }
72}