diff options
Diffstat (limited to 'third_party/rust/type-map')
-rw-r--r-- | third_party/rust/type-map/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | third_party/rust/type-map/Cargo.toml | 24 | ||||
-rwxr-xr-x | third_party/rust/type-map/README.md | 11 | ||||
-rwxr-xr-x | third_party/rust/type-map/src/lib.rs | 349 |
4 files changed, 385 insertions, 0 deletions
diff --git a/third_party/rust/type-map/.cargo-checksum.json b/third_party/rust/type-map/.cargo-checksum.json new file mode 100644 index 0000000000..48107174b5 --- /dev/null +++ b/third_party/rust/type-map/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"b9de957b7180f3784f79522b1a108b6c9e9f6bb16a2d089b4d0ca924d92387ae","README.md":"57bdb31dfb962b5051c8dd306a1169f762510cc6a4d47ddf854d7c77eb23c708","src/lib.rs":"cd937bd3e22abbd53798f796f646f3347ba72e44976231a3cb91ed2b1c054277"},"package":"b6d3364c5e96cb2ad1603037ab253ddd34d7fb72a58bdddf4b7350760fc69a46"}
\ No newline at end of file diff --git a/third_party/rust/type-map/Cargo.toml b/third_party/rust/type-map/Cargo.toml new file mode 100644 index 0000000000..8c05dd9b15 --- /dev/null +++ b/third_party/rust/type-map/Cargo.toml @@ -0,0 +1,24 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "type-map" +version = "0.4.0" +authors = ["Jacob Brown <kardeiz@gmail.com>"] +description = "Provides a typemap container with FxHashMap" +readme = "README.md" +keywords = ["typemap", "extensions", "hashmap"] +license = "MIT/Apache-2.0" +repository = "https://github.com/kardeiz/type-map" +[dependencies.rustc-hash] +version = "1" diff --git a/third_party/rust/type-map/README.md b/third_party/rust/type-map/README.md new file mode 100755 index 0000000000..01f87f88ea --- /dev/null +++ b/third_party/rust/type-map/README.md @@ -0,0 +1,11 @@ +# type-map + +[![Docs](https://docs.rs/type-map/badge.svg)](https://docs.rs/crate/type-map/) +[![Crates.io](https://img.shields.io/crates/v/type-map.svg)](https://crates.io/crates/type-map) + +`TypeMap` is a typed `HashMap` for `Any` values, similar to [`typemap`](https://github.com/reem/rust-typemap), +[`http::Extensions`](https://docs.rs/http/*/http/struct.Extensions.html), and [`actix-http::Extensions`](https://docs.rs/actix-http/*/actix_http/struct.Extensions.html). + +Provides the best of both `http::Extensions` and `actix_http::Extensions`, with some code and tests drawn directly from `actix-http::Extensions`. + +Useful when you need a typemap container, but not in the context of `actix-web` or an `http` project.
\ No newline at end of file diff --git a/third_party/rust/type-map/src/lib.rs b/third_party/rust/type-map/src/lib.rs new file mode 100755 index 0000000000..08558aae78 --- /dev/null +++ b/third_party/rust/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()))); +} |