anymap3/any.rs
1#[cfg(not(feature = "std"))]
2use alloc::boxed::Box;
3use core::any::{Any, TypeId};
4use core::fmt;
5
6#[doc(hidden)]
7pub trait CloneToAny {
8 /// Clone `self` into a new `Box<dyn CloneAny>` object.
9 fn clone_to_any(&self) -> Box<dyn CloneAny>;
10}
11
12impl<T: Any + Clone> CloneToAny for T {
13 #[inline]
14 fn clone_to_any(&self) -> Box<dyn CloneAny> {
15 Box::new(self.clone())
16 }
17}
18
19macro_rules! impl_clone {
20 ($t:ty) => {
21 impl Clone for Box<$t> {
22 #[inline]
23 fn clone(&self) -> Box<$t> {
24 // SAFETY: this dance is to reapply any Send/Sync marker. I’m not happy about this
25 // approach, given that I used to do it in safe code, but then came a dodgy
26 // future-compatibility warning where_clauses_object_safety, which is spurious for
27 // auto traits but still super annoying (future-compatibility lints seem to mean
28 // your bin crate needs a corresponding allow!). Although I explained my plight¹
29 // and it was all explained and agreed upon, no action has been taken. So I finally
30 // caved and worked around it by doing it this way, which matches what’s done for
31 // core::any², so it’s probably not *too* bad.
32 //
33 // ¹ https://github.com/rust-lang/rust/issues/51443#issuecomment-421988013
34 // ² https://github.com/rust-lang/rust/blob/e7825f2b690c9a0d21b6f6d84c404bb53b151b38/library/alloc/src/boxed.rs#L1613-L1616
35 let clone: Box<dyn CloneAny> = (**self).clone_to_any();
36 let raw: *mut dyn CloneAny = Box::into_raw(clone);
37
38 // SAFETY:
39 // There's a future incompat warning ptr_cast_add_auto_to_object tracked in [1]
40 // that warns when you use a pointer cast to add auto traits to a dyn Trait
41 // pointer.
42 //
43 // The issue that it is trying to avoid is that the trait may have methods that
44 // are conditional on the auto traits. e.g.
45 //
46 // #![feature(arbitrary_self_types)]
47 // trait Trait {
48 // fn func(self: *const Self) where Self: Send;
49 // }
50 //
51 // If this happens then the vtable for dyn Trait and the vtable for dyn Trait + Send
52 // may be different and so casting between pointers to each is UB.
53 //
54 // In our case we only care about the CloneAny trait. It has no methods that are
55 // conditional on any auto traits. This means that the vtable will always be the
56 // same and so the future incompatibility lint doesn't apply here.
57 //
58 // So, to avoid the lint, we use a transmute here instead of a pointer cast. As
59 // described in [1], that is the recommended way to suppress the warning.
60 //
61 // [1]: https://github.com/rust-lang/rust/issues/127323
62 unsafe { Box::from_raw(std::mem::transmute::<*mut dyn CloneAny, *mut _>(raw)) }
63 }
64 }
65
66 impl fmt::Debug for $t {
67 #[inline]
68 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69 f.pad(stringify!($t))
70 }
71 }
72 };
73}
74
75/// Methods for downcasting from an `Any`-like trait object.
76///
77/// This should only be implemented on trait objects for subtraits of `Any`, though you can
78/// implement it for other types and it’ll work fine, so long as your implementation is correct.
79pub trait Downcast {
80 /// Gets the `TypeId` of `self`.
81 fn type_id(&self) -> TypeId;
82
83 // Note the bound through these downcast methods is 'static, rather than the inexpressible
84 // concept of Self-but-as-a-trait (where Self is `dyn Trait`). This is sufficient, exceeding
85 // TypeId’s requirements. Sure, you *can* do CloneAny.downcast_unchecked::<NotClone>() and the
86 // type system won’t protect you, but that doesn’t introduce any unsafety: the method is
87 // already unsafe because you can specify the wrong type, and if this were exposing safe
88 // downcasting, CloneAny.downcast::<NotClone>() would just return an error, which is just as
89 // correct.
90 //
91 // Now in theory we could also add T: ?Sized, but that doesn’t play nicely with the common
92 // implementation, so I’m doing without it.
93
94 /// Downcast from `&Any` to `&T`, without checking the type matches.
95 ///
96 /// # Safety
97 ///
98 /// The caller must ensure that `T` matches the trait object, on pain of *undefined behaviour*.
99 unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T;
100
101 /// Downcast from `&mut Any` to `&mut T`, without checking the type matches.
102 ///
103 /// # Safety
104 ///
105 /// The caller must ensure that `T` matches the trait object, on pain of *undefined behaviour*.
106 unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T;
107
108 /// Downcast from `Box<Any>` to `Box<T>`, without checking the type matches.
109 ///
110 /// # Safety
111 ///
112 /// The caller must ensure that `T` matches the trait object, on pain of *undefined behaviour*.
113 unsafe fn downcast_unchecked<T: 'static>(self: Box<Self>) -> Box<T>;
114}
115
116/// A trait for the conversion of an object into a boxed trait object.
117pub trait IntoBox<A: ?Sized + Downcast>: Any {
118 /// Convert self into the appropriate boxed form.
119 fn into_box(self) -> Box<A>;
120}
121
122macro_rules! implement {
123 ($any_trait:ident $(+ $auto_traits:ident)*) => {
124 impl Downcast for dyn $any_trait $(+ $auto_traits)* {
125 #[inline]
126 fn type_id(&self) -> TypeId {
127 self.type_id()
128 }
129
130 #[inline]
131 unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T {
132 &*(self as *const Self as *const T)
133 }
134
135 #[inline]
136 unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T {
137 &mut *(self as *mut Self as *mut T)
138 }
139
140 #[inline]
141 unsafe fn downcast_unchecked<T: 'static>(self: Box<Self>) -> Box<T> {
142 Box::from_raw(Box::into_raw(self) as *mut T)
143 }
144 }
145
146 impl<T: $any_trait $(+ $auto_traits)*> IntoBox<dyn $any_trait $(+ $auto_traits)*> for T {
147 #[inline]
148 fn into_box(self) -> Box<dyn $any_trait $(+ $auto_traits)*> {
149 Box::new(self)
150 }
151 }
152 }
153}
154
155implement!(Any);
156implement!(Any + Send);
157implement!(Any + Send + Sync);
158
159/// [`Any`], but with cloning.
160///
161/// Every type with no non-`'static` references that implements `Clone` implements `CloneAny`.
162/// See [`core::any`] for more details on `Any` in general.
163pub trait CloneAny: Any + CloneToAny {}
164impl<T: Any + Clone> CloneAny for T {}
165implement!(CloneAny);
166implement!(CloneAny + Send);
167implement!(CloneAny + Send + Sync);
168impl_clone!(dyn CloneAny);
169impl_clone!(dyn CloneAny + Send);
170impl_clone!(dyn CloneAny + Send + Sync);