Replace Cargo features with arcane DST magicks.
(It was a toss-up between “arcane” and “eldritch” there; “arcane” won this time. “Eldritch”, maybe you can be it next time.)
This commit is contained in:
parent
fdba2f45b9
commit
7606e75aa4
|
@ -4,12 +4,6 @@ env:
|
||||||
- secure: nR+DJRUQ9v03nNZMpMu1tGKLKBAqdQsTIAr8ffdl+DUEh3b2jvQ+vLLNFLPjsloqhoOXo7cWO7qVpiE4ZOq2lNDURQjdiZGFjh/Y5+xKy2BqFdV7qQ1JoBzsMyx28tQTYz0mtBsACiCYKKb+ddNX5hpwrsjp8cS7htZktA5kbiU=
|
- secure: nR+DJRUQ9v03nNZMpMu1tGKLKBAqdQsTIAr8ffdl+DUEh3b2jvQ+vLLNFLPjsloqhoOXo7cWO7qVpiE4ZOq2lNDURQjdiZGFjh/Y5+xKy2BqFdV7qQ1JoBzsMyx28tQTYz0mtBsACiCYKKb+ddNX5hpwrsjp8cS7htZktA5kbiU=
|
||||||
script:
|
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 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 test
|
||||||
- cargo doc
|
- cargo doc
|
||||||
after_script:
|
after_script:
|
||||||
|
|
|
@ -11,6 +11,4 @@ keywords = ["container", "data-structure", "map"]
|
||||||
license = "MIT/Apache-2.0"
|
license = "MIT/Apache-2.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
clone = []
|
|
||||||
concurrent = []
|
|
||||||
nightly = []
|
nightly = []
|
||||||
|
|
|
@ -18,14 +18,6 @@ Instructions
|
||||||
|
|
||||||
Cargo all the way: it is `anymap` on crates.io.
|
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.
|
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
|
Author
|
||||||
|
|
167
src/any.rs
Normal file
167
src/any.rs
Normal file
|
@ -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<CloneAny>` object.
|
||||||
|
fn clone_to_any(&self) -> Box<CloneAny>;
|
||||||
|
|
||||||
|
/// Clone `self` into a new `Box<CloneAny + Send>` object.
|
||||||
|
fn clone_to_any_send(&self) -> Box<CloneAny + Send> where Self: Send;
|
||||||
|
|
||||||
|
/// Clone `self` into a new `Box<CloneAny + Sync>` object.
|
||||||
|
fn clone_to_any_sync(&self) -> Box<CloneAny + Sync> where Self: Sync;
|
||||||
|
|
||||||
|
/// Clone `self` into a new `Box<CloneAny + Send + Sync>` object.
|
||||||
|
fn clone_to_any_send_sync(&self) -> Box<CloneAny + Send + Sync> where Self: Send + Sync;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Any + Clone> CloneToAny for T {
|
||||||
|
fn clone_to_any(&self) -> Box<CloneAny> {
|
||||||
|
Box::new(self.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clone_to_any_send(&self) -> Box<CloneAny + Send> where Self: Send {
|
||||||
|
Box::new(self.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clone_to_any_sync(&self) -> Box<CloneAny + Sync> where Self: Sync {
|
||||||
|
Box::new(self.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clone_to_any_send_sync(&self) -> Box<CloneAny + Send + Sync> 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
|
||||||
|
/// <code><a class=trait title=core::marker::Send
|
||||||
|
/// href=http://doc.rust-lang.org/std/marker/trait.Send.html>Send</a></code> and
|
||||||
|
/// <code><a class=trait title=core::marker::Sync
|
||||||
|
/// href=http://doc.rust-lang.org/std/marker/trait.Sync.html>Sync</a></code>.
|
||||||
|
///
|
||||||
|
define!($t trait);
|
||||||
|
};
|
||||||
|
(CloneAny trait) => {
|
||||||
|
/// See also [`Any`](trait.Any.html) for a version without the `Clone` requirement.
|
||||||
|
pub trait CloneAny: Any + CloneToAny { }
|
||||||
|
impl<T: StdAny + Clone> CloneAny for T { }
|
||||||
|
};
|
||||||
|
(Any trait) => {
|
||||||
|
/// See also [`CloneAny`](trait.CloneAny.html) for a cloneable version of this trait.
|
||||||
|
pub trait Any: StdAny { }
|
||||||
|
impl<T: StdAny> 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<T: Any>(&self) -> &T;
|
||||||
|
unsafe fn downcast_mut_unchecked<T: Any>(&mut self) -> &mut T;
|
||||||
|
unsafe fn downcast_unchecked<T: Any>(self: Box<Self>) -> Box<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
/// A trait for the conversion of an object into a boxed trait object.
|
||||||
|
pub trait IntoBox<A: ?Sized + UncheckedAnyExt>: Any {
|
||||||
|
/// Convert self into the appropriate boxed form.
|
||||||
|
fn into_box(self) -> Box<A>;
|
||||||
|
}
|
||||||
|
|
||||||
|
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<T: 'static>(&self) -> &T {
|
||||||
|
mem::transmute(mem::transmute::<_, TraitObject>(self).data)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T {
|
||||||
|
mem::transmute(mem::transmute::<_, TraitObject>(self).data)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn downcast_unchecked<T: 'static>(self: Box<Self>) -> Box<T> {
|
||||||
|
mem::transmute(mem::transmute::<_, TraitObject>(self).data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: $base $(+ $bounds)*> 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);
|
129
src/lib.rs
129
src/lib.rs
|
@ -10,8 +10,8 @@ extern crate test;
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use raw::{RawAnyMap, Any};
|
use raw::RawMap;
|
||||||
use unchecked_any::UncheckedAnyExt;
|
use any::{UncheckedAnyExt, IntoBox, Any};
|
||||||
|
|
||||||
macro_rules! impl_common_methods {
|
macro_rules! impl_common_methods {
|
||||||
(
|
(
|
||||||
|
@ -19,10 +19,10 @@ macro_rules! impl_common_methods {
|
||||||
new() => $new:expr;
|
new() => $new:expr;
|
||||||
with_capacity($with_capacity_arg:ident) => $with_capacity:expr;
|
with_capacity($with_capacity_arg:ident) => $with_capacity:expr;
|
||||||
) => {
|
) => {
|
||||||
impl $t {
|
impl<A: ?Sized + UncheckedAnyExt> $t<A> {
|
||||||
/// Create an empty collection.
|
/// Create an empty collection.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new() -> $t {
|
pub fn new() -> $t<A> {
|
||||||
$t {
|
$t {
|
||||||
$field: $new,
|
$field: $new,
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ macro_rules! impl_common_methods {
|
||||||
|
|
||||||
/// Creates an empty collection with the given initial capacity.
|
/// Creates an empty collection with the given initial capacity.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn with_capacity($with_capacity_arg: usize) -> $t {
|
pub fn with_capacity($with_capacity_arg: usize) -> $t<A> {
|
||||||
$t {
|
$t {
|
||||||
$field: $with_capacity,
|
$field: $with_capacity,
|
||||||
}
|
}
|
||||||
|
@ -83,12 +83,18 @@ macro_rules! impl_common_methods {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod unchecked_any;
|
pub mod any;
|
||||||
pub mod raw;
|
pub mod raw;
|
||||||
|
|
||||||
/// A collection containing zero or one values for any given type and allowing convenient,
|
/// A collection containing zero or one values for any given type and allowing convenient,
|
||||||
/// type-safe access to those values.
|
/// 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<Any + Send>`) to add those bounds.
|
||||||
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use anymap::AnyMap;
|
/// # use anymap::AnyMap;
|
||||||
/// let mut data = AnyMap::new();
|
/// let mut data = AnyMap::new();
|
||||||
|
@ -112,27 +118,42 @@ pub mod raw;
|
||||||
///
|
///
|
||||||
/// Values containing non-static references are not permitted.
|
/// Values containing non-static references are not permitted.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(feature = "clone", derive(Clone))]
|
pub struct Map<A: ?Sized + UncheckedAnyExt = Any> {
|
||||||
pub struct AnyMap {
|
raw: RawMap<A>,
|
||||||
raw: RawAnyMap,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #[derive(Clone)] would want A to implement Clone, but in reality it’s only Box<A> that can.
|
||||||
|
impl<A: ?Sized + UncheckedAnyExt> Clone for Map<A> where Box<A>: Clone {
|
||||||
|
fn clone(&self) -> Map<A> {
|
||||||
|
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<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<Any>;
|
||||||
|
|
||||||
impl_common_methods! {
|
impl_common_methods! {
|
||||||
field: AnyMap.raw;
|
field: Map.raw;
|
||||||
new() => RawAnyMap::new();
|
new() => RawMap::new();
|
||||||
with_capacity(capacity) => RawAnyMap::with_capacity(capacity);
|
with_capacity(capacity) => RawMap::with_capacity(capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AnyMap {
|
impl<A: ?Sized + UncheckedAnyExt> Map<A> {
|
||||||
/// Returns a reference to the value stored in the collection for the type `T`, if it exists.
|
/// Returns a reference to the value stored in the collection for the type `T`, if it exists.
|
||||||
pub fn get<T: Any>(&self) -> Option<&T> {
|
pub fn get<T: IntoBox<A>>(&self) -> Option<&T> {
|
||||||
self.raw.get(&TypeId::of::<T>())
|
self.raw.get(&TypeId::of::<T>())
|
||||||
.map(|any| unsafe { any.downcast_ref_unchecked::<T>() })
|
.map(|any| unsafe { any.downcast_ref_unchecked::<T>() })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a mutable reference to the value stored in the collection for the type `T`,
|
/// Returns a mutable reference to the value stored in the collection for the type `T`,
|
||||||
/// if it exists.
|
/// if it exists.
|
||||||
pub fn get_mut<T: Any>(&mut self) -> Option<&mut T> {
|
pub fn get_mut<T: IntoBox<A>>(&mut self) -> Option<&mut T> {
|
||||||
self.raw.get_mut(&TypeId::of::<T>())
|
self.raw.get_mut(&TypeId::of::<T>())
|
||||||
.map(|any| unsafe { any.downcast_mut_unchecked::<T>() })
|
.map(|any| unsafe { any.downcast_mut_unchecked::<T>() })
|
||||||
}
|
}
|
||||||
|
@ -140,28 +161,28 @@ impl AnyMap {
|
||||||
/// Sets the value stored in the collection for the type `T`.
|
/// 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.
|
/// If the collection already had a value of type `T`, that value is returned.
|
||||||
/// Otherwise, `None` is returned.
|
/// Otherwise, `None` is returned.
|
||||||
pub fn insert<T: Any>(&mut self, value: T) -> Option<T> {
|
pub fn insert<T: IntoBox<A>>(&mut self, value: T) -> Option<T> {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.raw.insert(TypeId::of::<T>(), Box::new(value))
|
self.raw.insert(TypeId::of::<T>(), value.into_box())
|
||||||
.map(|any| *any.downcast_unchecked::<T>())
|
.map(|any| *any.downcast_unchecked::<T>())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes the `T` value from the collection,
|
/// Removes the `T` value from the collection,
|
||||||
/// returning it if there was one or `None` if there was not.
|
/// returning it if there was one or `None` if there was not.
|
||||||
pub fn remove<T: Any>(&mut self) -> Option<T> {
|
pub fn remove<T: IntoBox<A>>(&mut self) -> Option<T> {
|
||||||
self.raw.remove(&TypeId::of::<T>())
|
self.raw.remove(&TypeId::of::<T>())
|
||||||
.map(|any| *unsafe { any.downcast_unchecked::<T>() })
|
.map(|any| *unsafe { any.downcast_unchecked::<T>() })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the collection contains a value of type `T`.
|
/// Returns true if the collection contains a value of type `T`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn contains<T: Any>(&self) -> bool {
|
pub fn contains<T: IntoBox<A>>(&self) -> bool {
|
||||||
self.raw.contains_key(&TypeId::of::<T>())
|
self.raw.contains_key(&TypeId::of::<T>())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the entry for the given type in the collection for in-place manipulation
|
/// Gets the entry for the given type in the collection for in-place manipulation
|
||||||
pub fn entry<T: Any>(&mut self) -> Entry<T> {
|
pub fn entry<T: IntoBox<A>>(&mut self) -> Entry<A, T> {
|
||||||
match self.raw.entry(TypeId::of::<T>()) {
|
match self.raw.entry(TypeId::of::<T>()) {
|
||||||
raw::Entry::Occupied(e) => Entry::Occupied(OccupiedEntry {
|
raw::Entry::Occupied(e) => Entry::Occupied(OccupiedEntry {
|
||||||
inner: e,
|
inner: e,
|
||||||
|
@ -175,45 +196,45 @@ impl AnyMap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRef<RawAnyMap> for AnyMap {
|
impl<A: ?Sized + UncheckedAnyExt> AsRef<RawMap<A>> for Map<A> {
|
||||||
fn as_ref(&self) -> &RawAnyMap {
|
fn as_ref(&self) -> &RawMap<A> {
|
||||||
&self.raw
|
&self.raw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsMut<RawAnyMap> for AnyMap {
|
impl<A: ?Sized + UncheckedAnyExt> AsMut<RawMap<A>> for Map<A> {
|
||||||
fn as_mut(&mut self) -> &mut RawAnyMap {
|
fn as_mut(&mut self) -> &mut RawMap<A> {
|
||||||
&mut self.raw
|
&mut self.raw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<RawAnyMap> for AnyMap {
|
impl<A: ?Sized + UncheckedAnyExt> Into<RawMap<A>> for Map<A> {
|
||||||
fn into(self) -> RawAnyMap {
|
fn into(self) -> RawMap<A> {
|
||||||
self.raw
|
self.raw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A view into a single occupied location in an `AnyMap`.
|
/// A view into a single occupied location in an `Map`.
|
||||||
pub struct OccupiedEntry<'a, V: 'a> {
|
pub struct OccupiedEntry<'a, A: ?Sized + UncheckedAnyExt, V: 'a> {
|
||||||
inner: raw::OccupiedEntry<'a>,
|
inner: raw::OccupiedEntry<'a, A>,
|
||||||
type_: PhantomData<V>,
|
type_: PhantomData<V>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A view into a single empty location in an `AnyMap`.
|
/// A view into a single empty location in an `Map`.
|
||||||
pub struct VacantEntry<'a, V: 'a> {
|
pub struct VacantEntry<'a, A: ?Sized + UncheckedAnyExt, V: 'a> {
|
||||||
inner: raw::VacantEntry<'a>,
|
inner: raw::VacantEntry<'a, A>,
|
||||||
type_: PhantomData<V>,
|
type_: PhantomData<V>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A view into a single location in an `AnyMap`, which may be vacant or occupied.
|
/// A view into a single location in an `Map`, which may be vacant or occupied.
|
||||||
pub enum Entry<'a, V: 'a> {
|
pub enum Entry<'a, A: ?Sized + UncheckedAnyExt, V: 'a> {
|
||||||
/// An occupied Entry
|
/// An occupied Entry
|
||||||
Occupied(OccupiedEntry<'a, V>),
|
Occupied(OccupiedEntry<'a, A, V>),
|
||||||
/// A vacant Entry
|
/// 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<A> + Clone> Entry<'a, A, V> {
|
||||||
/// Ensures a value is in the entry by inserting the default if empty, and returns
|
/// Ensures a value is in the entry by inserting the default if empty, and returns
|
||||||
/// a mutable reference to the value in the entry.
|
/// a mutable reference to the value in the entry.
|
||||||
pub fn or_insert(self, default: V) -> &'a mut V {
|
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<A>> OccupiedEntry<'a, A, V> {
|
||||||
/// Gets a reference to the value in the entry
|
/// Gets a reference to the value in the entry
|
||||||
pub fn get(&self) -> &V {
|
pub fn get(&self) -> &V {
|
||||||
unsafe { self.inner.get().downcast_ref_unchecked() }
|
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
|
/// Sets the value of the entry, and returns the entry's old value
|
||||||
pub fn insert(&mut self, value: V) -> V {
|
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
|
/// 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<A>> VacantEntry<'a, A, V> {
|
||||||
/// Sets the value of the entry with the VacantEntry's key,
|
/// Sets the value of the entry with the VacantEntry's key,
|
||||||
/// and returns a mutable reference to it
|
/// and returns a mutable reference to it
|
||||||
pub fn insert(self, value: V) -> &'a mut V {
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
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 A(i32);
|
||||||
#[derive(Clone, Debug, PartialEq)] struct B(i32);
|
#[derive(Clone, Debug, PartialEq)] struct B(i32);
|
||||||
|
@ -380,10 +402,9 @@ mod tests {
|
||||||
assert_eq!(map.len(), 7);
|
assert_eq!(map.len(), 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "clone")]
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_clone() {
|
fn test_clone() {
|
||||||
let mut map = AnyMap::new();
|
let mut map: Map<CloneAny> = Map::new();
|
||||||
let _ = map.insert(A(1));
|
let _ = map.insert(A(1));
|
||||||
let _ = map.insert(B(2));
|
let _ = map.insert(B(2));
|
||||||
let _ = map.insert(D(3));
|
let _ = map.insert(D(3));
|
||||||
|
@ -401,10 +422,22 @@ mod tests {
|
||||||
assert_eq!(map2.get::<J>(), Some(&J(6)));
|
assert_eq!(map2.get::<J>(), Some(&J(6)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "concurrent")]
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_concurrent() {
|
fn test_varieties() {
|
||||||
fn assert_concurrent<T: Send + Sync>() { }
|
fn assert_send<T: Send>() { }
|
||||||
assert_concurrent::<AnyMap>();
|
fn assert_sync<T: Sync>() { }
|
||||||
|
fn assert_clone<T: Clone>() { }
|
||||||
|
assert_send::<Map<Any + Send>>();
|
||||||
|
assert_send::<Map<Any + Send + Sync>>();
|
||||||
|
assert_sync::<Map<Any + Sync>>();
|
||||||
|
assert_sync::<Map<Any + Send + Sync>>();
|
||||||
|
assert_send::<Map<CloneAny + Send>>();
|
||||||
|
assert_send::<Map<CloneAny + Send + Sync>>();
|
||||||
|
assert_sync::<Map<CloneAny + Sync>>();
|
||||||
|
assert_sync::<Map<CloneAny + Send + Sync>>();
|
||||||
|
assert_clone::<Map<CloneAny + Send>>();
|
||||||
|
assert_clone::<Map<CloneAny + Send + Sync>>();
|
||||||
|
assert_clone::<Map<CloneAny + Sync>>();
|
||||||
|
assert_clone::<Map<CloneAny + Send + Sync>>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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::any::TypeId;
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
|
@ -18,16 +18,14 @@ use std::ops::{Index, IndexMut};
|
||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
pub use self::any::Any;
|
use any::{Any, UncheckedAnyExt};
|
||||||
|
|
||||||
mod any;
|
|
||||||
|
|
||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
struct TypeIdHasher {
|
struct TypeIdHasher {
|
||||||
value: u64,
|
value: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "clone", derive(Clone))]
|
#[derive(Clone)]
|
||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
struct TypeIdState;
|
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<TypeId, Box<Any>>`, with the portions that
|
/// At its essence, this is a wrapper around `HashMap<TypeId, Box<Any>>`, with the portions that
|
||||||
/// would be memory-unsafe removed or marked unsafe. Normal people are expected to use the safe
|
/// 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
|
/// `Map` 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
|
/// 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.
|
/// doesn’t tend to be so very useful. Still, if you need it, it’s here.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(feature = "clone", derive(Clone))]
|
pub struct RawMap<A: ?Sized + UncheckedAnyExt = Any> {
|
||||||
pub struct RawAnyMap {
|
|
||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
inner: HashMap<TypeId, Box<Any>, TypeIdState>,
|
inner: HashMap<TypeId, Box<A>, TypeIdState>,
|
||||||
|
|
||||||
#[cfg(not(feature = "nightly"))]
|
#[cfg(not(feature = "nightly"))]
|
||||||
inner: HashMap<TypeId, Box<Any>>,
|
inner: HashMap<TypeId, Box<A>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for RawAnyMap {
|
// #[derive(Clone)] would want A to implement Clone, but in reality it’s only Box<A> that can.
|
||||||
fn default() -> RawAnyMap {
|
impl<A: ?Sized + UncheckedAnyExt> Clone for RawMap<A> where Box<A>: Clone {
|
||||||
RawAnyMap::new()
|
fn clone(&self) -> RawMap<A> {
|
||||||
|
RawMap {
|
||||||
|
inner: self.inner.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: ?Sized + UncheckedAnyExt> Default for RawMap<A> {
|
||||||
|
fn default() -> RawMap<A> {
|
||||||
|
RawMap::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
impl_common_methods! {
|
impl_common_methods! {
|
||||||
field: RawAnyMap.inner;
|
field: RawMap.inner;
|
||||||
new() => HashMap::with_hash_state(TypeIdState);
|
new() => HashMap::with_hash_state(TypeIdState);
|
||||||
with_capacity(capacity) => HashMap::with_capacity_and_hash_state(capacity, TypeIdState);
|
with_capacity(capacity) => HashMap::with_capacity_and_hash_state(capacity, TypeIdState);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "nightly"))]
|
#[cfg(not(feature = "nightly"))]
|
||||||
impl_common_methods! {
|
impl_common_methods! {
|
||||||
field: RawAnyMap.inner;
|
field: RawMap.inner;
|
||||||
new() => HashMap::new();
|
new() => HashMap::new();
|
||||||
with_capacity(capacity) => HashMap::with_capacity(capacity);
|
with_capacity(capacity) => HashMap::with_capacity(capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// RawAnyMap iterator.
|
/// RawMap iterator.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Iter<'a> {
|
pub struct Iter<'a, A: ?Sized + UncheckedAnyExt> {
|
||||||
inner: hash_map::Iter<'a, TypeId, Box<Any>>,
|
inner: hash_map::Iter<'a, TypeId, Box<A>>,
|
||||||
}
|
}
|
||||||
impl<'a> Iterator for Iter<'a> {
|
impl<'a, A: ?Sized + UncheckedAnyExt> Iterator for Iter<'a, A> {
|
||||||
type Item = &'a Any;
|
type Item = &'a A;
|
||||||
#[inline] fn next(&mut self) -> Option<&'a Any> { self.inner.next().map(|x| &**x.1) }
|
#[inline] fn next(&mut self) -> Option<&'a A> { self.inner.next().map(|x| &**x.1) }
|
||||||
#[inline] fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
|
#[inline] fn size_hint(&self) -> (usize, Option<usize>) { 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() }
|
#[inline] fn len(&self) -> usize { self.inner.len() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// RawAnyMap mutable iterator.
|
/// RawMap mutable iterator.
|
||||||
pub struct IterMut<'a> {
|
pub struct IterMut<'a, A: ?Sized + UncheckedAnyExt> {
|
||||||
inner: hash_map::IterMut<'a, TypeId, Box<Any>>,
|
inner: hash_map::IterMut<'a, TypeId, Box<A>>,
|
||||||
}
|
}
|
||||||
impl<'a> Iterator for IterMut<'a> {
|
impl<'a, A: ?Sized + UncheckedAnyExt> Iterator for IterMut<'a, A> {
|
||||||
type Item = &'a mut Any;
|
type Item = &'a mut A;
|
||||||
#[inline] fn next(&mut self) -> Option<&'a mut Any> { self.inner.next().map(|x| &mut **x.1) }
|
#[inline] fn next(&mut self) -> Option<&'a mut A> { self.inner.next().map(|x| &mut **x.1) }
|
||||||
#[inline] fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
|
#[inline] fn size_hint(&self) -> (usize, Option<usize>) { 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() }
|
#[inline] fn len(&self) -> usize { self.inner.len() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// RawAnyMap move iterator.
|
/// RawMap move iterator.
|
||||||
pub struct IntoIter {
|
pub struct IntoIter<A: ?Sized + UncheckedAnyExt> {
|
||||||
inner: hash_map::IntoIter<TypeId, Box<Any>>,
|
inner: hash_map::IntoIter<TypeId, Box<A>>,
|
||||||
}
|
}
|
||||||
impl Iterator for IntoIter {
|
impl<A: ?Sized + UncheckedAnyExt> Iterator for IntoIter<A> {
|
||||||
type Item = Box<Any>;
|
type Item = Box<A>;
|
||||||
#[inline] fn next(&mut self) -> Option<Box<Any>> { self.inner.next().map(|x| x.1) }
|
#[inline] fn next(&mut self) -> Option<Box<A>> { self.inner.next().map(|x| x.1) }
|
||||||
#[inline] fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
|
#[inline] fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
|
||||||
}
|
}
|
||||||
impl ExactSizeIterator for IntoIter {
|
impl<A: ?Sized + UncheckedAnyExt> ExactSizeIterator for IntoIter<A> {
|
||||||
#[inline] fn len(&self) -> usize { self.inner.len() }
|
#[inline] fn len(&self) -> usize { self.inner.len() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// RawAnyMap drain iterator.
|
/// RawMap drain iterator.
|
||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
pub struct Drain<'a> {
|
pub struct Drain<'a, A: ?Sized + UncheckedAnyExt> {
|
||||||
inner: hash_map::Drain<'a, TypeId, Box<Any>>,
|
inner: hash_map::Drain<'a, TypeId, Box<A>>,
|
||||||
}
|
}
|
||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
impl<'a> Iterator for Drain<'a> {
|
impl<'a, A: ?Sized + UncheckedAnyExt> Iterator for Drain<'a, A> {
|
||||||
type Item = Box<Any>;
|
type Item = Box<A>;
|
||||||
#[inline] fn next(&mut self) -> Option<Box<Any>> { self.inner.next().map(|x| x.1) }
|
#[inline] fn next(&mut self) -> Option<Box<A>> { self.inner.next().map(|x| x.1) }
|
||||||
#[inline] fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
|
#[inline] fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
|
||||||
}
|
}
|
||||||
#[cfg(feature = "nightly")]
|
#[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() }
|
#[inline] fn len(&self) -> usize { self.inner.len() }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RawAnyMap {
|
impl<A: ?Sized + UncheckedAnyExt> RawMap<A> {
|
||||||
/// An iterator visiting all entries in arbitrary order.
|
/// An iterator visiting all entries in arbitrary order.
|
||||||
///
|
///
|
||||||
/// Iterator element type is `&Any`.
|
/// Iterator element type is `&Any`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn iter(&self) -> Iter {
|
pub fn iter(&self) -> Iter<A> {
|
||||||
Iter {
|
Iter {
|
||||||
inner: self.inner.iter(),
|
inner: self.inner.iter(),
|
||||||
}
|
}
|
||||||
|
@ -164,24 +170,12 @@ impl RawAnyMap {
|
||||||
///
|
///
|
||||||
/// Iterator element type is `&mut Any`.
|
/// Iterator element type is `&mut Any`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn iter_mut(&mut self) -> IterMut {
|
pub fn iter_mut(&mut self) -> IterMut<A> {
|
||||||
IterMut {
|
IterMut {
|
||||||
inner: self.inner.iter_mut(),
|
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<Any>`.
|
|
||||||
#[inline]
|
|
||||||
pub fn into_iter(self) -> IntoIter {
|
|
||||||
IntoIter {
|
|
||||||
inner: self.inner.into_iter(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clears the map, returning all items as an iterator.
|
/// Clears the map, returning all items as an iterator.
|
||||||
///
|
///
|
||||||
/// Iterator element type is `Box<Any>`.
|
/// Iterator element type is `Box<Any>`.
|
||||||
|
@ -189,14 +183,14 @@ impl RawAnyMap {
|
||||||
/// Keeps the allocated memory for reuse.
|
/// Keeps the allocated memory for reuse.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
pub fn drain(&mut self) -> Drain {
|
pub fn drain(&mut self) -> Drain<A> {
|
||||||
Drain {
|
Drain {
|
||||||
inner: self.inner.drain(),
|
inner: self.inner.drain(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the entry for the given type in the collection for in-place manipulation.
|
/// 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<A> {
|
||||||
match self.inner.entry(key) {
|
match self.inner.entry(key) {
|
||||||
hash_map::Entry::Occupied(e) => Entry::Occupied(OccupiedEntry {
|
hash_map::Entry::Occupied(e) => Entry::Occupied(OccupiedEntry {
|
||||||
inner: e,
|
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
|
/// 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.
|
/// form *must* match those for the key type.
|
||||||
pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&Any>
|
pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&A>
|
||||||
where TypeId: Borrow<Q>, Q: Hash + Eq {
|
where TypeId: Borrow<Q>, Q: Hash + Eq {
|
||||||
self.inner.get(k).map(|x| &**x)
|
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
|
/// 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.
|
/// form *must* match those for the key type.
|
||||||
pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut Any>
|
pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut A>
|
||||||
where TypeId: Borrow<Q>, Q: Hash + Eq {
|
where TypeId: Borrow<Q>, Q: Hash + Eq {
|
||||||
self.inner.get_mut(k).map(|x| &mut **x)
|
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
|
/// 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.
|
/// the value. If they do not, memory safety may be violated.
|
||||||
pub unsafe fn insert(&mut self, key: TypeId, value: Box<Any>) -> Option<Box<Any>> {
|
pub unsafe fn insert(&mut self, key: TypeId, value: Box<A>) -> Option<Box<A>> {
|
||||||
self.inner.insert(key, value)
|
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
|
/// 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.
|
/// form *must* match those for the key type.
|
||||||
pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<Box<Any>>
|
pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<Box<A>>
|
||||||
where TypeId: Borrow<Q>, Q: Hash + Eq {
|
where TypeId: Borrow<Q>, Q: Hash + Eq {
|
||||||
self.inner.remove(k)
|
self.inner.remove(k)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Q> Index<Q> for RawAnyMap where TypeId: Borrow<Q>, Q: Eq + Hash {
|
impl<A: ?Sized + UncheckedAnyExt, Q> Index<Q> for RawMap<A> where TypeId: Borrow<Q>, Q: Eq + Hash {
|
||||||
type Output = Any;
|
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")
|
self.get(&index).expect("no entry found for key")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Q> IndexMut<Q> for RawAnyMap where TypeId: Borrow<Q>, Q: Eq + Hash {
|
impl<A: ?Sized + UncheckedAnyExt, Q> IndexMut<Q> for RawMap<A> where TypeId: Borrow<Q>, Q: Eq + Hash {
|
||||||
fn index_mut<'a>(&'a mut self, index: Q) -> &'a mut Any {
|
fn index_mut<'a>(&'a mut self, index: Q) -> &'a mut A {
|
||||||
self.get_mut(&index).expect("no entry found for key")
|
self.get_mut(&index).expect("no entry found for key")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoIterator for RawAnyMap {
|
impl<A: ?Sized + UncheckedAnyExt> IntoIterator for RawMap<A> {
|
||||||
type Item = Box<Any>;
|
type Item = Box<A>;
|
||||||
type IntoIter = IntoIter;
|
type IntoIter = IntoIter<A>;
|
||||||
|
|
||||||
fn into_iter(self) -> IntoIter {
|
fn into_iter(self) -> IntoIter<A> {
|
||||||
self.into_iter()
|
IntoIter {
|
||||||
|
inner: self.inner.into_iter(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A view into a single occupied location in a `RawAnyMap`.
|
/// A view into a single occupied location in a `RawMap`.
|
||||||
pub struct OccupiedEntry<'a> {
|
pub struct OccupiedEntry<'a, A: ?Sized + UncheckedAnyExt> {
|
||||||
inner: hash_map::OccupiedEntry<'a, TypeId, Box<Any>>,
|
inner: hash_map::OccupiedEntry<'a, TypeId, Box<A>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A view into a single empty location in a `RawAnyMap`.
|
/// A view into a single empty location in a `RawMap`.
|
||||||
pub struct VacantEntry<'a> {
|
pub struct VacantEntry<'a, A: ?Sized + UncheckedAnyExt> {
|
||||||
inner: hash_map::VacantEntry<'a, TypeId, Box<Any>>,
|
inner: hash_map::VacantEntry<'a, TypeId, Box<A>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A view into a single location in an AnyMap, which may be vacant or occupied.
|
/// A view into a single location in a `RawMap`, which may be vacant or occupied.
|
||||||
pub enum Entry<'a> {
|
pub enum Entry<'a, A: ?Sized + UncheckedAnyExt> {
|
||||||
/// An occupied Entry
|
/// An occupied Entry
|
||||||
Occupied(OccupiedEntry<'a>),
|
Occupied(OccupiedEntry<'a, A>),
|
||||||
/// A vacant Entry
|
/// 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
|
/// Ensures a value is in the entry by inserting the default if empty, and returns
|
||||||
/// a mutable reference to the value in the entry.
|
/// 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
|
/// 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.
|
/// the type ID of `value`. If they do not, memory safety may be violated.
|
||||||
pub unsafe fn or_insert(self, default: Box<Any>) -> &'a mut Any {
|
pub unsafe fn or_insert(self, default: Box<A>) -> &'a mut A {
|
||||||
match self {
|
match self {
|
||||||
Entry::Occupied(inner) => inner.into_mut(),
|
Entry::Occupied(inner) => inner.into_mut(),
|
||||||
Entry::Vacant(inner) => inner.insert(default),
|
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
|
/// 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.
|
/// the type ID of `value`. If they do not, memory safety may be violated.
|
||||||
pub unsafe fn or_insert_with<F: FnOnce() -> Box<Any>>(self, default: F) -> &'a mut Any {
|
pub unsafe fn or_insert_with<F: FnOnce() -> Box<A>>(self, default: F) -> &'a mut A {
|
||||||
match self {
|
match self {
|
||||||
Entry::Occupied(inner) => inner.into_mut(),
|
Entry::Occupied(inner) => inner.into_mut(),
|
||||||
Entry::Vacant(inner) => inner.insert(default()),
|
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.
|
/// Gets a reference to the value in the entry.
|
||||||
pub fn get(&self) -> &Any {
|
pub fn get(&self) -> &A {
|
||||||
&**self.inner.get()
|
&**self.inner.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a mutable reference to the value in the entry.
|
/// 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()
|
&mut **self.inner.get_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts the OccupiedEntry into a mutable reference to the value in the entry
|
/// Converts the OccupiedEntry into a mutable reference to the value in the entry
|
||||||
/// with a lifetime bound to the collection itself.
|
/// 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()
|
&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
|
/// 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.
|
/// the type ID of `value`. If they do not, memory safety may be violated.
|
||||||
pub unsafe fn insert(&mut self, value: Box<Any>) -> Box<Any> {
|
pub unsafe fn insert(&mut self, value: Box<A>) -> Box<A> {
|
||||||
self.inner.insert(value)
|
self.inner.insert(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Takes the value out of the entry, and returns it.
|
/// Takes the value out of the entry, and returns it.
|
||||||
pub fn remove(self) -> Box<Any> {
|
pub fn remove(self) -> Box<A> {
|
||||||
self.inner.remove()
|
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,
|
/// Sets the value of the entry with the VacantEntry's key,
|
||||||
/// and returns a mutable reference to it
|
/// and returns a mutable reference to it
|
||||||
///
|
///
|
||||||
/// It is the caller’s responsibility to ensure that the key of the entry corresponds with
|
/// 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.
|
/// the type ID of `value`. If they do not, memory safety may be violated.
|
||||||
pub unsafe fn insert(self, value: Box<Any>) -> &'a mut Any {
|
pub unsafe fn insert(self, value: Box<A>) -> &'a mut A {
|
||||||
&mut **self.inner.insert(value)
|
&mut **self.inner.insert(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
105
src/raw/any.rs
105
src/raw/any.rs
|
@ -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<Any>` object.
|
|
||||||
fn clone_to_any(&self) -> Box<Any>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "clone")]
|
|
||||||
impl<T: Any + Clone> CloneToAny for T {
|
|
||||||
fn clone_to_any(&self) -> Box<Any> {
|
|
||||||
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:
|
|
||||||
///
|
|
||||||
/// <table>
|
|
||||||
/// <thead>
|
|
||||||
/// <tr>
|
|
||||||
/// <th title="The name of the Cargo feature to enable">Feature name</th>
|
|
||||||
/// <th title="If a type doesn’t satisfy these bounds, it won’t implement Any">Additional bounds</th>
|
|
||||||
/// <th title="Were these docs built with this feature enabled?">Enabled in these docs?</th>
|
|
||||||
/// </tr>
|
|
||||||
/// </thead>
|
|
||||||
/// <tbody>
|
|
||||||
/// <tr>
|
|
||||||
/// <th><code>clone</code></th>
|
|
||||||
/// <td><code><a class=trait title=core::clone::Clone
|
|
||||||
/// href=http://doc.rust-lang.org/std/clone/trait.Clone.html
|
|
||||||
/// >Clone</a></code></td>
|
|
||||||
#[cfg_attr(feature = "clone", doc = " <td>Yes</td>")]
|
|
||||||
#[cfg_attr(not(feature = "clone"), doc = " <td>No</td>")]
|
|
||||||
/// </tr>
|
|
||||||
/// <tr>
|
|
||||||
/// <th><code>concurrent</code></th>
|
|
||||||
/// <td><code><a class=trait title=core::marker::Send
|
|
||||||
/// href=http://doc.rust-lang.org/std/marker/trait.Send.html
|
|
||||||
/// >Send</a> + <a class=trait title=core::marker::Sync
|
|
||||||
/// href=http://doc.rust-lang.org/std/marker/trait.Sync.html
|
|
||||||
/// >Sync</a></code></td>
|
|
||||||
#[cfg_attr(feature = "concurrent", doc = " <td>Yes</td>")]
|
|
||||||
#[cfg_attr(not(feature = "concurrent"), doc = " <td>No</td>")]
|
|
||||||
/// </tr>
|
|
||||||
/// </tbody>
|
|
||||||
/// </table>
|
|
||||||
#[$m] $t
|
|
||||||
#[$m] $i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
define_any! {
|
|
||||||
#[cfg(all(not(feature = "clone"), not(feature = "concurrent")))]
|
|
||||||
pub trait Any: StdAny { }
|
|
||||||
impl<T: StdAny> Any for T { }
|
|
||||||
}
|
|
||||||
|
|
||||||
define_any! {
|
|
||||||
#[cfg(all(feature = "clone", not(feature = "concurrent")))]
|
|
||||||
pub trait Any: StdAny + CloneToAny { }
|
|
||||||
impl<T: StdAny + Clone> Any for T { }
|
|
||||||
}
|
|
||||||
|
|
||||||
define_any! {
|
|
||||||
#[cfg(all(not(feature = "clone"), feature = "concurrent"))]
|
|
||||||
pub trait Any: StdAny + Send + Sync { }
|
|
||||||
impl<T: StdAny + Send + Sync> Any for T { }
|
|
||||||
}
|
|
||||||
|
|
||||||
define_any! {
|
|
||||||
#[cfg(all(feature = "clone", feature = "concurrent"))]
|
|
||||||
pub trait Any: StdAny + CloneToAny + Send + Sync { }
|
|
||||||
impl<T: StdAny + Clone + Send + Sync> Any for T { }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "clone")]
|
|
||||||
impl Clone for Box<Any> {
|
|
||||||
fn clone(&self) -> Box<Any> {
|
|
||||||
(**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<Any> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
f.pad("Box<Any>")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<T: 'static>(&self) -> &T;
|
|
||||||
unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T;
|
|
||||||
unsafe fn downcast_unchecked<T: 'static>(self: Box<Self>) -> Box<T>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UncheckedAnyExt for Any {
|
|
||||||
unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T {
|
|
||||||
mem::transmute(mem::transmute::<_, TraitObject>(self).data)
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T {
|
|
||||||
mem::transmute(mem::transmute::<_, TraitObject>(self).data)
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn downcast_unchecked<T: 'static>(self: Box<Any>) -> Box<T> {
|
|
||||||
mem::transmute(mem::transmute::<_, TraitObject>(self).data)
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue