type-map-0.5.0/.cargo_vcs_info.json0000644000000001121401361671200126230ustar { "git": { "sha1": "07b12c54735c4c3599586c7b2fe28a24982d2ebe" } } type-map-0.5.0/.gitignore010077700017500001750000000000361400267571500134360ustar 00000000000000/target **/*.rs.bk Cargo.lock type-map-0.5.0/Cargo.toml0000644000000015611401361671200106320ustar # 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.5.0" authors = ["Jacob Brown "] 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" type-map-0.5.0/Cargo.toml.orig010077700017500001750000000005361401361604200143300ustar 00000000000000[package] name = "type-map" version = "0.5.0" authors = ["Jacob Brown "] edition = "2018" license = "MIT/Apache-2.0" repository = "https://github.com/kardeiz/type-map" readme = "README.md" keywords = ["typemap", "extensions", "hashmap"] description = "Provides a typemap container with FxHashMap" [dependencies] rustc-hash = "1" type-map-0.5.0/README.md010077700017500001750000000013161400267571500127270ustar 00000000000000# 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.type-map-0.5.0/src/lib.rs010077700017500001750000000323131401361662100133450ustar 00000000000000use std::any::{Any, TypeId}; use rustc_hash::FxHashMap; use std::collections::hash_map; use std::marker::PhantomData; /// Prepared key-value pair pub struct KvPair(TypeId, Box); impl KvPair { pub fn new(value: T) -> Self { KvPair(TypeId::of::(), Box::new(value)) } pub fn extract(self) -> Result { let KvPair(key, value) = self; value.downcast().map(|boxed| *boxed).map_err(|e| KvPair(key, e)) } } /// A view into an occupied entry in a `TypeMap`. #[derive(Debug)] pub struct OccupiedEntry<'a, T> { data: hash_map::OccupiedEntry<'a, TypeId, Box>, marker: PhantomData, } 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>, marker: PhantomData, } 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 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>>, } impl TypeMap { /// Create an empty `TypeMap`. #[inline] pub fn new() -> Self { Self { map: None } } /// Insert a prepared `KvPair` into this `TypeMap`. /// /// If a value of this type already exists, it will be returned. pub fn insert_kv_pair(&mut self, KvPair(key, value): KvPair) -> Option { self.map .get_or_insert_with(|| FxHashMap::default()) .insert(key, value) .map(|old_value| KvPair(key, old_value)) } /// Insert a value into this `TypeMap`. /// /// If a value of this type already exists, it will be returned. pub fn insert(&mut self, val: T) -> Option { self.map .get_or_insert_with(|| FxHashMap::default()) .insert(TypeId::of::(), Box::new(val)) .and_then(|boxed| boxed.downcast().ok().map(|boxed| *boxed)) } /// Check if container contains value for type pub fn contains(&self) -> bool { self.map.as_ref().and_then(|m| m.get(&TypeId::of::())).is_some() } /// Get a reference to a value previously inserted on this `TypeMap`. pub fn get(&self) -> Option<&T> { self.map .as_ref() .and_then(|m| m.get(&TypeId::of::())) .and_then(|boxed| boxed.downcast_ref()) } /// Get a mutable reference to a value previously inserted on this `TypeMap`. pub fn get_mut(&mut self) -> Option<&mut T> { self.map .as_mut() .and_then(|m| m.get_mut(&TypeId::of::())) .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(&mut self) -> Option { self.map .as_mut() .and_then(|m| m.remove(&TypeId::of::())) .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(&mut self) -> Entry { match self.map.get_or_insert_with(|| FxHashMap::default()).entry(TypeId::of::()) { 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; /// Prepared key-value pair pub struct KvPair(TypeId, Box); impl KvPair { pub fn new(value: T) -> Self { KvPair(TypeId::of::(), Box::new(value)) } pub fn extract(self) -> Result { let KvPair(key, value) = self; if value.is::() { Ok((value as Box).downcast().map(|boxed| *boxed).unwrap()) } else { Err(KvPair(key, value)) } } } /// A view into an occupied entry in a `TypeMap`. #[derive(Debug)] pub struct OccupiedEntry<'a, T> { data: hash_map::OccupiedEntry<'a, TypeId, Box>, marker: PhantomData, } 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) .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).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>, marker: PhantomData, } 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 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>>, } impl TypeMap { /// Create an empty `TypeMap`. #[inline] pub fn new() -> Self { Self { map: None } } /// Insert a prepared `KvPair` into this `TypeMap`. /// /// If a value of this type already exists, it will be returned. pub fn insert_kv_pair(&mut self, KvPair(key, value): KvPair) -> Option { self.map .get_or_insert_with(|| FxHashMap::default()) .insert(key, value) .map(|old_value| KvPair(key, old_value)) } /// Insert a value into this `TypeMap`. /// /// If a value of this type already exists, it will be returned. pub fn insert(&mut self, val: T) -> Option { self.map .get_or_insert_with(|| FxHashMap::default()) .insert(TypeId::of::(), Box::new(val)) .and_then(|boxed| (boxed as Box).downcast().ok().map(|boxed| *boxed)) } /// Check if container contains value for type pub fn contains(&self) -> bool { self.map.as_ref().and_then(|m| m.get(&TypeId::of::())).is_some() } /// Get a reference to a value previously inserted on this `TypeMap`. pub fn get(&self) -> Option<&T> { self.map .as_ref() .and_then(|m| m.get(&TypeId::of::())) .and_then(|boxed| boxed.downcast_ref()) } /// Get a mutable reference to a value previously inserted on this `TypeMap`. pub fn get_mut(&mut self) -> Option<&mut T> { self.map .as_mut() .and_then(|m| m.get_mut(&TypeId::of::())) .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(&mut self) -> Option { self.map .as_mut() .and_then(|m| m.remove(&TypeId::of::())) .and_then(|boxed| (boxed as Box).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(&mut self) -> Entry { match self.map.get_or_insert_with(|| FxHashMap::default()).entry(TypeId::of::()) { 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::(), Some(5i32)); assert!(map.get::().is_none()); assert_eq!(map.get::(), None); assert_eq!(map.get(), Some(&MyType(10))); let entry = map.entry::(); let mut v = entry.or_insert_with(MyType2::default); v.0 = "Hello".into(); assert_eq!(map.get(), Some(&MyType2("Hello".into()))); }