No more bare trait objects: use dyn Trait
syntax
This commit is contained in:
parent
7719a1c61b
commit
bf29e608d9
|
@ -6,7 +6,7 @@ As another example of such an interface, JavaScript objects are exactly the same
|
||||||
|
|
||||||
Fortunately, we can do better than these things in Rust. Our type system is quite equal to easy, robust expression of such problems.
|
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.
|
What this means is that in an ``AnyMap`` you may store zero or one values for every type.
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ What this means is that in an ``AnyMap`` you may store zero or one values for ev
|
||||||
|
|
||||||
This library uses a fair bit of unsafe code for several reasons:
|
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).
|
- 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).
|
||||||
|
|
||||||
|
|
42
src/any.rs
42
src/any.rs
|
@ -8,37 +8,37 @@ use std::any::Any as StdAny;
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub trait CloneToAny {
|
pub trait CloneToAny {
|
||||||
/// Clone `self` into a new `Box<CloneAny>` object.
|
/// Clone `self` into a new `Box<dyn CloneAny>` object.
|
||||||
fn clone_to_any(&self) -> Box<CloneAny>;
|
fn clone_to_any(&self) -> Box<dyn CloneAny>;
|
||||||
|
|
||||||
/// Clone `self` into a new `Box<CloneAny + Send>` object.
|
/// Clone `self` into a new `Box<dyn CloneAny + Send>` object.
|
||||||
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;
|
||||||
|
|
||||||
/// Clone `self` into a new `Box<CloneAny + Sync>` object.
|
/// Clone `self` into a new `Box<dyn CloneAny + Sync>` object.
|
||||||
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;
|
||||||
|
|
||||||
/// Clone `self` into a new `Box<CloneAny + Send + Sync>` object.
|
/// Clone `self` into a new `Box<dyn CloneAny + Send + Sync>` object.
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Any + Clone> CloneToAny for T {
|
impl<T: Any + Clone> CloneToAny for T {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clone_to_any(&self) -> Box<CloneAny> {
|
fn clone_to_any(&self) -> Box<dyn CloneAny> {
|
||||||
Box::new(self.clone())
|
Box::new(self.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[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())
|
Box::new(self.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[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())
|
Box::new(self.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[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())
|
Box::new(self.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,14 +108,14 @@ pub trait IntoBox<A: ?Sized + UncheckedAnyExt>: Any {
|
||||||
|
|
||||||
macro_rules! implement {
|
macro_rules! implement {
|
||||||
($base:ident, $(+ $bounds:ident)*) => {
|
($base:ident, $(+ $bounds:ident)*) => {
|
||||||
impl fmt::Debug for $base $(+ $bounds)* {
|
impl fmt::Debug for dyn $base $(+ $bounds)* {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
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]
|
#[inline]
|
||||||
unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T {
|
unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T {
|
||||||
&*(self as *const Self as *const T)
|
&*(self as *const Self as *const T)
|
||||||
|
@ -132,9 +132,9 @@ macro_rules! implement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: $base $(+ $bounds)*> IntoBox<$base $(+ $bounds)*> for T {
|
impl<T: $base $(+ $bounds)*> IntoBox<dyn $base $(+ $bounds)*> for T {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn into_box(self) -> Box<$base $(+ $bounds)*> {
|
fn into_box(self) -> Box<dyn $base $(+ $bounds)*> {
|
||||||
Box::new(self)
|
Box::new(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,7 +152,7 @@ implement!(CloneAny, + Sync);
|
||||||
implement!(CloneAny, + Send + Sync);
|
implement!(CloneAny, + Send + Sync);
|
||||||
|
|
||||||
define!(CloneAny);
|
define!(CloneAny);
|
||||||
impl_clone!(CloneAny, clone_to_any);
|
impl_clone!(dyn CloneAny, clone_to_any);
|
||||||
impl_clone!((CloneAny + Send), clone_to_any_send);
|
impl_clone!(dyn CloneAny + Send, clone_to_any_send);
|
||||||
impl_clone!((CloneAny + Sync), clone_to_any_sync);
|
impl_clone!(dyn CloneAny + Sync, clone_to_any_sync);
|
||||||
impl_clone!((CloneAny + Send + Sync), clone_to_any_send_sync);
|
impl_clone!(dyn CloneAny + Send + Sync, clone_to_any_send_sync);
|
||||||
|
|
50
src/lib.rs
50
src/lib.rs
|
@ -95,7 +95,7 @@ pub mod raw;
|
||||||
/// be `anymap::any::Any`, but there are other choices:
|
/// be `anymap::any::Any`, but there are other choices:
|
||||||
///
|
///
|
||||||
/// - If you want the entire map to be cloneable, use `CloneAny` instead of `Any`.
|
/// - 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
|
/// ```rust
|
||||||
/// # use anymap::AnyMap;
|
/// # use anymap::AnyMap;
|
||||||
|
@ -120,7 +120,7 @@ pub mod raw;
|
||||||
///
|
///
|
||||||
/// Values containing non-static references are not permitted.
|
/// Values containing non-static references are not permitted.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Map<A: ?Sized + UncheckedAnyExt = Any> {
|
pub struct Map<A: ?Sized + UncheckedAnyExt = dyn Any> {
|
||||||
raw: RawMap<A>,
|
raw: RawMap<A>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ impl<A: ?Sized + UncheckedAnyExt> Clone for Map<A> where Box<A>: Clone {
|
||||||
/// Why is this a separate type alias rather than a default value for `Map<A>`? `Map::new()`
|
/// 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.
|
/// 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.
|
/// 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! {
|
impl_common_methods! {
|
||||||
field: Map.raw;
|
field: Map.raw;
|
||||||
|
@ -394,7 +394,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
test_entry!(test_entry_any, AnyMap);
|
test_entry!(test_entry_any, AnyMap);
|
||||||
test_entry!(test_entry_cloneany, Map<CloneAny>);
|
test_entry!(test_entry_cloneany, Map<dyn CloneAny>);
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_default() {
|
fn test_default() {
|
||||||
|
@ -404,7 +404,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_clone() {
|
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(A(1));
|
||||||
let _ = map.insert(B(2));
|
let _ = map.insert(B(2));
|
||||||
let _ = map.insert(D(3));
|
let _ = map.insert(D(3));
|
||||||
|
@ -428,25 +428,25 @@ mod tests {
|
||||||
fn assert_sync<T: Sync>() { }
|
fn assert_sync<T: Sync>() { }
|
||||||
fn assert_clone<T: Clone>() { }
|
fn assert_clone<T: Clone>() { }
|
||||||
fn assert_debug<T: ::std::fmt::Debug>() { }
|
fn assert_debug<T: ::std::fmt::Debug>() { }
|
||||||
assert_send::<Map<Any + Send>>();
|
assert_send::<Map<dyn Any + Send>>();
|
||||||
assert_send::<Map<Any + Send + Sync>>();
|
assert_send::<Map<dyn Any + Send + Sync>>();
|
||||||
assert_sync::<Map<Any + Sync>>();
|
assert_sync::<Map<dyn Any + Sync>>();
|
||||||
assert_sync::<Map<Any + Send + Sync>>();
|
assert_sync::<Map<dyn Any + Send + Sync>>();
|
||||||
assert_debug::<Map<Any>>();
|
assert_debug::<Map<dyn Any>>();
|
||||||
assert_debug::<Map<Any + Send>>();
|
assert_debug::<Map<dyn Any + Send>>();
|
||||||
assert_debug::<Map<Any + Sync>>();
|
assert_debug::<Map<dyn Any + Sync>>();
|
||||||
assert_debug::<Map<Any + Send + Sync>>();
|
assert_debug::<Map<dyn Any + Send + Sync>>();
|
||||||
assert_send::<Map<CloneAny + Send>>();
|
assert_send::<Map<dyn CloneAny + Send>>();
|
||||||
assert_send::<Map<CloneAny + Send + Sync>>();
|
assert_send::<Map<dyn CloneAny + Send + Sync>>();
|
||||||
assert_sync::<Map<CloneAny + Sync>>();
|
assert_sync::<Map<dyn CloneAny + Sync>>();
|
||||||
assert_sync::<Map<CloneAny + Send + Sync>>();
|
assert_sync::<Map<dyn CloneAny + Send + Sync>>();
|
||||||
assert_clone::<Map<CloneAny + Send>>();
|
assert_clone::<Map<dyn CloneAny + Send>>();
|
||||||
assert_clone::<Map<CloneAny + Send + Sync>>();
|
assert_clone::<Map<dyn CloneAny + Send + Sync>>();
|
||||||
assert_clone::<Map<CloneAny + Sync>>();
|
assert_clone::<Map<dyn CloneAny + Sync>>();
|
||||||
assert_clone::<Map<CloneAny + Send + Sync>>();
|
assert_clone::<Map<dyn CloneAny + Send + Sync>>();
|
||||||
assert_debug::<Map<CloneAny>>();
|
assert_debug::<Map<dyn CloneAny>>();
|
||||||
assert_debug::<Map<CloneAny + Send>>();
|
assert_debug::<Map<dyn CloneAny + Send>>();
|
||||||
assert_debug::<Map<CloneAny + Sync>>();
|
assert_debug::<Map<dyn CloneAny + Sync>>();
|
||||||
assert_debug::<Map<CloneAny + Send + Sync>>();
|
assert_debug::<Map<dyn CloneAny + Send + Sync>>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ fn type_id_hasher() {
|
||||||
/// contents of an `Map`. 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)]
|
||||||
pub struct RawMap<A: ?Sized + UncheckedAnyExt = Any> {
|
pub struct RawMap<A: ?Sized + UncheckedAnyExt = dyn Any> {
|
||||||
inner: HashMap<TypeId, Box<A>, BuildHasherDefault<TypeIdHasher>>,
|
inner: HashMap<TypeId, Box<A>, BuildHasherDefault<TypeIdHasher>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue