Skip to main content

neco_server_router/
extensions.rs

1use std::any::{Any, TypeId};
2use std::collections::HashMap;
3
4/// Request-local typed extensions for router and middleware context.
5#[derive(Default)]
6pub struct Extensions {
7    entries: HashMap<TypeId, Box<dyn Any + Send + Sync>>,
8}
9
10impl Extensions {
11    /// Creates an empty extensions map.
12    pub fn new() -> Self {
13        Self::default()
14    }
15
16    /// Inserts a typed value, replacing any previous value of the same type.
17    pub fn insert<T>(&mut self, value: T) -> Option<T>
18    where
19        T: Any + Send + Sync + 'static,
20    {
21        self.entries
22            .insert(TypeId::of::<T>(), Box::new(value))
23            .and_then(|value| value.downcast::<T>().ok())
24            .map(|value| *value)
25    }
26
27    /// Returns a shared reference to a previously inserted typed value.
28    pub fn get<T>(&self) -> Option<&T>
29    where
30        T: Any + Send + Sync + 'static,
31    {
32        self.entries
33            .get(&TypeId::of::<T>())
34            .and_then(|value| value.downcast_ref::<T>())
35    }
36
37    /// Returns a mutable reference to a previously inserted typed value.
38    pub fn get_mut<T>(&mut self) -> Option<&mut T>
39    where
40        T: Any + Send + Sync + 'static,
41    {
42        self.entries
43            .get_mut(&TypeId::of::<T>())
44            .and_then(|value| value.downcast_mut::<T>())
45    }
46
47    /// Removes a previously inserted typed value.
48    pub fn remove<T>(&mut self) -> Option<T>
49    where
50        T: Any + Send + Sync + 'static,
51    {
52        self.entries
53            .remove(&TypeId::of::<T>())
54            .and_then(|value| value.downcast::<T>().ok())
55            .map(|value| *value)
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::Extensions;
62
63    #[test]
64    fn extensions_store_typed_values() {
65        let mut extensions = Extensions::new();
66        assert_eq!(extensions.insert::<u64>(7), None);
67        assert_eq!(extensions.get::<u64>(), Some(&7));
68        assert_eq!(extensions.remove::<u64>(), Some(7));
69        assert_eq!(extensions.get::<u64>(), None);
70    }
71}