2018-06-16 21:22:08 +00:00
|
|
|
use std::any::{Any, TypeId};
|
|
|
|
use std::fmt;
|
|
|
|
|
2019-12-04 12:32:18 +00:00
|
|
|
use fxhash::FxHashMap;
|
2018-06-16 21:22:08 +00:00
|
|
|
|
2018-10-02 04:16:56 +00:00
|
|
|
#[derive(Default)]
|
2018-06-16 21:22:08 +00:00
|
|
|
/// A type map of request extensions.
|
|
|
|
pub struct Extensions {
|
2020-05-03 13:33:29 +00:00
|
|
|
/// Use FxHasher with a std HashMap with for faster
|
|
|
|
/// lookups on the small `TypeId` (u64 equivalent) keys.
|
2019-12-04 12:32:18 +00:00
|
|
|
map: FxHashMap<TypeId, Box<dyn Any>>,
|
2018-06-16 21:22:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Extensions {
|
|
|
|
/// Create an empty `Extensions`.
|
|
|
|
#[inline]
|
2018-08-18 17:32:28 +00:00
|
|
|
pub fn new() -> Extensions {
|
2018-06-16 21:22:08 +00:00
|
|
|
Extensions {
|
2019-12-04 12:32:18 +00:00
|
|
|
map: FxHashMap::default(),
|
2018-06-16 21:22:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Insert a type into this `Extensions`.
|
|
|
|
///
|
|
|
|
/// If a extension of this type already existed, it will
|
|
|
|
/// be returned.
|
|
|
|
pub fn insert<T: 'static>(&mut self, val: T) {
|
|
|
|
self.map.insert(TypeId::of::<T>(), Box::new(val));
|
|
|
|
}
|
|
|
|
|
2019-02-09 18:45:35 +00:00
|
|
|
/// Check if container contains entry
|
|
|
|
pub fn contains<T: 'static>(&self) -> bool {
|
2020-02-07 07:08:25 +00:00
|
|
|
self.map.contains_key(&TypeId::of::<T>())
|
2019-02-09 18:45:35 +00:00
|
|
|
}
|
|
|
|
|
2018-06-16 21:22:08 +00:00
|
|
|
/// Get a reference to a type previously inserted on this `Extensions`.
|
|
|
|
pub fn get<T: 'static>(&self) -> Option<&T> {
|
|
|
|
self.map
|
|
|
|
.get(&TypeId::of::<T>())
|
2020-02-07 07:08:25 +00:00
|
|
|
.and_then(|boxed| boxed.downcast_ref())
|
2018-06-16 21:22:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Get a mutable reference to a type previously inserted on this `Extensions`.
|
|
|
|
pub fn get_mut<T: 'static>(&mut self) -> Option<&mut T> {
|
|
|
|
self.map
|
|
|
|
.get_mut(&TypeId::of::<T>())
|
2020-02-07 07:08:25 +00:00
|
|
|
.and_then(|boxed| boxed.downcast_mut())
|
2018-06-16 21:22:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Remove a type from this `Extensions`.
|
|
|
|
///
|
|
|
|
/// If a extension of this type existed, it will be returned.
|
|
|
|
pub fn remove<T: 'static>(&mut self) -> Option<T> {
|
2020-02-07 07:08:25 +00:00
|
|
|
self.map
|
|
|
|
.remove(&TypeId::of::<T>())
|
|
|
|
.and_then(|boxed| boxed.downcast().ok().map(|boxed| *boxed))
|
2018-06-16 21:22:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Clear the `Extensions` of all inserted extensions.
|
|
|
|
#[inline]
|
|
|
|
pub fn clear(&mut self) {
|
|
|
|
self.map.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Debug for Extensions {
|
2019-12-07 18:46:51 +00:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2018-06-16 21:22:08 +00:00
|
|
|
f.debug_struct("Extensions").finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-29 17:20:47 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
2020-07-21 23:28:33 +00:00
|
|
|
|
2020-04-29 17:20:47 +00:00
|
|
|
#[test]
|
|
|
|
fn test_remove() {
|
|
|
|
let mut map = Extensions::new();
|
|
|
|
|
|
|
|
map.insert::<i8>(123);
|
|
|
|
assert!(map.get::<i8>().is_some());
|
|
|
|
|
|
|
|
map.remove::<i8>();
|
|
|
|
assert!(map.get::<i8>().is_none());
|
|
|
|
}
|
2020-02-07 07:08:25 +00:00
|
|
|
|
2020-04-29 17:20:47 +00:00
|
|
|
#[test]
|
|
|
|
fn test_clear() {
|
|
|
|
let mut map = Extensions::new();
|
2020-02-07 07:08:25 +00:00
|
|
|
|
2020-04-29 17:20:47 +00:00
|
|
|
map.insert::<i8>(8);
|
|
|
|
map.insert::<i16>(16);
|
|
|
|
map.insert::<i32>(32);
|
2020-02-07 07:08:25 +00:00
|
|
|
|
2020-04-29 17:20:47 +00:00
|
|
|
assert!(map.contains::<i8>());
|
|
|
|
assert!(map.contains::<i16>());
|
|
|
|
assert!(map.contains::<i32>());
|
2020-02-07 07:08:25 +00:00
|
|
|
|
2020-04-29 17:20:47 +00:00
|
|
|
map.clear();
|
2020-02-07 07:08:25 +00:00
|
|
|
|
2020-04-29 17:20:47 +00:00
|
|
|
assert!(!map.contains::<i8>());
|
|
|
|
assert!(!map.contains::<i16>());
|
|
|
|
assert!(!map.contains::<i32>());
|
2020-02-07 07:08:25 +00:00
|
|
|
|
2020-04-29 17:20:47 +00:00
|
|
|
map.insert::<i8>(10);
|
|
|
|
assert_eq!(*map.get::<i8>().unwrap(), 10);
|
|
|
|
}
|
2020-02-07 07:08:25 +00:00
|
|
|
|
2020-04-29 17:20:47 +00:00
|
|
|
#[test]
|
|
|
|
fn test_integers() {
|
|
|
|
let mut map = Extensions::new();
|
|
|
|
|
|
|
|
map.insert::<i8>(8);
|
|
|
|
map.insert::<i16>(16);
|
|
|
|
map.insert::<i32>(32);
|
|
|
|
map.insert::<i64>(64);
|
|
|
|
map.insert::<i128>(128);
|
|
|
|
map.insert::<u8>(8);
|
|
|
|
map.insert::<u16>(16);
|
|
|
|
map.insert::<u32>(32);
|
|
|
|
map.insert::<u64>(64);
|
|
|
|
map.insert::<u128>(128);
|
|
|
|
assert!(map.get::<i8>().is_some());
|
|
|
|
assert!(map.get::<i16>().is_some());
|
|
|
|
assert!(map.get::<i32>().is_some());
|
|
|
|
assert!(map.get::<i64>().is_some());
|
|
|
|
assert!(map.get::<i128>().is_some());
|
|
|
|
assert!(map.get::<u8>().is_some());
|
|
|
|
assert!(map.get::<u16>().is_some());
|
|
|
|
assert!(map.get::<u32>().is_some());
|
|
|
|
assert!(map.get::<u64>().is_some());
|
|
|
|
assert!(map.get::<u128>().is_some());
|
|
|
|
}
|
2020-02-07 07:08:25 +00:00
|
|
|
|
2020-04-29 17:20:47 +00:00
|
|
|
#[test]
|
|
|
|
fn test_composition() {
|
|
|
|
struct Magi<T>(pub T);
|
2020-02-07 07:08:25 +00:00
|
|
|
|
2020-04-29 17:20:47 +00:00
|
|
|
struct Madoka {
|
|
|
|
pub god: bool,
|
|
|
|
}
|
2020-02-07 07:08:25 +00:00
|
|
|
|
2020-04-29 17:20:47 +00:00
|
|
|
struct Homura {
|
|
|
|
pub attempts: usize,
|
|
|
|
}
|
2020-02-07 07:08:25 +00:00
|
|
|
|
2020-04-29 17:20:47 +00:00
|
|
|
struct Mami {
|
|
|
|
pub guns: usize,
|
|
|
|
}
|
2020-02-07 07:08:25 +00:00
|
|
|
|
2020-04-29 17:20:47 +00:00
|
|
|
let mut map = Extensions::new();
|
2020-02-07 07:08:25 +00:00
|
|
|
|
2020-04-29 17:20:47 +00:00
|
|
|
map.insert(Magi(Madoka { god: false }));
|
|
|
|
map.insert(Magi(Homura { attempts: 0 }));
|
|
|
|
map.insert(Magi(Mami { guns: 999 }));
|
2020-02-07 07:08:25 +00:00
|
|
|
|
2020-04-29 17:20:47 +00:00
|
|
|
assert!(!map.get::<Magi<Madoka>>().unwrap().0.god);
|
|
|
|
assert_eq!(0, map.get::<Magi<Homura>>().unwrap().0.attempts);
|
|
|
|
assert_eq!(999, map.get::<Magi<Mami>>().unwrap().0.guns);
|
|
|
|
}
|
2020-02-07 07:08:25 +00:00
|
|
|
|
2020-04-29 17:20:47 +00:00
|
|
|
#[test]
|
|
|
|
fn test_extensions() {
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
|
struct MyType(i32);
|
2018-06-16 21:22:08 +00:00
|
|
|
|
2020-04-29 17:20:47 +00:00
|
|
|
let mut extensions = Extensions::new();
|
2018-06-16 21:22:08 +00:00
|
|
|
|
2020-04-29 17:20:47 +00:00
|
|
|
extensions.insert(5i32);
|
|
|
|
extensions.insert(MyType(10));
|
2018-06-16 21:22:08 +00:00
|
|
|
|
2020-04-29 17:20:47 +00:00
|
|
|
assert_eq!(extensions.get(), Some(&5i32));
|
|
|
|
assert_eq!(extensions.get_mut(), Some(&mut 5i32));
|
2018-06-16 21:22:08 +00:00
|
|
|
|
2020-04-29 17:20:47 +00:00
|
|
|
assert_eq!(extensions.remove::<i32>(), Some(5i32));
|
|
|
|
assert!(extensions.get::<i32>().is_none());
|
2018-06-16 21:22:08 +00:00
|
|
|
|
2020-04-29 17:20:47 +00:00
|
|
|
assert_eq!(extensions.get::<bool>(), None);
|
|
|
|
assert_eq!(extensions.get(), Some(&MyType(10)));
|
|
|
|
}
|
2018-06-16 21:22:08 +00:00
|
|
|
}
|