imperat_common/
dependencies.rs1use std::{
2 any::{Any, TypeId},
3 collections::HashMap,
4 ops::Deref,
5 sync::Arc,
6};
7use variadics_please::all_tuples;
8
9#[derive(Default, Debug)]
14pub struct TypeMap {
15 bindings: HashMap<TypeId, Box<dyn Any>>,
16}
17
18impl TypeMap {
19 pub fn new() -> Self {
21 TypeMap::default()
22 }
23
24 pub fn bind<T: Any>(&mut self, val: T) -> Option<Box<T>> {
28 self.bindings
29 .insert(val.type_id(), Box::new(val))
30 .and_then(|v| v.downcast().ok())
31 }
32
33 pub fn get<T: Any>(&self) -> Option<&T> {
35 self.bindings
36 .get(&TypeId::of::<T>())
37 .and_then(|boxed| boxed.downcast_ref())
38 }
39}
40
41pub trait FromTypeMap: Any + Sized {
44 fn retrieve_from_map(tm: &TypeMap) -> Option<Self>;
45}
46
47macro_rules! impl_fromtypemap_tuples {
54 ($($param: ident),*) => {
55 #[allow(
56 non_snake_case,
57 reason = "Certain variable names are provided by the caller, not by us."
58 )]
59 #[allow(
60 unused_variables,
61 reason = "Zero-length tuples won't use some of the parameters."
62 )]
63 #[expect(
64 clippy::allow_attributes,
65 reason = "This is in a macro, and as such, the below lints may not always apply."
66 )]
67 impl<$($param: FromTypeMap,)*> FromTypeMap for ($($param,)*) {
68 fn retrieve_from_map(tm: &TypeMap) -> Option<Self> {
69 (
70 Some(($(
71 $param::retrieve_from_map(tm)?,
72 )*))
73 )
74 }
75 }
76 }
77}
78
79all_tuples!(impl_fromtypemap_tuples, 0, 16, F);
80
81pub struct Dep<T: ?Sized>(Arc<T>);
84
85impl<T> Dep<T> {
86 pub fn new(val: T) -> Dep<T> {
88 Dep(Arc::new(val))
89 }
90
91 #[must_use]
93 pub fn inner(self) -> Arc<T> {
94 self.0
95 }
96}
97
98impl<T: ?Sized> Clone for Dep<T> {
99 fn clone(&self) -> Self {
100 Dep(self.0.clone())
101 }
102}
103
104impl<T: ?Sized> Deref for Dep<T> {
105 type Target = Arc<T>;
106
107 fn deref(&self) -> &Arc<T> {
108 &self.0
109 }
110}
111
112impl<T: ?Sized + 'static> FromTypeMap for Dep<T> {
113 fn retrieve_from_map(tm: &TypeMap) -> Option<Self> {
114 tm.get::<Self>().cloned()
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121
122 struct Database;
123 #[derive(Debug)]
124 struct Config(i32, u32);
125
126 #[test]
128 fn test_retrieval() {
129 let mut tm = TypeMap::new();
130
131 tm.bind(Dep::new(Database));
132 tm.bind(Dep::new(Config(2, 3)));
133
134 tm.get::<Dep<Database>>().unwrap();
135 let cfg = tm.get::<Dep<Config>>().unwrap();
136
137 assert_eq!(cfg.0.0, 2);
140 assert_eq!(cfg.0.1, 3);
141 }
142
143 #[test]
145 fn test_missing() {
146 let tm = TypeMap::new();
147 assert!(tm.get::<Dep<i32>>().is_none());
148 }
149}