jupiter_rs/
platform.rs

1use std::any::Any;
2use std::collections::HashMap;
3use std::sync::{Arc, Mutex};
4
5use crate::flag::Flag;
6
7pub struct Platform {
8    services: Mutex<HashMap<String, Arc<dyn Any + Send + Sync>>>,
9    pub is_running: Flag,
10}
11
12impl Platform {
13    pub fn new() -> Arc<Self> {
14        Arc::new(Platform {
15            services: Mutex::new(HashMap::new()),
16            is_running: Flag::new(true),
17        })
18    }
19
20    pub fn register<T>(&self, service: Arc<T>)
21    where
22        T: Any + Send + Sync,
23    {
24        let name = std::any::type_name::<T>().to_owned();
25        self.services.lock().unwrap().insert(name, service);
26    }
27
28    pub fn find<T>(&self) -> Option<Arc<T>>
29    where
30        T: Any + Send + Sync,
31    {
32        let name = std::any::type_name::<T>();
33        let services = self.services.lock().unwrap();
34        services
35            .get(name)
36            .and_then(|entry| entry.clone().downcast::<T>().ok())
37    }
38
39    pub fn require<T>(&self) -> Arc<T>
40    where
41        T: Any + Send + Sync,
42    {
43        match self.find::<T>() {
44            Some(service) => service,
45            None => panic!(
46                "A required component ({}) was not available in the platform registry!",
47                std::any::type_name::<T>()
48            ),
49        }
50    }
51
52    pub fn is_running(&self) -> bool {
53        self.is_running.read()
54    }
55
56    pub fn terminate(&self) {
57        self.is_running.change(false);
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use std::sync::Arc;
64
65    use crate::platform::Platform;
66
67    struct Foo {
68        value: i32,
69    }
70
71    struct Bar {
72        value: i32,
73    }
74
75    #[test]
76    fn registering_services_works() {
77        let platform = Platform::new();
78        platform.register(Arc::new(Foo { value: 42 }));
79        platform.register(Arc::new(Bar { value: 32 }));
80
81        let foo = platform.find::<Foo>();
82        assert_eq!(foo.is_some(), true);
83        assert_eq!(foo.unwrap().value, 42);
84
85        let bar = platform.require::<Bar>();
86        assert_eq!(bar.value, 32);
87
88        assert_eq!(platform.find::<i32>(), None);
89    }
90
91    #[test]
92    #[should_panic]
93    fn requiring_an_unknown_service_panics() {
94        let platform = Platform::new();
95        platform.require::<i32>();
96    }
97}