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