diff options
| -rw-r--r-- | crates/anymap/src/lib.rs | 370 |
1 files changed, 176 insertions, 194 deletions
diff --git a/crates/anymap/src/lib.rs b/crates/anymap/src/lib.rs index 967c3769ec6..d8c6c889f78 100644 --- a/crates/anymap/src/lib.rs +++ b/crates/anymap/src/lib.rs @@ -10,21 +10,15 @@ //! This crate has two independent features, each of which provides an implementation providing //! types `Map`, `AnyMap`, `OccupiedEntry`, `VacantEntry`, `Entry` and `RawMap`: //! -#![cfg_attr(feature = "std", doc = " - **std** (default, *enabled* in this build):")] -#![cfg_attr(not(feature = "std"), doc = " - **std** (default, *disabled* in this build):")] +//! - **std** (default, *enabled* in this build): //! an implementation using `std::collections::hash_map`, placed in the crate root //! (e.g. `anymap::AnyMap`). //! -#![cfg_attr(feature = "hashbrown", doc = " - **hashbrown** (optional; *enabled* in this build):")] -#![cfg_attr( - not(feature = "hashbrown"), - doc = " - **hashbrown** (optional; *disabled* in this build):" -)] +//! - **hashbrown** (optional; *enabled* in this build): //! an implementation using `alloc` and `hashbrown::hash_map`, placed in a module `hashbrown` //! (e.g. `anymap::hashbrown::AnyMap`). #![warn(missing_docs, unused_results)] -#![cfg_attr(not(feature = "std"), no_std)] use core::convert::TryInto; use core::hash::Hasher; @@ -63,213 +57,201 @@ impl Hasher for TypeIdHasher { } } -#[cfg(any(feature = "std", feature = "hashbrown"))] -macro_rules! everything { - ($example_init:literal, $($parent:ident)::+ $(, $entry_generics:ty)?) => { - use core::any::{Any, TypeId}; - use core::hash::BuildHasherDefault; - use core::marker::PhantomData; +use core::any::{Any, TypeId}; +use core::hash::BuildHasherDefault; +use core::marker::PhantomData; - #[cfg(not(feature = "std"))] - use alloc::boxed::Box; +use ::std::collections::hash_map::{self, HashMap}; - use ::$($parent)::+::hash_map::{self, HashMap}; +use crate::any::{Downcast, IntoBox}; - use crate::any::{Downcast, IntoBox}; +/// Raw access to the underlying `HashMap`. +/// +/// This alias is provided for convenience because of the ugly third generic parameter. +pub type RawMap<A> = HashMap<TypeId, Box<A>, BuildHasherDefault<TypeIdHasher>>; - /// Raw access to the underlying `HashMap`. - /// - /// This alias is provided for convenience because of the ugly third generic parameter. - pub type RawMap<A> = HashMap<TypeId, Box<A>, BuildHasherDefault<TypeIdHasher>>; +/// A collection containing zero or one values for any given type and allowing convenient, +/// type-safe access to those values. +/// +/// The type parameter `A` allows you to use a different value type; normally you will want +/// it to be `core::any::Any` (also known as `std::any::Any`), but there are other choices: +/// +/// - If you want the entire map to be cloneable, use `CloneAny` instead of `Any`; with +/// that, you can only add types that implement `Clone` to the map. +/// - You can add on `+ Send` or `+ Send + Sync` (e.g. `Map<dyn Any + Send>`) to add those +/// auto traits. +/// +/// Cumulatively, there are thus six forms of map: +/// +/// - <code>[Map]<dyn [core::any::Any]></code>, +/// also spelled [`AnyMap`] for convenience. +/// - <code>[Map]<dyn [core::any::Any] + Send></code> +/// - <code>[Map]<dyn [core::any::Any] + Send + Sync></code> +/// - <code>[Map]<dyn [CloneAny]></code> +/// - <code>[Map]<dyn [CloneAny] + Send></code> +/// - <code>[Map]<dyn [CloneAny] + Send + Sync></code> +/// +/// ## Example +/// +/// (Here using the [`AnyMap`] convenience alias; the first line could use +/// <code>[anymap::Map][Map]::<[core::any::Any]>::new()</code> instead if desired.) +/// +/// ```rust +#[doc = "let mut data = anymap::AnyMap::new();"] +/// assert_eq!(data.get(), None::<&i32>); +/// ``` +/// +/// Values containing non-static references are not permitted. +#[derive(Debug)] +pub struct Map<A: ?Sized + Downcast = dyn Any> { + raw: RawMap<A>, +} - /// A collection containing zero or one values for any given type and allowing convenient, - /// type-safe access to those values. - /// - /// The type parameter `A` allows you to use a different value type; normally you will want - /// it to be `core::any::Any` (also known as `std::any::Any`), but there are other choices: - /// - /// - If you want the entire map to be cloneable, use `CloneAny` instead of `Any`; with - /// that, you can only add types that implement `Clone` to the map. - /// - You can add on `+ Send` or `+ Send + Sync` (e.g. `Map<dyn Any + Send>`) to add those - /// auto traits. - /// - /// Cumulatively, there are thus six forms of map: - /// - /// - <code>[Map]<dyn [core::any::Any]></code>, - /// also spelled [`AnyMap`] for convenience. - /// - <code>[Map]<dyn [core::any::Any] + Send></code> - /// - <code>[Map]<dyn [core::any::Any] + Send + Sync></code> - /// - <code>[Map]<dyn [CloneAny]></code> - /// - <code>[Map]<dyn [CloneAny] + Send></code> - /// - <code>[Map]<dyn [CloneAny] + Send + Sync></code> - /// - /// ## Example - /// - /// (Here using the [`AnyMap`] convenience alias; the first line could use - /// <code>[anymap::Map][Map]::<[core::any::Any]>::new()</code> instead if desired.) - /// - /// ```rust - #[doc = $example_init] - /// assert_eq!(data.get(), None::<&i32>); - /// ``` - /// - /// Values containing non-static references are not permitted. - #[derive(Debug)] - pub struct Map<A: ?Sized + Downcast = dyn Any> { - raw: RawMap<A>, - } +/// The most common type of `Map`: just using `Any`; <code>[Map]<dyn [Any]></code>. +/// +/// Why is this a separate type alias rather than a default value for `Map<A>`? +/// `Map::new()` doesn’t seem to be happy to infer that it should go with the default +/// value. It’s a bit sad, really. Ah well, I guess this approach will do. +pub type AnyMap = Map<dyn Any>; +impl<A: ?Sized + Downcast> Default for Map<A> { + #[inline] + fn default() -> Map<A> { + Map::new() + } +} - /// The most common type of `Map`: just using `Any`; <code>[Map]<dyn [Any]></code>. - /// - /// Why is this a separate type alias rather than a default value for `Map<A>`? - /// `Map::new()` doesn’t seem to be happy to infer that it should go with the default - /// value. It’s a bit sad, really. Ah well, I guess this approach will do. - pub type AnyMap = Map<dyn Any>; - impl<A: ?Sized + Downcast> Default for Map<A> { - #[inline] - fn default() -> Map<A> { - Map::new() - } - } +impl<A: ?Sized + Downcast> Map<A> { + /// Create an empty collection. + #[inline] + pub fn new() -> Map<A> { + Map { raw: RawMap::with_hasher(Default::default()) } + } - impl<A: ?Sized + Downcast> Map<A> { - /// Create an empty collection. - #[inline] - pub fn new() -> Map<A> { - Map { - raw: RawMap::with_hasher(Default::default()), - } - } + /// Returns a reference to the value stored in the collection for the type `T`, + /// if it exists. + #[inline] + pub fn get<T: IntoBox<A>>(&self) -> Option<&T> { + self.raw.get(&TypeId::of::<T>()).map(|any| unsafe { any.downcast_ref_unchecked::<T>() }) + } - /// Returns a reference to the value stored in the collection for the type `T`, - /// if it exists. - #[inline] - pub fn get<T: IntoBox<A>>(&self) -> Option<&T> { - self.raw.get(&TypeId::of::<T>()) - .map(|any| unsafe { any.downcast_ref_unchecked::<T>() }) + /// Gets the entry for the given type in the collection for in-place manipulation + #[inline] + pub fn entry<T: IntoBox<A>>(&mut self) -> Entry<A, T> { + match self.raw.entry(TypeId::of::<T>()) { + hash_map::Entry::Occupied(e) => { + Entry::Occupied(OccupiedEntry { inner: e, type_: PhantomData }) } - - /// Gets the entry for the given type in the collection for in-place manipulation - #[inline] - pub fn entry<T: IntoBox<A>>(&mut self) -> Entry<A, T> { - match self.raw.entry(TypeId::of::<T>()) { - hash_map::Entry::Occupied(e) => Entry::Occupied(OccupiedEntry { - inner: e, - type_: PhantomData, - }), - hash_map::Entry::Vacant(e) => Entry::Vacant(VacantEntry { - inner: e, - type_: PhantomData, - }), - } + hash_map::Entry::Vacant(e) => { + Entry::Vacant(VacantEntry { inner: e, type_: PhantomData }) } - - } - - /// A view into a single occupied location in an `Map`. - pub struct OccupiedEntry<'a, A: ?Sized + Downcast, V: 'a> { - inner: hash_map::OccupiedEntry<'a, TypeId, Box<A>, $($entry_generics)?>, - type_: PhantomData<V>, - } - - /// A view into a single empty location in an `Map`. - pub struct VacantEntry<'a, A: ?Sized + Downcast, V: 'a> { - inner: hash_map::VacantEntry<'a, TypeId, Box<A>, $($entry_generics)?>, - type_: PhantomData<V>, } + } +} - /// A view into a single location in an `Map`, which may be vacant or occupied. - pub enum Entry<'a, A: ?Sized + Downcast, V: 'a> { - /// An occupied Entry - Occupied(OccupiedEntry<'a, A, V>), - /// A vacant Entry - Vacant(VacantEntry<'a, A, V>), - } +/// A view into a single occupied location in an `Map`. +pub struct OccupiedEntry<'a, A: ?Sized + Downcast, V: 'a> { + inner: hash_map::OccupiedEntry<'a, TypeId, Box<A>>, + type_: PhantomData<V>, +} - impl<'a, A: ?Sized + Downcast, V: IntoBox<A>> Entry<'a, A, V> { +/// A view into a single empty location in an `Map`. +pub struct VacantEntry<'a, A: ?Sized + Downcast, V: 'a> { + inner: hash_map::VacantEntry<'a, TypeId, Box<A>>, + type_: PhantomData<V>, +} +/// A view into a single location in an `Map`, which may be vacant or occupied. +pub enum Entry<'a, A: ?Sized + Downcast, V: 'a> { + /// An occupied Entry + Occupied(OccupiedEntry<'a, A, V>), + /// A vacant Entry + Vacant(VacantEntry<'a, A, V>), +} - /// 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. - #[inline] - pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V { - match self { - Entry::Occupied(inner) => inner.into_mut(), - Entry::Vacant(inner) => inner.insert(default()), - } - } +impl<'a, A: ?Sized + Downcast, V: IntoBox<A>> Entry<'a, A, V> { + /// 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. + #[inline] + pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V { + match self { + Entry::Occupied(inner) => inner.into_mut(), + Entry::Vacant(inner) => inner.insert(default()), } + } +} - impl<'a, A: ?Sized + Downcast, V: IntoBox<A>> OccupiedEntry<'a, A, V> { - /// Converts the OccupiedEntry into a mutable reference to the value in the entry - /// with a lifetime bound to the collection itself - #[inline] - pub fn into_mut(self) -> &'a mut V { - unsafe { self.inner.into_mut().downcast_mut_unchecked() } - } - } +impl<'a, A: ?Sized + Downcast, V: IntoBox<A>> OccupiedEntry<'a, A, V> { + /// Converts the OccupiedEntry into a mutable reference to the value in the entry + /// with a lifetime bound to the collection itself + #[inline] + pub fn into_mut(self) -> &'a mut V { + unsafe { self.inner.into_mut().downcast_mut_unchecked() } + } +} - impl<'a, A: ?Sized + Downcast, V: IntoBox<A>> VacantEntry<'a, A, V> { - /// Sets the value of the entry with the VacantEntry's key, - /// and returns a mutable reference to it - #[inline] - pub fn insert(self, value: V) -> &'a mut V { - unsafe { self.inner.insert(value.into_box()).downcast_mut_unchecked() } - } - } +impl<'a, A: ?Sized + Downcast, V: IntoBox<A>> VacantEntry<'a, A, V> { + /// Sets the value of the entry with the VacantEntry's key, + /// and returns a mutable reference to it + #[inline] + pub fn insert(self, value: V) -> &'a mut V { + unsafe { self.inner.insert(value.into_box()).downcast_mut_unchecked() } + } +} - #[cfg(test)] - mod tests { - use crate::CloneAny; - use super::*; +#[cfg(test)] +mod tests { + use super::*; + use crate::CloneAny; - #[derive(Clone, Debug, PartialEq)] struct A(i32); - #[derive(Clone, Debug, PartialEq)] struct B(i32); - #[derive(Clone, Debug, PartialEq)] struct C(i32); - #[derive(Clone, Debug, PartialEq)] struct D(i32); - #[derive(Clone, Debug, PartialEq)] struct E(i32); - #[derive(Clone, Debug, PartialEq)] struct F(i32); - #[derive(Clone, Debug, PartialEq)] struct J(i32); + #[derive(Clone, Debug, PartialEq)] + struct A(i32); + #[derive(Clone, Debug, PartialEq)] + struct B(i32); + #[derive(Clone, Debug, PartialEq)] + struct C(i32); + #[derive(Clone, Debug, PartialEq)] + struct D(i32); + #[derive(Clone, Debug, PartialEq)] + struct E(i32); + #[derive(Clone, Debug, PartialEq)] + struct F(i32); + #[derive(Clone, Debug, PartialEq)] + struct J(i32); - #[test] - fn test_varieties() { - fn assert_send<T: Send>() { } - fn assert_sync<T: Sync>() { } - fn assert_debug<T: ::core::fmt::Debug>() { } - assert_send::<Map<dyn Any + Send>>(); - assert_send::<Map<dyn Any + Send + Sync>>(); - assert_sync::<Map<dyn Any + Send + Sync>>(); - assert_debug::<Map<dyn Any>>(); - assert_debug::<Map<dyn Any + Send>>(); - assert_debug::<Map<dyn Any + Send + Sync>>(); - assert_send::<Map<dyn CloneAny + Send>>(); - assert_send::<Map<dyn CloneAny + Send + Sync>>(); - assert_sync::<Map<dyn CloneAny + Send + Sync>>(); - assert_debug::<Map<dyn CloneAny>>(); - assert_debug::<Map<dyn CloneAny + Send>>(); - assert_debug::<Map<dyn CloneAny + Send + Sync>>(); - } - } - }; -} + #[test] + fn test_varieties() { + fn assert_send<T: Send>() {} + fn assert_sync<T: Sync>() {} + fn assert_debug<T: ::core::fmt::Debug>() {} + assert_send::<Map<dyn Any + Send>>(); + assert_send::<Map<dyn Any + Send + Sync>>(); + assert_sync::<Map<dyn Any + Send + Sync>>(); + assert_debug::<Map<dyn Any>>(); + assert_debug::<Map<dyn Any + Send>>(); + assert_debug::<Map<dyn Any + Send + Sync>>(); + assert_send::<Map<dyn CloneAny + Send>>(); + assert_send::<Map<dyn CloneAny + Send + Sync>>(); + assert_sync::<Map<dyn CloneAny + Send + Sync>>(); + assert_debug::<Map<dyn CloneAny>>(); + assert_debug::<Map<dyn CloneAny + Send>>(); + assert_debug::<Map<dyn CloneAny + Send + Sync>>(); + } -#[test] -fn type_id_hasher() { - use core::any::TypeId; - use core::hash::Hash; - fn verify_hashing_with(type_id: TypeId) { - let mut hasher = TypeIdHasher::default(); - type_id.hash(&mut hasher); - // SAFETY: u64 is valid for all bit patterns. - let _ = hasher.finish(); + #[test] + fn type_id_hasher() { + use core::any::TypeId; + use core::hash::Hash; + fn verify_hashing_with(type_id: TypeId) { + let mut hasher = TypeIdHasher::default(); + type_id.hash(&mut hasher); + // SAFETY: u64 is valid for all bit patterns. + let _ = hasher.finish(); + } + // Pick a variety of types, just to demonstrate it’s all sane. Normal, zero-sized, unsized, &c. + verify_hashing_with(TypeId::of::<usize>()); + verify_hashing_with(TypeId::of::<()>()); + verify_hashing_with(TypeId::of::<str>()); + verify_hashing_with(TypeId::of::<&str>()); + verify_hashing_with(TypeId::of::<Vec<u8>>()); } - // Pick a variety of types, just to demonstrate it’s all sane. Normal, zero-sized, unsized, &c. - verify_hashing_with(TypeId::of::<usize>()); - verify_hashing_with(TypeId::of::<()>()); - verify_hashing_with(TypeId::of::<str>()); - verify_hashing_with(TypeId::of::<&str>()); - verify_hashing_with(TypeId::of::<Vec<u8>>()); } - -#[cfg(feature = "std")] -everything!("let mut data = anymap::AnyMap::new();", std::collections); |
