Fortunately, we can do better than these things in Rust. Our type system is quite equal to easy, robust expression of such problems.
-The ``AnyMap`` type is a friendly wrapper around a ``HashMap<TypeId, Box<Any>>``, exposing a nice, easy typed interface, perfectly safe and absolutely robust.
+The ``AnyMap`` type is a friendly wrapper around a ``HashMap<TypeId, Box<dyn Any>>``, exposing a nice, easy typed interface, perfectly safe and absolutely robust.
What this means is that in an ``AnyMap`` you may store zero or one values for every type.
This library uses a fair bit of unsafe code for several reasons:
-- To support Any and CloneAny, unsafe code is required (because of how the `downcast` methods are defined in `impl Any` rather than being trait methods; I think this is kind of a historical detail of the structure of `std::any::Any`); if you wanted to ditch `Clone` support this unsafety could be removed.
+- To support Any and CloneAny, unsafe code is required (because of how the `downcast` methods are defined in `impl dyn Any` rather than being trait methods; I think this is kind of a historical detail of the structure of `std::any::Any`); if you wanted to ditch `Clone` support this unsafety could be removed.
- In the interests of performance, skipping various checks that are unnecessary because of the invariants of the data structure (no need to check the type ID when it’s been statically ensured by being used as the hash map key) and simplifying hashing (type IDs are already good hashes, no need to mangle them through SipHash).
#[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<dyn CloneAny>` object.
+ fn clone_to_any(&self) -> Box<dyn 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<dyn CloneAny + Send>` object.
+ fn clone_to_any_send(&self) -> Box<dyn 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<dyn CloneAny + Sync>` object.
+ fn clone_to_any_sync(&self) -> Box<dyn 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;
+ /// Clone `self` into a new `Box<dyn CloneAny + Send + Sync>` object.
+ fn clone_to_any_send_sync(&self) -> Box<dyn CloneAny + Send + Sync> where Self: Send + Sync;
}
impl<T: Any + Clone> CloneToAny for T {
#[inline]
- fn clone_to_any(&self) -> Box<CloneAny> {
+ fn clone_to_any(&self) -> Box<dyn CloneAny> {
Box::new(self.clone())
}
#[inline]
- fn clone_to_any_send(&self) -> Box<CloneAny + Send> where Self: Send {
+ fn clone_to_any_send(&self) -> Box<dyn CloneAny + Send> where Self: Send {
Box::new(self.clone())
}
#[inline]
- fn clone_to_any_sync(&self) -> Box<CloneAny + Sync> where Self: Sync {
+ fn clone_to_any_sync(&self) -> Box<dyn CloneAny + Sync> where Self: Sync {
Box::new(self.clone())
}
#[inline]
- fn clone_to_any_send_sync(&self) -> Box<CloneAny + Send + Sync> where Self: Send + Sync {
+ fn clone_to_any_send_sync(&self) -> Box<dyn CloneAny + Send + Sync> where Self: Send + Sync {
Box::new(self.clone())
}
}
macro_rules! implement {
($base:ident, $(+ $bounds:ident)*) => {
- impl fmt::Debug for $base $(+ $bounds)* {
+ impl fmt::Debug for dyn $base $(+ $bounds)* {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.pad(stringify!($base $(+ $bounds)*))
+ f.pad(stringify!(dyn $base $(+ $bounds)*))
}
}
- impl UncheckedAnyExt for $base $(+ $bounds)* {
+ impl UncheckedAnyExt for dyn $base $(+ $bounds)* {
#[inline]
unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T {
&*(self as *const Self as *const T)
}
}
- impl<T: $base $(+ $bounds)*> IntoBox<$base $(+ $bounds)*> for T {
+ impl<T: $base $(+ $bounds)*> IntoBox<dyn $base $(+ $bounds)*> for T {
#[inline]
- fn into_box(self) -> Box<$base $(+ $bounds)*> {
+ fn into_box(self) -> Box<dyn $base $(+ $bounds)*> {
Box::new(self)
}
}
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);
+impl_clone!(dyn CloneAny, clone_to_any);
+impl_clone!(dyn CloneAny + Send, clone_to_any_send);
+impl_clone!(dyn CloneAny + Sync, clone_to_any_sync);
+impl_clone!(dyn CloneAny + Send + Sync, clone_to_any_send_sync);
/// 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.
+/// - You can add on `+ Send` and/or `+ Sync` (e.g. `Map<dyn Any + Send>`) to add those bounds.
///
/// ```rust
/// # use anymap::AnyMap;
///
/// Values containing non-static references are not permitted.
#[derive(Debug)]
-pub struct Map<A: ?Sized + UncheckedAnyExt = Any> {
+pub struct Map<A: ?Sized + UncheckedAnyExt = dyn Any> {
raw: RawMap<A>,
}
/// 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>;
+pub type AnyMap = Map<dyn Any>;
impl_common_methods! {
field: Map.raw;
}
test_entry!(test_entry_any, AnyMap);
- test_entry!(test_entry_cloneany, Map<CloneAny>);
+ test_entry!(test_entry_cloneany, Map<dyn CloneAny>);
#[test]
fn test_default() {
#[test]
fn test_clone() {
- let mut map: Map<CloneAny> = Map::new();
+ let mut map: Map<dyn CloneAny> = Map::new();
let _ = map.insert(A(1));
let _ = map.insert(B(2));
let _ = map.insert(D(3));
fn assert_sync<T: Sync>() { }
fn assert_clone<T: Clone>() { }
fn assert_debug<T: ::std::fmt::Debug>() { }
- assert_send::<Map<Any + Send>>();
- assert_send::<Map<Any + Send + Sync>>();
- assert_sync::<Map<Any + Sync>>();
- assert_sync::<Map<Any + Send + Sync>>();
- assert_debug::<Map<Any>>();
- assert_debug::<Map<Any + Send>>();
- assert_debug::<Map<Any + Sync>>();
- assert_debug::<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>>();
- assert_debug::<Map<CloneAny>>();
- assert_debug::<Map<CloneAny + Send>>();
- assert_debug::<Map<CloneAny + Sync>>();
- assert_debug::<Map<CloneAny + Send + Sync>>();
+ assert_send::<Map<dyn Any + Send>>();
+ assert_send::<Map<dyn Any + Send + Sync>>();
+ assert_sync::<Map<dyn Any + Sync>>();
+ assert_sync::<Map<dyn Any + Send + Sync>>();
+ assert_debug::<Map<dyn Any>>();
+ assert_debug::<Map<dyn Any + Send>>();
+ assert_debug::<Map<dyn Any + Sync>>();
+ 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 + Sync>>();
+ assert_sync::<Map<dyn CloneAny + Send + Sync>>();
+ assert_clone::<Map<dyn CloneAny + Send>>();
+ assert_clone::<Map<dyn CloneAny + Send + Sync>>();
+ assert_clone::<Map<dyn CloneAny + Sync>>();
+ assert_clone::<Map<dyn CloneAny + Send + Sync>>();
+ assert_debug::<Map<dyn CloneAny>>();
+ assert_debug::<Map<dyn CloneAny + Send>>();
+ assert_debug::<Map<dyn CloneAny + Sync>>();
+ assert_debug::<Map<dyn CloneAny + Send + Sync>>();
}
}
/// 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)]
-pub struct RawMap<A: ?Sized + UncheckedAnyExt = Any> {
+pub struct RawMap<A: ?Sized + UncheckedAnyExt = dyn Any> {
inner: HashMap<TypeId, Box<A>, BuildHasherDefault<TypeIdHasher>>,
}