use std::any::{Any, TypeId}; use std::collections::HashMap; use std::fmt; use std::hash::BuildHasherDefault; use fnv::FnvHasher; type AnyMap = HashMap, BuildHasherDefault>; /// A type map of request extensions. pub struct Extensions { map: AnyMap, } impl Extensions { /// Create an empty `Extensions`. #[inline] pub(crate) fn new() -> Extensions { Extensions { map: HashMap::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)); } /// 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 &(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 (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))); }