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}