diff --git a/.travis.yml b/.travis.yml index 64c99e0..0b7902c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,12 +4,6 @@ env: - secure: nR+DJRUQ9v03nNZMpMu1tGKLKBAqdQsTIAr8ffdl+DUEh3b2jvQ+vLLNFLPjsloqhoOXo7cWO7qVpiE4ZOq2lNDURQjdiZGFjh/Y5+xKy2BqFdV7qQ1JoBzsMyx28tQTYz0mtBsACiCYKKb+ddNX5hpwrsjp8cS7htZktA5kbiU= script: - if [[ "$(rustc --version)" =~ -(dev|nightly) ]]; then cargo test --features nightly; else ! cargo test --features nightly; fi - - if [[ "$(rustc --version)" =~ -(dev|nightly) ]]; then cargo test --features 'clone nightly'; else ! cargo test --features 'clone nightly'; fi - - if [[ "$(rustc --version)" =~ -(dev|nightly) ]]; then cargo test --features 'concurrent nightly'; else ! cargo test --features 'concurrent nightly'; fi - - if [[ "$(rustc --version)" =~ -(dev|nightly) ]]; then cargo test --features 'clone concurrent nightly'; else ! cargo test --features 'clone concurrent nightly'; fi - - cargo test --features clone - - cargo test --features concurrent - - cargo test --features 'clone concurrent' - cargo test - cargo doc after_script: diff --git a/Cargo.toml b/Cargo.toml index 85f18cb..2cd1601 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,4 @@ keywords = ["container", "data-structure", "map"] license = "MIT/Apache-2.0" [features] -clone = [] -concurrent = [] nightly = [] diff --git a/README.md b/README.md index a498edd..77b147b 100644 --- a/README.md +++ b/README.md @@ -18,14 +18,6 @@ Instructions Cargo all the way: it is `anymap` on crates.io. -There are a couple of optional features on the `anymap` crate: - -- `clone`: if enabled, your `AnyMap` will require contained types to implement `Clone` and will itself satisfy `Clone`. - -- `concurrent`: if enabled, your `AnyMap` will require contained types to satisfy `Send` and `Sync` and will itself satisfy `Send` and `Sync`. - -These can be combined if desired. - For users of the nightly instead of the beta of rustc there are a couple of things behind the `nightly` feature like a `drain` method on the `RawAnyMap` and a more efficient hashing technique which makes lookup in the map a tad faster. Author diff --git a/src/any.rs b/src/any.rs new file mode 100644 index 0000000..45ad5cc --- /dev/null +++ b/src/any.rs @@ -0,0 +1,167 @@ +//! The different types of `Any` for use in a map. +//! +//! This stuff is all based on `std::any`, but goes a little further, with `CloneAny` being a +//! cloneable `Any` and with the `Send` and `Sync` bounds possible on both `Any` and `CloneAny`. + +use std::mem; +use std::fmt; +use std::any::Any as StdAny; + +#[doc(hidden)] +pub trait CloneToAny { + /// Clone `self` into a new `Box` object. + fn clone_to_any(&self) -> Box; + + /// Clone `self` into a new `Box` object. + fn clone_to_any_send(&self) -> Box where Self: Send; + + /// Clone `self` into a new `Box` object. + fn clone_to_any_sync(&self) -> Box where Self: Sync; + + /// Clone `self` into a new `Box` object. + fn clone_to_any_send_sync(&self) -> Box where Self: Send + Sync; +} + +impl CloneToAny for T { + fn clone_to_any(&self) -> Box { + Box::new(self.clone()) + } + + fn clone_to_any_send(&self) -> Box where Self: Send { + Box::new(self.clone()) + } + + fn clone_to_any_sync(&self) -> Box where Self: Sync { + Box::new(self.clone()) + } + + fn clone_to_any_send_sync(&self) -> Box where Self: Send + Sync { + Box::new(self.clone()) + } +} + +macro_rules! define { + (CloneAny) => { + /// A type to emulate dynamic typing. + /// + /// Every type with no non-`'static` references implements `Any`. + define!(CloneAny remainder); + }; + (Any) => { + /// A type to emulate dynamic typing with cloning. + /// + /// Every type with no non-`'static` references that implements `Clone` implements `Any`. + define!(Any remainder); + }; + ($t:ident remainder) => { + /// See the [`std::any` documentation](https://doc.rust-lang.org/std/any/index.html) for + /// more details on `Any` in general. + /// + /// This trait is not `std::any::Any` but rather a type extending that for this library’s + /// purposes so that it can be combined with marker traits like + /// Send and + /// Sync. + /// + define!($t trait); + }; + (CloneAny trait) => { + /// See also [`Any`](trait.Any.html) for a version without the `Clone` requirement. + pub trait CloneAny: Any + CloneToAny { } + impl CloneAny for T { } + }; + (Any trait) => { + /// See also [`CloneAny`](trait.CloneAny.html) for a cloneable version of this trait. + pub trait Any: StdAny { } + impl Any for T { } + }; +} + +macro_rules! impl_clone { + ($t:ty, $method:ident) => { + impl Clone for Box<$t> { + fn clone(&self) -> Box<$t> { + (**self).$method() + } + } + } +} + +#[cfg(feature = "nightly")] +use std::raw::TraitObject; + +#[cfg(not(feature = "nightly"))] +#[repr(C)] +#[allow(raw_pointer_derive)] +#[derive(Copy, Clone)] +struct TraitObject { + pub data: *mut (), + pub vtable: *mut (), +} + +#[allow(missing_docs)] // Bogus warning (it’s not public outside the crate), ☹ +pub trait UncheckedAnyExt: Any { + unsafe fn downcast_ref_unchecked(&self) -> &T; + unsafe fn downcast_mut_unchecked(&mut self) -> &mut T; + unsafe fn downcast_unchecked(self: Box) -> Box; +} + +#[doc(hidden)] +/// A trait for the conversion of an object into a boxed trait object. +pub trait IntoBox: Any { + /// Convert self into the appropriate boxed form. + fn into_box(self) -> Box; +} + +macro_rules! implement { + ($base:ident, $(+ $bounds:ident)*) => { + impl<'a> fmt::Debug for &'a ($base $(+ $bounds)*) { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad(stringify!(&($base $(+ $bounds)*))) + } + } + + impl<'a> fmt::Debug for Box<$base $(+ $bounds)*> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad(stringify!(Box<$base $(+ $bounds)*>)) + } + } + + impl UncheckedAnyExt for $base $(+ $bounds)* { + unsafe fn downcast_ref_unchecked(&self) -> &T { + mem::transmute(mem::transmute::<_, TraitObject>(self).data) + } + + unsafe fn downcast_mut_unchecked(&mut self) -> &mut T { + mem::transmute(mem::transmute::<_, TraitObject>(self).data) + } + + unsafe fn downcast_unchecked(self: Box) -> Box { + mem::transmute(mem::transmute::<_, TraitObject>(self).data) + } + } + + impl IntoBox<$base $(+ $bounds)*> for T { + fn into_box(self) -> Box<$base $(+ $bounds)*> { + Box::new(self) + } + } + } +} + +define!(Any); +implement!(Any,); +implement!(Any, + Send); +implement!(Any, + Sync); +implement!(Any, + Send + Sync); +implement!(CloneAny,); +implement!(CloneAny, + Send); +implement!(CloneAny, + Sync); +implement!(CloneAny, + Send + Sync); + +define!(CloneAny); +impl_clone!(CloneAny, clone_to_any); +impl_clone!((CloneAny + Send), clone_to_any_send); +impl_clone!((CloneAny + Sync), clone_to_any_sync); +impl_clone!((CloneAny + Send + Sync), clone_to_any_send_sync); diff --git a/src/lib.rs b/src/lib.rs index d32af5f..8e83bab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,8 +10,8 @@ extern crate test; use std::any::TypeId; use std::marker::PhantomData; -use raw::{RawAnyMap, Any}; -use unchecked_any::UncheckedAnyExt; +use raw::RawMap; +use any::{UncheckedAnyExt, IntoBox, Any}; macro_rules! impl_common_methods { ( @@ -19,10 +19,10 @@ macro_rules! impl_common_methods { new() => $new:expr; with_capacity($with_capacity_arg:ident) => $with_capacity:expr; ) => { - impl $t { + impl $t { /// Create an empty collection. #[inline] - pub fn new() -> $t { + pub fn new() -> $t { $t { $field: $new, } @@ -30,7 +30,7 @@ macro_rules! impl_common_methods { /// Creates an empty collection with the given initial capacity. #[inline] - pub fn with_capacity($with_capacity_arg: usize) -> $t { + pub fn with_capacity($with_capacity_arg: usize) -> $t { $t { $field: $with_capacity, } @@ -83,12 +83,18 @@ macro_rules! impl_common_methods { } } -mod unchecked_any; +pub mod any; pub mod raw; /// 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 `anymap::any::Any`, but there are other choices: +/// +/// - If you want the entire map to be cloneable, use `CloneAny` instead of `Any`. +/// - You can add on `+ Send` and/or `+ Sync` (e.g. `Map`) to add those bounds. +/// /// ```rust /// # use anymap::AnyMap; /// let mut data = AnyMap::new(); @@ -112,27 +118,42 @@ pub mod raw; /// /// Values containing non-static references are not permitted. #[derive(Debug)] -#[cfg_attr(feature = "clone", derive(Clone))] -pub struct AnyMap { - raw: RawAnyMap, +pub struct Map { + raw: RawMap, } +// #[derive(Clone)] would want A to implement Clone, but in reality it’s only Box that can. +impl Clone for Map where Box: Clone { + fn clone(&self) -> Map { + Map { + raw: self.raw.clone(), + } + } +} + +/// The most common type of `Map`: just using `Any`. +/// +/// Why is this a separate type alias rather than a default value for `Map`? `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; + impl_common_methods! { - field: AnyMap.raw; - new() => RawAnyMap::new(); - with_capacity(capacity) => RawAnyMap::with_capacity(capacity); + field: Map.raw; + new() => RawMap::new(); + with_capacity(capacity) => RawMap::with_capacity(capacity); } -impl AnyMap { +impl Map { /// Returns a reference to the value stored in the collection for the type `T`, if it exists. - pub fn get(&self) -> Option<&T> { + pub fn get>(&self) -> Option<&T> { self.raw.get(&TypeId::of::()) .map(|any| unsafe { any.downcast_ref_unchecked::() }) } /// Returns a mutable reference to the value stored in the collection for the type `T`, /// if it exists. - pub fn get_mut(&mut self) -> Option<&mut T> { + pub fn get_mut>(&mut self) -> Option<&mut T> { self.raw.get_mut(&TypeId::of::()) .map(|any| unsafe { any.downcast_mut_unchecked::() }) } @@ -140,28 +161,28 @@ impl AnyMap { /// Sets the value stored in the collection for the type `T`. /// If the collection already had a value of type `T`, that value is returned. /// Otherwise, `None` is returned. - pub fn insert(&mut self, value: T) -> Option { + pub fn insert>(&mut self, value: T) -> Option { unsafe { - self.raw.insert(TypeId::of::(), Box::new(value)) + self.raw.insert(TypeId::of::(), value.into_box()) .map(|any| *any.downcast_unchecked::()) } } /// Removes the `T` value from the collection, /// returning it if there was one or `None` if there was not. - pub fn remove(&mut self) -> Option { + pub fn remove>(&mut self) -> Option { self.raw.remove(&TypeId::of::()) .map(|any| *unsafe { any.downcast_unchecked::() }) } /// Returns true if the collection contains a value of type `T`. #[inline] - pub fn contains(&self) -> bool { + pub fn contains>(&self) -> bool { self.raw.contains_key(&TypeId::of::()) } /// Gets the entry for the given type in the collection for in-place manipulation - pub fn entry(&mut self) -> Entry { + pub fn entry>(&mut self) -> Entry { match self.raw.entry(TypeId::of::()) { raw::Entry::Occupied(e) => Entry::Occupied(OccupiedEntry { inner: e, @@ -175,45 +196,45 @@ impl AnyMap { } } -impl AsRef for AnyMap { - fn as_ref(&self) -> &RawAnyMap { +impl AsRef> for Map { + fn as_ref(&self) -> &RawMap { &self.raw } } -impl AsMut for AnyMap { - fn as_mut(&mut self) -> &mut RawAnyMap { +impl AsMut> for Map { + fn as_mut(&mut self) -> &mut RawMap { &mut self.raw } } -impl Into for AnyMap { - fn into(self) -> RawAnyMap { +impl Into> for Map { + fn into(self) -> RawMap { self.raw } } -/// A view into a single occupied location in an `AnyMap`. -pub struct OccupiedEntry<'a, V: 'a> { - inner: raw::OccupiedEntry<'a>, +/// A view into a single occupied location in an `Map`. +pub struct OccupiedEntry<'a, A: ?Sized + UncheckedAnyExt, V: 'a> { + inner: raw::OccupiedEntry<'a, A>, type_: PhantomData, } -/// A view into a single empty location in an `AnyMap`. -pub struct VacantEntry<'a, V: 'a> { - inner: raw::VacantEntry<'a>, +/// A view into a single empty location in an `Map`. +pub struct VacantEntry<'a, A: ?Sized + UncheckedAnyExt, V: 'a> { + inner: raw::VacantEntry<'a, A>, type_: PhantomData, } -/// A view into a single location in an `AnyMap`, which may be vacant or occupied. -pub enum Entry<'a, V: 'a> { +/// A view into a single location in an `Map`, which may be vacant or occupied. +pub enum Entry<'a, A: ?Sized + UncheckedAnyExt, V: 'a> { /// An occupied Entry - Occupied(OccupiedEntry<'a, V>), + Occupied(OccupiedEntry<'a, A, V>), /// A vacant Entry - Vacant(VacantEntry<'a, V>), + Vacant(VacantEntry<'a, A, V>), } -impl<'a, V: Any + Clone> Entry<'a, V> { +impl<'a, A: ?Sized + UncheckedAnyExt, V: IntoBox + Clone> Entry<'a, A, V> { /// 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: V) -> &'a mut V { @@ -233,7 +254,7 @@ impl<'a, V: Any + Clone> Entry<'a, V> { } } -impl<'a, V: Any> OccupiedEntry<'a, V> { +impl<'a, A: ?Sized + UncheckedAnyExt, V: IntoBox> OccupiedEntry<'a, A, V> { /// Gets a reference to the value in the entry pub fn get(&self) -> &V { unsafe { self.inner.get().downcast_ref_unchecked() } @@ -252,7 +273,7 @@ impl<'a, V: Any> OccupiedEntry<'a, V> { /// Sets the value of the entry, and returns the entry's old value pub fn insert(&mut self, value: V) -> V { - unsafe { *self.inner.insert(Box::new(value)).downcast_unchecked() } + unsafe { *self.inner.insert(value.into_box()).downcast_unchecked() } } /// Takes the value out of the entry, and returns it @@ -261,11 +282,11 @@ impl<'a, V: Any> OccupiedEntry<'a, V> { } } -impl<'a, V: Any> VacantEntry<'a, V> { +impl<'a, A: ?Sized + UncheckedAnyExt, V: IntoBox> VacantEntry<'a, A, V> { /// Sets the value of the entry with the VacantEntry's key, /// and returns a mutable reference to it pub fn insert(self, value: V) -> &'a mut V { - unsafe { self.inner.insert(Box::new(value)).downcast_mut_unchecked() } + unsafe { self.inner.insert(value.into_box()).downcast_mut_unchecked() } } } @@ -303,7 +324,8 @@ fn bench_get_present(b: &mut ::test::Bencher) { #[cfg(test)] mod tests { - use {AnyMap, Entry}; + use {Map, AnyMap, Entry}; + use any::{Any, CloneAny}; #[derive(Clone, Debug, PartialEq)] struct A(i32); #[derive(Clone, Debug, PartialEq)] struct B(i32); @@ -380,10 +402,9 @@ mod tests { assert_eq!(map.len(), 7); } - #[cfg(feature = "clone")] #[test] fn test_clone() { - let mut map = AnyMap::new(); + let mut map: Map = Map::new(); let _ = map.insert(A(1)); let _ = map.insert(B(2)); let _ = map.insert(D(3)); @@ -401,10 +422,22 @@ mod tests { assert_eq!(map2.get::(), Some(&J(6))); } - #[cfg(feature = "concurrent")] #[test] - fn test_concurrent() { - fn assert_concurrent() { } - assert_concurrent::(); + fn test_varieties() { + fn assert_send() { } + fn assert_sync() { } + fn assert_clone() { } + assert_send::>(); + assert_send::>(); + assert_sync::>(); + assert_sync::>(); + assert_send::>(); + assert_send::>(); + assert_sync::>(); + assert_sync::>(); + assert_clone::>(); + assert_clone::>(); + assert_clone::>(); + assert_clone::>(); } } diff --git a/src/raw/mod.rs b/src/raw.rs similarity index 63% rename from src/raw/mod.rs rename to src/raw.rs index 1ae1a6c..6439771 100644 --- a/src/raw/mod.rs +++ b/src/raw.rs @@ -1,6 +1,6 @@ -//! The raw form of an AnyMap, allowing untyped access. +//! The raw form of a `Map`, allowing untyped access. //! -//! All relevant details are in the `RawAnyMap` struct. +//! All relevant details are in the `RawMap` struct. use std::any::TypeId; use std::borrow::Borrow; @@ -18,16 +18,14 @@ use std::ops::{Index, IndexMut}; #[cfg(feature = "nightly")] use std::ptr; -pub use self::any::Any; - -mod any; +use any::{Any, UncheckedAnyExt}; #[cfg(feature = "nightly")] struct TypeIdHasher { value: u64, } -#[cfg_attr(feature = "clone", derive(Clone))] +#[derive(Clone)] #[cfg(feature = "nightly")] struct TypeIdState; @@ -56,105 +54,113 @@ impl Hasher for TypeIdHasher { } -/// The raw, underlying form of an AnyMap. +/// The raw, underlying form of a `Map`. /// /// At its essence, this is a wrapper around `HashMap>`, with the portions that /// would be memory-unsafe removed or marked unsafe. Normal people are expected to use the safe -/// `AnyMap` interface instead, but there is the occasional use for this such as iteration over the -/// contents of an `AnyMap`. However, because you will then be dealing with `Any` trait objects, it +/// `Map` interface instead, but there is the occasional use for this such as iteration over the +/// contents of an `Map`. However, because you will then be dealing with `Any` trait objects, it /// doesn’t tend to be so very useful. Still, if you need it, it’s here. #[derive(Debug)] -#[cfg_attr(feature = "clone", derive(Clone))] -pub struct RawAnyMap { +pub struct RawMap { #[cfg(feature = "nightly")] - inner: HashMap, TypeIdState>, + inner: HashMap, TypeIdState>, #[cfg(not(feature = "nightly"))] - inner: HashMap>, + inner: HashMap>, } -impl Default for RawAnyMap { - fn default() -> RawAnyMap { - RawAnyMap::new() +// #[derive(Clone)] would want A to implement Clone, but in reality it’s only Box that can. +impl Clone for RawMap where Box: Clone { + fn clone(&self) -> RawMap { + RawMap { + inner: self.inner.clone(), + } + } +} + +impl Default for RawMap { + fn default() -> RawMap { + RawMap::new() } } #[cfg(feature = "nightly")] impl_common_methods! { - field: RawAnyMap.inner; + field: RawMap.inner; new() => HashMap::with_hash_state(TypeIdState); with_capacity(capacity) => HashMap::with_capacity_and_hash_state(capacity, TypeIdState); } #[cfg(not(feature = "nightly"))] impl_common_methods! { - field: RawAnyMap.inner; + field: RawMap.inner; new() => HashMap::new(); with_capacity(capacity) => HashMap::with_capacity(capacity); } -/// RawAnyMap iterator. +/// RawMap iterator. #[derive(Clone)] -pub struct Iter<'a> { - inner: hash_map::Iter<'a, TypeId, Box>, +pub struct Iter<'a, A: ?Sized + UncheckedAnyExt> { + inner: hash_map::Iter<'a, TypeId, Box>, } -impl<'a> Iterator for Iter<'a> { - type Item = &'a Any; - #[inline] fn next(&mut self) -> Option<&'a Any> { self.inner.next().map(|x| &**x.1) } +impl<'a, A: ?Sized + UncheckedAnyExt> Iterator for Iter<'a, A> { + type Item = &'a A; + #[inline] fn next(&mut self) -> Option<&'a A> { self.inner.next().map(|x| &**x.1) } #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } -impl<'a> ExactSizeIterator for Iter<'a> { +impl<'a, A: ?Sized + UncheckedAnyExt> ExactSizeIterator for Iter<'a, A> { #[inline] fn len(&self) -> usize { self.inner.len() } } -/// RawAnyMap mutable iterator. -pub struct IterMut<'a> { - inner: hash_map::IterMut<'a, TypeId, Box>, +/// RawMap mutable iterator. +pub struct IterMut<'a, A: ?Sized + UncheckedAnyExt> { + inner: hash_map::IterMut<'a, TypeId, Box>, } -impl<'a> Iterator for IterMut<'a> { - type Item = &'a mut Any; - #[inline] fn next(&mut self) -> Option<&'a mut Any> { self.inner.next().map(|x| &mut **x.1) } +impl<'a, A: ?Sized + UncheckedAnyExt> Iterator for IterMut<'a, A> { + type Item = &'a mut A; + #[inline] fn next(&mut self) -> Option<&'a mut A> { self.inner.next().map(|x| &mut **x.1) } #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } -impl<'a> ExactSizeIterator for IterMut<'a> { +impl<'a, A: ?Sized + UncheckedAnyExt> ExactSizeIterator for IterMut<'a, A> { #[inline] fn len(&self) -> usize { self.inner.len() } } -/// RawAnyMap move iterator. -pub struct IntoIter { - inner: hash_map::IntoIter>, +/// RawMap move iterator. +pub struct IntoIter { + inner: hash_map::IntoIter>, } -impl Iterator for IntoIter { - type Item = Box; - #[inline] fn next(&mut self) -> Option> { self.inner.next().map(|x| x.1) } +impl Iterator for IntoIter { + type Item = Box; + #[inline] fn next(&mut self) -> Option> { self.inner.next().map(|x| x.1) } #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } -impl ExactSizeIterator for IntoIter { +impl ExactSizeIterator for IntoIter { #[inline] fn len(&self) -> usize { self.inner.len() } } -/// RawAnyMap drain iterator. +/// RawMap drain iterator. #[cfg(feature = "nightly")] -pub struct Drain<'a> { - inner: hash_map::Drain<'a, TypeId, Box>, +pub struct Drain<'a, A: ?Sized + UncheckedAnyExt> { + inner: hash_map::Drain<'a, TypeId, Box>, } #[cfg(feature = "nightly")] -impl<'a> Iterator for Drain<'a> { - type Item = Box; - #[inline] fn next(&mut self) -> Option> { self.inner.next().map(|x| x.1) } +impl<'a, A: ?Sized + UncheckedAnyExt> Iterator for Drain<'a, A> { + type Item = Box; + #[inline] fn next(&mut self) -> Option> { self.inner.next().map(|x| x.1) } #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } #[cfg(feature = "nightly")] -impl<'a> ExactSizeIterator for Drain<'a> { +impl<'a, A: ?Sized + UncheckedAnyExt> ExactSizeIterator for Drain<'a, A> { #[inline] fn len(&self) -> usize { self.inner.len() } } -impl RawAnyMap { +impl RawMap { /// An iterator visiting all entries in arbitrary order. /// /// Iterator element type is `&Any`. #[inline] - pub fn iter(&self) -> Iter { + pub fn iter(&self) -> Iter { Iter { inner: self.inner.iter(), } @@ -164,24 +170,12 @@ impl RawAnyMap { /// /// Iterator element type is `&mut Any`. #[inline] - pub fn iter_mut(&mut self) -> IterMut { + pub fn iter_mut(&mut self) -> IterMut { IterMut { inner: self.inner.iter_mut(), } } - /// Creates a consuming iterator, that is, one that moves each item - /// out of the map in arbitrary order. The map cannot be used after - /// calling this. - /// - /// Iterator element type is `Box`. - #[inline] - pub fn into_iter(self) -> IntoIter { - IntoIter { - inner: self.inner.into_iter(), - } - } - /// Clears the map, returning all items as an iterator. /// /// Iterator element type is `Box`. @@ -189,14 +183,14 @@ impl RawAnyMap { /// Keeps the allocated memory for reuse. #[inline] #[cfg(feature = "nightly")] - pub fn drain(&mut self) -> Drain { + pub fn drain(&mut self) -> Drain { Drain { inner: self.inner.drain(), } } /// Gets the entry for the given type in the collection for in-place manipulation. - pub fn entry(&mut self, key: TypeId) -> Entry { + pub fn entry(&mut self, key: TypeId) -> Entry { match self.inner.entry(key) { hash_map::Entry::Occupied(e) => Entry::Occupied(OccupiedEntry { inner: e, @@ -211,7 +205,7 @@ impl RawAnyMap { /// /// The key may be any borrowed form of the map's key type, but `Hash` and `Eq` on the borrowed /// form *must* match those for the key type. - pub fn get(&self, k: &Q) -> Option<&Any> + pub fn get(&self, k: &Q) -> Option<&A> where TypeId: Borrow, Q: Hash + Eq { self.inner.get(k).map(|x| &**x) } @@ -229,7 +223,7 @@ impl RawAnyMap { /// /// The key may be any borrowed form of the map's key type, but `Hash` and `Eq` on the borrowed /// form *must* match those for the key type. - pub fn get_mut(&mut self, k: &Q) -> Option<&mut Any> + pub fn get_mut(&mut self, k: &Q) -> Option<&mut A> where TypeId: Borrow, Q: Hash + Eq { self.inner.get_mut(k).map(|x| &mut **x) } @@ -239,7 +233,7 @@ impl RawAnyMap { /// /// It is the caller’s responsibility to ensure that the key corresponds with the type ID of /// the value. If they do not, memory safety may be violated. - pub unsafe fn insert(&mut self, key: TypeId, value: Box) -> Option> { + pub unsafe fn insert(&mut self, key: TypeId, value: Box) -> Option> { self.inner.insert(key, value) } @@ -248,61 +242,63 @@ impl RawAnyMap { /// /// The key may be any borrowed form of the map's key type, but `Hash` and `Eq` on the borrowed /// form *must* match those for the key type. - pub fn remove(&mut self, k: &Q) -> Option> + pub fn remove(&mut self, k: &Q) -> Option> where TypeId: Borrow, Q: Hash + Eq { self.inner.remove(k) } } -impl Index for RawAnyMap where TypeId: Borrow, Q: Eq + Hash { - type Output = Any; +impl Index for RawMap where TypeId: Borrow, Q: Eq + Hash { + type Output = A; - fn index<'a>(&'a self, index: Q) -> &'a Any { + fn index<'a>(&'a self, index: Q) -> &'a A { self.get(&index).expect("no entry found for key") } } -impl IndexMut for RawAnyMap where TypeId: Borrow, Q: Eq + Hash { - fn index_mut<'a>(&'a mut self, index: Q) -> &'a mut Any { +impl IndexMut for RawMap where TypeId: Borrow, Q: Eq + Hash { + fn index_mut<'a>(&'a mut self, index: Q) -> &'a mut A { self.get_mut(&index).expect("no entry found for key") } } -impl IntoIterator for RawAnyMap { - type Item = Box; - type IntoIter = IntoIter; +impl IntoIterator for RawMap { + type Item = Box; + type IntoIter = IntoIter; - fn into_iter(self) -> IntoIter { - self.into_iter() + fn into_iter(self) -> IntoIter { + IntoIter { + inner: self.inner.into_iter(), + } } } -/// A view into a single occupied location in a `RawAnyMap`. -pub struct OccupiedEntry<'a> { - inner: hash_map::OccupiedEntry<'a, TypeId, Box>, +/// A view into a single occupied location in a `RawMap`. +pub struct OccupiedEntry<'a, A: ?Sized + UncheckedAnyExt> { + inner: hash_map::OccupiedEntry<'a, TypeId, Box>, } -/// A view into a single empty location in a `RawAnyMap`. -pub struct VacantEntry<'a> { - inner: hash_map::VacantEntry<'a, TypeId, Box>, +/// A view into a single empty location in a `RawMap`. +pub struct VacantEntry<'a, A: ?Sized + UncheckedAnyExt> { + inner: hash_map::VacantEntry<'a, TypeId, Box>, } -/// A view into a single location in an AnyMap, which may be vacant or occupied. -pub enum Entry<'a> { +/// A view into a single location in a `RawMap`, which may be vacant or occupied. +pub enum Entry<'a, A: ?Sized + UncheckedAnyExt> { /// An occupied Entry - Occupied(OccupiedEntry<'a>), + Occupied(OccupiedEntry<'a, A>), /// A vacant Entry - Vacant(VacantEntry<'a>), + Vacant(VacantEntry<'a, A>), } -impl<'a> Entry<'a> { +impl<'a, A: ?Sized + UncheckedAnyExt> Entry<'a, A> { /// Ensures a value is in the entry by inserting the default if empty, and returns /// a mutable reference to the value in the entry. /// /// It is the caller’s responsibility to ensure that the key of the entry corresponds with /// the type ID of `value`. If they do not, memory safety may be violated. - pub unsafe fn or_insert(self, default: Box) -> &'a mut Any { + pub unsafe fn or_insert(self, default: Box) -> &'a mut A { match self { Entry::Occupied(inner) => inner.into_mut(), Entry::Vacant(inner) => inner.insert(default), @@ -314,7 +310,7 @@ impl<'a> Entry<'a> { /// /// It is the caller’s responsibility to ensure that the key of the entry corresponds with /// the type ID of `value`. If they do not, memory safety may be violated. - pub unsafe fn or_insert_with Box>(self, default: F) -> &'a mut Any { + pub unsafe fn or_insert_with Box>(self, default: F) -> &'a mut A { match self { Entry::Occupied(inner) => inner.into_mut(), Entry::Vacant(inner) => inner.insert(default()), @@ -322,20 +318,20 @@ impl<'a> Entry<'a> { } } -impl<'a> OccupiedEntry<'a> { +impl<'a, A: ?Sized + UncheckedAnyExt> OccupiedEntry<'a, A> { /// Gets a reference to the value in the entry. - pub fn get(&self) -> &Any { + pub fn get(&self) -> &A { &**self.inner.get() } /// Gets a mutable reference to the value in the entry. - pub fn get_mut(&mut self) -> &mut Any { + pub fn get_mut(&mut self) -> &mut A { &mut **self.inner.get_mut() } /// Converts the OccupiedEntry into a mutable reference to the value in the entry /// with a lifetime bound to the collection itself. - pub fn into_mut(self) -> &'a mut Any { + pub fn into_mut(self) -> &'a mut A { &mut **self.inner.into_mut() } @@ -343,23 +339,23 @@ impl<'a> OccupiedEntry<'a> { /// /// It is the caller’s responsibility to ensure that the key of the entry corresponds with /// the type ID of `value`. If they do not, memory safety may be violated. - pub unsafe fn insert(&mut self, value: Box) -> Box { + pub unsafe fn insert(&mut self, value: Box) -> Box { self.inner.insert(value) } /// Takes the value out of the entry, and returns it. - pub fn remove(self) -> Box { + pub fn remove(self) -> Box { self.inner.remove() } } -impl<'a> VacantEntry<'a> { +impl<'a, A: ?Sized + UncheckedAnyExt> VacantEntry<'a, A> { /// Sets the value of the entry with the VacantEntry's key, /// and returns a mutable reference to it /// /// It is the caller’s responsibility to ensure that the key of the entry corresponds with /// the type ID of `value`. If they do not, memory safety may be violated. - pub unsafe fn insert(self, value: Box) -> &'a mut Any { + pub unsafe fn insert(self, value: Box) -> &'a mut A { &mut **self.inner.insert(value) } } diff --git a/src/raw/any.rs b/src/raw/any.rs deleted file mode 100644 index d908040..0000000 --- a/src/raw/any.rs +++ /dev/null @@ -1,105 +0,0 @@ -use std::fmt; -use std::any::Any as StdAny; - -#[cfg(feature = "clone")] -#[doc(hidden)] -pub trait CloneToAny { - /// Clone `self` into a new `Box` object. - fn clone_to_any(&self) -> Box; -} - -#[cfg(feature = "clone")] -impl CloneToAny for T { - fn clone_to_any(&self) -> Box { - Box::new(self.clone()) - } -} - -macro_rules! define_any { - (#[$m:meta] $t:item $i:item) => { - /// A type to emulate dynamic typing. - /// - /// Every suitable type with no non-`'static` references implements `Any`. See the - /// [`std::any` documentation](https://doc.rust-lang.org/std/any/index.html) for more - /// details on `Any` in general. - /// - /// This trait is not `std::any::Any` but rather a type extending that for this library’s - /// purposes; most specifically, there are a couple of Cargo features that can be enabled - /// which will alter the constraints of what comprises a suitable type: - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - #[cfg_attr(feature = "clone", doc = " ")] - #[cfg_attr(not(feature = "clone"), doc = " ")] - /// - /// - /// - /// - #[cfg_attr(feature = "concurrent", doc = " ")] - #[cfg_attr(not(feature = "concurrent"), doc = " ")] - /// - /// - ///
Feature nameAdditional boundsEnabled in these docs?
cloneCloneYesNo
concurrentSend + SyncYesNo
- #[$m] $t - #[$m] $i - } -} - -define_any! { - #[cfg(all(not(feature = "clone"), not(feature = "concurrent")))] - pub trait Any: StdAny { } - impl Any for T { } -} - -define_any! { - #[cfg(all(feature = "clone", not(feature = "concurrent")))] - pub trait Any: StdAny + CloneToAny { } - impl Any for T { } -} - -define_any! { - #[cfg(all(not(feature = "clone"), feature = "concurrent"))] - pub trait Any: StdAny + Send + Sync { } - impl Any for T { } -} - -define_any! { - #[cfg(all(feature = "clone", feature = "concurrent"))] - pub trait Any: StdAny + CloneToAny + Send + Sync { } - impl Any for T { } -} - -#[cfg(feature = "clone")] -impl Clone for Box { - fn clone(&self) -> Box { - (**self).clone_to_any() - } -} - -impl<'a> fmt::Debug for &'a Any { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("&Any") - } -} - -impl<'a> fmt::Debug for Box { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("Box") - } -} diff --git a/src/unchecked_any.rs b/src/unchecked_any.rs deleted file mode 100644 index 52dee67..0000000 --- a/src/unchecked_any.rs +++ /dev/null @@ -1,34 +0,0 @@ -use raw::Any; -use std::mem; -#[cfg(feature = "nightly")] -use std::raw::TraitObject; - -#[cfg(not(feature = "nightly"))] -#[repr(C)] -#[allow(raw_pointer_derive)] -#[derive(Copy, Clone)] -struct TraitObject { - pub data: *mut (), - pub vtable: *mut (), -} - -#[allow(missing_docs)] // Bogus warning (it’s not public outside the crate), ☹ -pub trait UncheckedAnyExt { - unsafe fn downcast_ref_unchecked(&self) -> &T; - unsafe fn downcast_mut_unchecked(&mut self) -> &mut T; - unsafe fn downcast_unchecked(self: Box) -> Box; -} - -impl UncheckedAnyExt for Any { - unsafe fn downcast_ref_unchecked(&self) -> &T { - mem::transmute(mem::transmute::<_, TraitObject>(self).data) - } - - unsafe fn downcast_mut_unchecked(&mut self) -> &mut T { - mem::transmute(mem::transmute::<_, TraitObject>(self).data) - } - - unsafe fn downcast_unchecked(self: Box) -> Box { - mem::transmute(mem::transmute::<_, TraitObject>(self).data) - } -}