use std::any::{Any, TypeId}; use std::fmt; use fxhash::FxHashMap; #[derive(Default)] /// A type map of request extensions. pub struct Extensions { map: FxHashMap>, } impl Extensions { /// Create an empty `Extensions`. #[inline] pub fn new() -> Extensions { Extensions { map: FxHashMap::default(), } } /// Insert a type into this `Extensions`. /// /// If a extension of this type already existed, it will /// be returned. pub fn insert(&mut self, val: T) { self.map.insert(TypeId::of::(), Box::new(val)); } /// Check if container contains entry pub fn contains(&self) -> bool { self.map.get(&TypeId::of::()).is_some() } /// Get a reference to a type previously inserted on this `Extensions`. pub fn get(&self) -> Option<&T> { self.map .get(&TypeId::of::()) .and_then(|boxed| (&**boxed as &(dyn Any + 'static)).downcast_ref()) } /// Get a mutable reference to a type previously inserted on this `Extensions`. pub fn get_mut(&mut self) -> Option<&mut T> { self.map .get_mut(&TypeId::of::()) .and_then(|boxed| (&mut **boxed as &mut (dyn Any + 'static)).downcast_mut()) } /// Remove a type from this `Extensions`. /// /// If a extension of this type existed, it will be returned. pub fn remove(&mut self) -> Option { self.map.remove(&TypeId::of::()).and_then(|boxed| { (boxed as Box) .downcast() .ok() .map(|boxed| *boxed) }) } /// Clear the `Extensions` of all inserted extensions. #[inline] pub fn clear(&mut self) { self.map.clear(); } } impl fmt::Debug for Extensions { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Extensions").finish() } } #[test] fn test_extensions() { #[derive(Debug, PartialEq)] struct MyType(i32); let mut extensions = Extensions::new(); extensions.insert(5i32); extensions.insert(MyType(10)); assert_eq!(extensions.get(), Some(&5i32)); assert_eq!(extensions.get_mut(), Some(&mut 5i32)); assert_eq!(extensions.remove::(), Some(5i32)); assert!(extensions.get::().is_none()); assert_eq!(extensions.get::(), None); assert_eq!(extensions.get(), Some(&MyType(10))); }