|
| 1 | +//! Copyright © 2014–2022 Chris Morgan |
| 2 | +//! https://github.com/chris-morgan/anymap/blob/master/COPYING |
| 3 | +//! impl some traits for dyn Any |
| 4 | +use core::any::{Any, TypeId}; |
| 5 | +use core::fmt; |
| 6 | + |
| 7 | +#[doc(hidden)] |
| 8 | +pub trait CloneToAny { |
| 9 | + /// Clone `self` into a new `Box<dyn CloneAny>` object. |
| 10 | + fn clone_to_any(&self) -> Box<dyn CloneAny>; |
| 11 | +} |
| 12 | + |
| 13 | +impl<T: Any + Clone> CloneToAny for T { |
| 14 | + #[inline] |
| 15 | + fn clone_to_any(&self) -> Box<dyn CloneAny> { |
| 16 | + Box::new(self.clone()) |
| 17 | + } |
| 18 | +} |
| 19 | + |
| 20 | +macro_rules! impl_clone { |
| 21 | + ($t:ty) => { |
| 22 | + impl Clone for Box<$t> { |
| 23 | + #[inline] |
| 24 | + fn clone(&self) -> Box<$t> { |
| 25 | + // SAFETY: this dance is to reapply any Send/Sync marker. I’m not happy about this |
| 26 | + // approach, given that I used to do it in safe code, but then came a dodgy |
| 27 | + // future-compatibility warning where_clauses_object_safety, which is spurious for |
| 28 | + // auto traits but still super annoying (future-compatibility lints seem to mean |
| 29 | + // your bin crate needs a corresponding allow!). Although I explained my plight¹ |
| 30 | + // and it was all explained and agreed upon, no action has been taken. So I finally |
| 31 | + // caved and worked around it by doing it this way, which matches what’s done for |
| 32 | + // core::any², so it’s probably not *too* bad. |
| 33 | + // |
| 34 | + // ¹ https://github.com/rust-lang/rust/issues/51443#issuecomment-421988013 |
| 35 | + // ² https://github.com/rust-lang/rust/blob/e7825f2b690c9a0d21b6f6d84c404bb53b151b38/library/alloc/src/boxed.rs#L1613-L1616 |
| 36 | + let clone: Box<dyn CloneAny> = (**self).clone_to_any(); |
| 37 | + let raw: *mut dyn CloneAny = Box::into_raw(clone); |
| 38 | + unsafe { Box::from_raw(raw as *mut $t) } |
| 39 | + } |
| 40 | + } |
| 41 | + |
| 42 | + impl fmt::Debug for $t { |
| 43 | + #[inline] |
| 44 | + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 45 | + f.pad(stringify!($t)) |
| 46 | + } |
| 47 | + } |
| 48 | + }; |
| 49 | +} |
| 50 | + |
| 51 | +/// Methods for downcasting from an `Any`-like trait object. |
| 52 | +/// |
| 53 | +/// This should only be implemented on trait objects for subtraits of `Any`, though you can |
| 54 | +/// implement it for other types and it’ll work fine, so long as your implementation is correct. |
| 55 | +pub trait Downcast { |
| 56 | + /// Gets the `TypeId` of `self`. |
| 57 | + fn type_id(&self) -> TypeId; |
| 58 | + |
| 59 | + // Note the bound through these downcast methods is 'static, rather than the inexpressible |
| 60 | + // concept of Self-but-as-a-trait (where Self is `dyn Trait`). This is sufficient, exceeding |
| 61 | + // TypeId’s requirements. Sure, you *can* do CloneAny.downcast_unchecked::<NotClone>() and the |
| 62 | + // type system won’t protect you, but that doesn’t introduce any unsafety: the method is |
| 63 | + // already unsafe because you can specify the wrong type, and if this were exposing safe |
| 64 | + // downcasting, CloneAny.downcast::<NotClone>() would just return an error, which is just as |
| 65 | + // correct. |
| 66 | + // |
| 67 | + // Now in theory we could also add T: ?Sized, but that doesn’t play nicely with the common |
| 68 | + // implementation, so I’m doing without it. |
| 69 | + |
| 70 | + /// Downcast from `&Any` to `&T`, without checking the type matches. |
| 71 | + /// |
| 72 | + /// # Safety |
| 73 | + /// |
| 74 | + /// The caller must ensure that `T` matches the trait object, on pain of *undefined behaviour*. |
| 75 | + unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T; |
| 76 | + |
| 77 | + /// Downcast from `&mut Any` to `&mut T`, without checking the type matches. |
| 78 | + /// |
| 79 | + /// # Safety |
| 80 | + /// |
| 81 | + /// The caller must ensure that `T` matches the trait object, on pain of *undefined behaviour*. |
| 82 | + unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T; |
| 83 | +} |
| 84 | + |
| 85 | +/// A trait for the conversion of an object into a boxed trait object. |
| 86 | +pub trait IntoBox<A: ?Sized + Downcast>: Any { |
| 87 | + /// Convert self into the appropriate boxed form. |
| 88 | + fn into_box(self) -> Box<A>; |
| 89 | +} |
| 90 | + |
| 91 | +macro_rules! implement { |
| 92 | + ($any_trait:ident $(+ $auto_traits:ident)*) => { |
| 93 | + impl Downcast for dyn $any_trait $(+ $auto_traits)* { |
| 94 | + #[inline] |
| 95 | + fn type_id(&self) -> TypeId { |
| 96 | + self.type_id() |
| 97 | + } |
| 98 | + |
| 99 | + #[inline] |
| 100 | + unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T { |
| 101 | + &*(self as *const Self as *const T) |
| 102 | + } |
| 103 | + |
| 104 | + #[inline] |
| 105 | + unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T { |
| 106 | + &mut *(self as *mut Self as *mut T) |
| 107 | + } |
| 108 | + } |
| 109 | + |
| 110 | + impl<T: $any_trait $(+ $auto_traits)*> IntoBox<dyn $any_trait $(+ $auto_traits)*> for T { |
| 111 | + #[inline] |
| 112 | + fn into_box(self) -> Box<dyn $any_trait $(+ $auto_traits)*> { |
| 113 | + Box::new(self) |
| 114 | + } |
| 115 | + } |
| 116 | + } |
| 117 | +} |
| 118 | + |
| 119 | +implement!(Any); |
| 120 | +implement!(Any + Send); |
| 121 | +implement!(Any + Send + Sync); |
| 122 | + |
| 123 | +/// [`Any`], but with cloning. |
| 124 | +/// |
| 125 | +/// Every type with no non-`'static` references that implements `Clone` implements `CloneAny`. |
| 126 | +/// See [`core::any`] for more details on `Any` in general. |
| 127 | +pub trait CloneAny: Any + CloneToAny {} |
| 128 | +impl<T: Any + Clone> CloneAny for T {} |
| 129 | +implement!(CloneAny); |
| 130 | +implement!(CloneAny + Send); |
| 131 | +implement!(CloneAny + Send + Sync); |
| 132 | +impl_clone!(dyn CloneAny); |
| 133 | +impl_clone!(dyn CloneAny + Send); |
| 134 | +impl_clone!(dyn CloneAny + Send + Sync); |
0 commit comments