Skip to main content

eave_api/
registry.rs

1use crate::Widget;
2use crate::erased::{Constructor, construct};
3
4/// The widgets every plugin makes available, by the name `config.toml` uses.
5/// Cheap to clone: names and function pointers.
6#[derive(Default, Clone)]
7pub struct Registry {
8    widgets: Vec<(&'static str, Constructor)>,
9}
10
11impl Registry {
12    pub fn new() -> Self {
13        Self::default()
14    }
15
16    /// Makes `W` available as `widget = "<name>"` in the config.
17    pub fn widget<W: Widget>(&mut self, name: &'static str) {
18        self.widgets.push((name, construct::<W>));
19    }
20
21    #[doc(hidden)]
22    pub fn get(&self, name: &str) -> Option<Constructor> {
23        self.widgets
24            .iter()
25            .find(|(registered, _)| *registered == name)
26            .map(|(_, constructor)| *constructor)
27    }
28
29    /// Names registered more than once. Two plugins claiming one name is a build error to report,
30    /// not something to resolve silently.
31    #[doc(hidden)]
32    pub fn duplicates(&self) -> Vec<&'static str> {
33        let mut names: Vec<_> = self.widgets.iter().map(|(name, _)| *name).collect();
34        names.sort_unstable();
35        let mut duplicates: Vec<_> = names
36            .windows(2)
37            .filter(|pair| pair[0] == pair[1])
38            .map(|pair| pair[0])
39            .collect();
40        duplicates.dedup();
41        duplicates
42    }
43}
44
45#[cfg(test)]
46mod tests {
47    use super::*;
48    use crate::ui::{Item, label};
49    use crate::{Effect, Task};
50
51    struct Dummy;
52
53    impl Widget for Dummy {
54        type Config = toml::Table;
55        type Message = ();
56
57        fn new(_: Self::Config) -> (Self, Task<()>) {
58            (Self, Task::none())
59        }
60
61        fn update(&mut self, _: ()) -> Effect<()> {
62            Effect::none()
63        }
64
65        fn item(&self) -> Item<()> {
66            Item::new(label("dummy"))
67        }
68    }
69
70    #[test]
71    fn finds_and_reports_duplicates() {
72        let mut registry = Registry::new();
73        registry.widget::<Dummy>("a");
74        registry.widget::<Dummy>("b");
75        registry.widget::<Dummy>("a");
76        assert!(registry.get("b").is_some());
77        assert!(registry.get("c").is_none());
78        assert_eq!(registry.duplicates(), ["a"]);
79    }
80}