-/// A map containing zero or one values for any given type and allowing convenient,
-/// type-safe access to those values.
-///
-/// ```rust
-/// # use anymap::AnyMap;
-/// let mut data = AnyMap::new();
-/// assert_eq!(data.get(), None::<&int>);
-/// data.insert(42i);
-/// assert_eq!(data.get(), Some(&42i));
-/// data.remove::<int>();
-/// assert_eq!(data.get::<int>(), None);
-///
-/// #[deriving(PartialEq, Show)]
-/// struct Foo {
-/// str: String,
-/// }
-///
-/// assert_eq!(data.get::<Foo>(), None);
-/// data.insert(Foo { str: "foo".to_string() });
-/// assert_eq!(data.get(), Some(&Foo { str: "foo".to_string() }));
-/// data.get_mut::<Foo>().map(|foo| foo.str.push('t'));
-/// assert_eq!(data.get::<Foo>().unwrap().str.as_slice(), "foot");
-/// ```
-///
-/// Values containing non-static references are not permitted.
-pub struct AnyMap {
- data: HashMap<TypeId, Box<Any + 'static>, TypeIdHasher>,
+ /// 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.
+ #[inline]
+ pub fn insert<T: IntoBox<A>>(&mut self, value: T) -> Option<T> {
+ self.raw.insert(TypeId::of::<T>(), value.into_box())
+ .map(|any| unsafe { *any.downcast_unchecked::<T>() })
+ }
+
+ // rustc 1.60.0-nightly has another method try_insert that would be nice to add when stable.
+
+ /// Removes the `T` value from the collection,
+ /// returning it if there was one or `None` if there was not.
+ #[inline]
+ pub fn remove<T: IntoBox<A>>(&mut self) -> Option<T> {
+ self.raw.remove(&TypeId::of::<T>())
+ .map(|any| *unsafe { any.downcast_unchecked::<T>() })
+ }
+
+ /// Returns true if the collection contains a value of type `T`.
+ #[inline]
+ pub fn contains<T: IntoBox<A>>(&self) -> bool {
+ self.raw.contains_key(&TypeId::of::<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>()) {
+ raw_hash_map::Entry::Occupied(e) => Entry::Occupied(OccupiedEntry {
+ inner: e,
+ type_: PhantomData,
+ }),
+ raw_hash_map::Entry::Vacant(e) => Entry::Vacant(VacantEntry {
+ inner: e,
+ type_: PhantomData,
+ }),
+ }
+ }
+
+ /// Get access to the raw hash map that backs this.
+ ///
+ /// This will seldom be useful, but it’s conceivable that you could wish to iterate over all
+ /// the items in the collection, and this lets you do that.
+ ///
+ /// To improve compatibility with Cargo features, interact with this map through the names
+ /// [`anymap::RawMap`][RawMap] and [`anymap::raw_hash_map`][raw_hash_map], rather than through
+ /// `std::collections::{HashMap, hash_map}` or `hashbrown::{HashMap, hash_map}`, for anything
+ /// beyond self methods. Otherwise, if you use std and another crate in the tree enables
+ /// hashbrown, your code will break.
+ #[inline]
+ pub fn as_raw(&self) -> &RawMap<A> {
+ &self.raw
+ }
+
+ /// Get mutable access to the raw hash map that backs this.
+ ///
+ /// This will seldom be useful, but it’s conceivable that you could wish to iterate over all
+ /// the items in the collection mutably, or drain or something, or *possibly* even batch
+ /// insert, and this lets you do that.
+ ///
+ /// To improve compatibility with Cargo features, interact with this map through the names
+ /// [`anymap::RawMap`][RawMap] and [`anymap::raw_hash_map`][raw_hash_map], rather than through
+ /// `std::collections::{HashMap, hash_map}` or `hashbrown::{HashMap, hash_map}`, for anything
+ /// beyond self methods. Otherwise, if you use std and another crate in the tree enables
+ /// hashbrown, your code will break.
+ ///
+ /// # Safety
+ ///
+ /// If you insert any values to the raw map, the key (a `TypeId`) must match the value’s type,
+ /// or *undefined behaviour* will occur when you access those values.
+ ///
+ /// (*Removing* entries is perfectly safe.)
+ #[inline]
+ pub unsafe fn as_raw_mut(&mut self) -> &mut RawMap<A> {
+ &mut self.raw
+ }
+
+ /// Convert this into the raw hash map that backs this.
+ ///
+ /// This will seldom be useful, but it’s conceivable that you could wish to consume all the
+ /// items in the collection and do *something* with some or all of them, and this lets you do
+ /// that, without the `unsafe` that `.as_raw_mut().drain()` would require.
+ ///
+ /// To improve compatibility with Cargo features, interact with this map through the names
+ /// [`anymap::RawMap`][RawMap] and [`anymap::raw_hash_map`][raw_hash_map], rather than through
+ /// `std::collections::{HashMap, hash_map}` or `hashbrown::{HashMap, hash_map}`, for anything
+ /// beyond self methods. Otherwise, if you use std and another crate in the tree enables
+ /// hashbrown, your code will break.
+ #[inline]
+ pub fn into_raw(self) -> RawMap<A> {
+ self.raw
+ }
+
+ /// Construct a map from a collection of raw values.
+ ///
+ /// You know what? I can’t immediately think of any legitimate use for this, especially because
+ /// of the requirement of the `BuildHasherDefault<TypeIdHasher>` generic in the map.
+ ///
+ /// Perhaps this will be most practical as `unsafe { Map::from_raw(iter.collect()) }`, iter
+ /// being an iterator over `(TypeId, Box<A>)` pairs. Eh, this method provides symmetry with
+ /// `into_raw`, so I don’t care if literally no one ever uses it. I’m not even going to write a
+ /// test for it, it’s so trivial.
+ ///
+ /// To improve compatibility with Cargo features, interact with this map through the names
+ /// [`anymap::RawMap`][RawMap] and [`anymap::raw_hash_map`][raw_hash_map], rather than through
+ /// `std::collections::{HashMap, hash_map}` or `hashbrown::{HashMap, hash_map}`, for anything
+ /// beyond self methods. Otherwise, if you use std and another crate in the tree enables
+ /// hashbrown, your code will break.
+ ///
+ /// # Safety
+ ///
+ /// For all entries in the raw map, the key (a `TypeId`) must match the value’s type,
+ /// or *undefined behaviour* will occur when you access that entry.
+ #[inline]
+ pub unsafe fn from_raw(raw: RawMap<A>) -> Map<A> {
+ Self { raw }
+ }