diff options
Diffstat (limited to 'vendor/type-map/src/lib.rs')
-rwxr-xr-x | vendor/type-map/src/lib.rs | 349 |
1 files changed, 349 insertions, 0 deletions
diff --git a/vendor/type-map/src/lib.rs b/vendor/type-map/src/lib.rs new file mode 100755 index 000000000..08558aae7 --- /dev/null +++ b/vendor/type-map/src/lib.rs @@ -0,0 +1,349 @@ +use std::any::{Any, TypeId}; + +use rustc_hash::FxHashMap; + +use std::collections::hash_map; +use std::marker::PhantomData; + +/// A view into an occupied entry in a `TypeMap`. +#[derive(Debug)] +pub struct OccupiedEntry<'a, T> { + data: hash_map::OccupiedEntry<'a, TypeId, Box<dyn Any>>, + marker: PhantomData<fn(T)>, +} + +impl<'a, T: 'static> OccupiedEntry<'a, T> { + /// Gets a reference to the value in the entry. + pub fn get(&self) -> &T { + self.data.get().downcast_ref().unwrap() + } + + ///Gets a mutable reference to the value in the entry. + pub fn get_mut(&mut self) -> &mut T { + self.data.get_mut().downcast_mut().unwrap() + } + + /// Converts the `OccupiedEntry` into a mutable reference to the value in the entry + /// with a lifetime bound to the map itself. + pub fn into_mut(self) -> &'a mut T { + self.data.into_mut().downcast_mut().unwrap() + } + + /// Sets the value of the entry, and returns the entry's old value. + pub fn insert(&mut self, value: T) -> T { + self.data.insert(Box::new(value)).downcast().map(|boxed| *boxed).unwrap() + } + + /// Takes the value out of the entry, and returns it. + pub fn remove(self) -> T { + self.data.remove().downcast().map(|boxed| *boxed).unwrap() + } +} + +/// A view into a vacant entry in a `TypeMap`. +#[derive(Debug)] +pub struct VacantEntry<'a, T> { + data: hash_map::VacantEntry<'a, TypeId, Box<dyn Any>>, + marker: PhantomData<fn(T)>, +} + +impl<'a, T: 'static> VacantEntry<'a, T> { + /// Sets the value of the entry with the key of the `VacantEntry`, and returns a mutable reference to it. + pub fn insert(self, value: T) -> &'a mut T { + self.data.insert(Box::new(value)).downcast_mut().unwrap() + } +} + +/// A view into a single entry in a map, which may either be vacant or occupied. +#[derive(Debug)] +pub enum Entry<'a, T> { + Occupied(OccupiedEntry<'a, T>), + Vacant(VacantEntry<'a, T>), +} + +impl<'a, T: 'static> Entry<'a, T> { + /// Ensures a value is in the entry by inserting the default if empty, and returns + /// a mutable reference to the value in the entry. + pub fn or_insert(self, default: T) -> &'a mut T { + match self { + Entry::Occupied(inner) => inner.into_mut(), + Entry::Vacant(inner) => inner.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, and returns + /// a mutable reference to the value in the entry. + pub fn or_insert_with<F: FnOnce() -> T>(self, default: F) -> &'a mut T { + match self { + Entry::Occupied(inner) => inner.into_mut(), + Entry::Vacant(inner) => inner.insert(default()), + } + } +} + +#[derive(Debug, Default)] +/// The typemap container +pub struct TypeMap { + map: Option<FxHashMap<TypeId, Box<dyn Any>>>, +} + +impl TypeMap { + /// Create an empty `TypeMap`. + #[inline] + pub fn new() -> Self { + Self { map: None } + } + + /// Insert a value into this `TypeMap`. + /// + /// If a value of this type already exists, it will be returned. + pub fn insert<T: 'static>(&mut self, val: T) -> Option<T> { + self.map + .get_or_insert_with(|| FxHashMap::default()) + .insert(TypeId::of::<T>(), Box::new(val)) + .and_then(|boxed| boxed.downcast().ok().map(|boxed| *boxed)) + } + + /// Check if container contains value for type + pub fn contains<T: 'static>(&self) -> bool { + self.map.as_ref().and_then(|m| m.get(&TypeId::of::<T>())).is_some() + } + + /// Get a reference to a value previously inserted on this `TypeMap`. + pub fn get<T: 'static>(&self) -> Option<&T> { + self.map + .as_ref() + .and_then(|m| m.get(&TypeId::of::<T>())) + .and_then(|boxed| boxed.downcast_ref()) + } + + /// Get a mutable reference to a value previously inserted on this `TypeMap`. + pub fn get_mut<T: 'static>(&mut self) -> Option<&mut T> { + self.map + .as_mut() + .and_then(|m| m.get_mut(&TypeId::of::<T>())) + .and_then(|boxed| boxed.downcast_mut()) + } + + /// Remove a value from this `TypeMap`. + /// + /// If a value of this type exists, it will be returned. + pub fn remove<T: 'static>(&mut self) -> Option<T> { + self.map + .as_mut() + .and_then(|m| m.remove(&TypeId::of::<T>())) + .and_then(|boxed| boxed.downcast().ok().map(|boxed| *boxed)) + } + + /// Clear the `TypeMap` of all inserted values. + #[inline] + pub fn clear(&mut self) { + self.map = None; + } + + /// Get an entry in the `TypeMap` for in-place manipulation. + pub fn entry<T: 'static>(&mut self) -> Entry<T> { + match self.map.get_or_insert_with(|| FxHashMap::default()).entry(TypeId::of::<T>()) { + hash_map::Entry::Occupied(e) => { + Entry::Occupied(OccupiedEntry { data: e, marker: PhantomData }) + } + hash_map::Entry::Vacant(e) => { + Entry::Vacant(VacantEntry { data: e, marker: PhantomData }) + } + } + } +} + +/// Provides the same `TypeMap` container, but with `Send` + `Sync` bounds on values +pub mod concurrent { + + use std::any::{Any, TypeId}; + + use rustc_hash::FxHashMap; + + use std::collections::hash_map; + use std::marker::PhantomData; + + /// A view into an occupied entry in a `TypeMap`. + #[derive(Debug)] + pub struct OccupiedEntry<'a, T> { + data: hash_map::OccupiedEntry<'a, TypeId, Box<dyn Any + Send + Sync>>, + marker: PhantomData<fn(T)>, + } + + impl<'a, T: 'static + Send + Sync> OccupiedEntry<'a, T> { + /// Gets a reference to the value in the entry. + pub fn get(&self) -> &T { + self.data.get().downcast_ref().unwrap() + } + + ///Gets a mutable reference to the value in the entry. + pub fn get_mut(&mut self) -> &mut T { + self.data.get_mut().downcast_mut().unwrap() + } + + /// Converts the `OccupiedEntry` into a mutable reference to the value in the entry + /// with a lifetime bound to the map itself. + pub fn into_mut(self) -> &'a mut T { + self.data.into_mut().downcast_mut().unwrap() + } + + /// Sets the value of the entry, and returns the entry's old value. + pub fn insert(&mut self, value: T) -> T { + (self.data.insert(Box::new(value)) as Box<dyn Any>) + .downcast() + .map(|boxed| *boxed) + .unwrap() + } + + /// Takes the value out of the entry, and returns it. + pub fn remove(self) -> T { + (self.data.remove() as Box<dyn Any>).downcast().map(|boxed| *boxed).unwrap() + } + } + + /// A view into a vacant entry in a `TypeMap`. + #[derive(Debug)] + pub struct VacantEntry<'a, T> { + data: hash_map::VacantEntry<'a, TypeId, Box<dyn Any + Send + Sync>>, + marker: PhantomData<fn(T)>, + } + + impl<'a, T: 'static + Send + Sync> VacantEntry<'a, T> { + /// Sets the value of the entry with the key of the `VacantEntry`, and returns a mutable reference to it. + pub fn insert(self, value: T) -> &'a mut T { + self.data.insert(Box::new(value)).downcast_mut().unwrap() + } + } + + /// A view into a single entry in a map, which may either be vacant or occupied. + #[derive(Debug)] + pub enum Entry<'a, T> { + Occupied(OccupiedEntry<'a, T>), + Vacant(VacantEntry<'a, T>), + } + + impl<'a, T: 'static + Send + Sync> Entry<'a, T> { + /// Ensures a value is in the entry by inserting the default if empty, and returns + /// a mutable reference to the value in the entry. + pub fn or_insert(self, default: T) -> &'a mut T { + match self { + Entry::Occupied(inner) => inner.into_mut(), + Entry::Vacant(inner) => inner.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, and returns + /// a mutable reference to the value in the entry. + pub fn or_insert_with<F: FnOnce() -> T>(self, default: F) -> &'a mut T { + match self { + Entry::Occupied(inner) => inner.into_mut(), + Entry::Vacant(inner) => inner.insert(default()), + } + } + } + + #[derive(Debug, Default)] + /// The typemap container + pub struct TypeMap { + map: Option<FxHashMap<TypeId, Box<dyn Any + Send + Sync>>>, + } + + impl TypeMap { + /// Create an empty `TypeMap`. + #[inline] + pub fn new() -> Self { + Self { map: None } + } + + /// Insert a value into this `TypeMap`. + /// + /// If a value of this type already exists, it will be returned. + pub fn insert<T: Send + Sync + 'static>(&mut self, val: T) -> Option<T> { + self.map + .get_or_insert_with(|| FxHashMap::default()) + .insert(TypeId::of::<T>(), Box::new(val)) + .and_then(|boxed| (boxed as Box<dyn Any>).downcast().ok().map(|boxed| *boxed)) + } + + /// Check if container contains value for type + pub fn contains<T: 'static>(&self) -> bool { + self.map.as_ref().and_then(|m| m.get(&TypeId::of::<T>())).is_some() + } + + /// Get a reference to a value previously inserted on this `TypeMap`. + pub fn get<T: 'static>(&self) -> Option<&T> { + self.map + .as_ref() + .and_then(|m| m.get(&TypeId::of::<T>())) + .and_then(|boxed| boxed.downcast_ref()) + } + + /// Get a mutable reference to a value previously inserted on this `TypeMap`. + pub fn get_mut<T: 'static>(&mut self) -> Option<&mut T> { + self.map + .as_mut() + .and_then(|m| m.get_mut(&TypeId::of::<T>())) + .and_then(|boxed| boxed.downcast_mut()) + } + + /// Remove a value from this `TypeMap`. + /// + /// If a value of this type exists, it will be returned. + pub fn remove<T: 'static>(&mut self) -> Option<T> { + self.map + .as_mut() + .and_then(|m| m.remove(&TypeId::of::<T>())) + .and_then(|boxed| (boxed as Box<dyn Any>).downcast().ok().map(|boxed| *boxed)) + } + + /// Clear the `TypeMap` of all inserted values. + #[inline] + pub fn clear(&mut self) { + self.map = None; + } + + /// Get an entry in the `TypeMap` for in-place manipulation. + pub fn entry<T: 'static + Send + Sync>(&mut self) -> Entry<T> { + match self.map.get_or_insert_with(|| FxHashMap::default()).entry(TypeId::of::<T>()) { + hash_map::Entry::Occupied(e) => { + Entry::Occupied(OccupiedEntry { data: e, marker: PhantomData }) + } + hash_map::Entry::Vacant(e) => { + Entry::Vacant(VacantEntry { data: e, marker: PhantomData }) + } + } + } + } +} + +#[test] +fn test_type_map() { + #[derive(Debug, PartialEq)] + struct MyType(i32); + + #[derive(Debug, PartialEq, Default)] + struct MyType2(String); + + let mut map = TypeMap::new(); + + map.insert(5i32); + map.insert(MyType(10)); + + assert_eq!(map.get(), Some(&5i32)); + assert_eq!(map.get_mut(), Some(&mut 5i32)); + + assert_eq!(map.remove::<i32>(), Some(5i32)); + assert!(map.get::<i32>().is_none()); + + assert_eq!(map.get::<bool>(), None); + assert_eq!(map.get(), Some(&MyType(10))); + + let entry = map.entry::<MyType2>(); + + let mut v = entry.or_insert_with(MyType2::default); + + v.0 = "Hello".into(); + + assert_eq!(map.get(), Some(&MyType2("Hello".into()))); +} |