1#![cfg_attr(not(feature = "std"), no_std)]
2#![cfg_attr(feature = "nightly", feature(core_intrinsics, try_from))]
3
4#[cfg(not(feature = "std"))]
5mod std {
6 pub use core::*;
7}
8
9use std::any::Any as StdAny;
10use std::any::TypeId;
11#[cfg(feature = "nightly")]
12use std::convert::TryFrom;
13#[cfg(feature = "std")]
14use std::error::Error;
15#[cfg(feature = "nightly")]
16use std::intrinsics;
17use std::fmt::{self, Debug, Display};
18use std::mem;
19
20#[cfg(feature = "nightly")]
23fn type_name<T: StdAny + ?Sized>() -> &'static str { unsafe { intrinsics::type_name::<T>() } }
24#[cfg(not(feature = "nightly"))]
25fn type_name<T: StdAny + ?Sized>() -> &'static str { "[ONLY ON NIGHTLY]" }
26
27pub trait Any: StdAny {
28 fn type_id_compat(&self) -> TypeId { TypeId::of::<Self>() }
32 #[doc(hidden)]
33 fn type_name(&self) -> &'static str { type_name::<Self>() }
34}
35
36impl<T> Any for T where T: StdAny + ?Sized {}
37
38#[derive(Debug, Clone, Copy)]
41pub struct TypeMismatch {
42 expected: &'static str,
43 found: &'static str,
44}
45
46impl TypeMismatch {
47 pub fn new<T, O>(found_obj: &O) -> Self
48 where T: Any + ?Sized, O: Any + ?Sized
49 {
50 TypeMismatch {
51 expected: type_name::<T>(),
52 found: found_obj.type_name(),
53 }
54 }
55}
56
57impl Display for TypeMismatch {
58 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
59 write!(fmt, "Type mismatch: Expected '{}', found '{}'!", self.expected, self.found)
60 }
61}
62
63#[cfg(feature = "std")]
64impl Error for TypeMismatch {
65 fn description(&self) -> &str { "Type mismatch" }
66}
67
68pub struct DowncastError<O> {
71 mismatch: TypeMismatch,
72 object: O,
73}
74
75impl<O> DowncastError<O> {
76 pub fn new(mismatch: TypeMismatch, object: O) -> Self {
77 Self {
78 mismatch: mismatch,
79 object: object,
80 }
81 }
82 pub fn type_mismatch(&self) -> TypeMismatch { self.mismatch }
83 pub fn into_object(self) -> O { self.object }
84}
85
86impl<O> Debug for DowncastError<O> {
87 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
88 fmt.debug_struct("DowncastError")
89 .field("mismatch", &self.mismatch)
90 .finish()
91 }
92}
93
94impl<O> Display for DowncastError<O> {
95 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
96 Display::fmt(&self.mismatch, fmt)
97 }
98}
99
100#[cfg(feature = "std")]
101impl<O> Error for DowncastError<O> {
102 fn description(&self) -> &str { self.mismatch.description() }
103}
104
105#[derive(Clone, Copy)]
108struct TraitObject {
109 pub data: *mut (),
110 pub vtable: *mut (),
111}
112
113#[inline]
114fn to_trait_object<T: ?Sized>(obj: &T) -> TraitObject {
115 assert_eq!(mem::size_of::<&T>(), mem::size_of::<TraitObject>());
116 unsafe { *((&obj) as *const &T as *const TraitObject) }
117}
118
119pub trait Downcast<T>: Any
120 where T: Any
121{
122 fn is_type(&self) -> bool { self.type_id_compat() == TypeId::of::<T>() }
123
124 unsafe fn downcast_ref_unchecked(&self) -> &T { &*(to_trait_object(self).data as *mut T) }
125
126 fn downcast_ref(&self) -> Result<&T, TypeMismatch> {
127 if self.is_type() {
128 Ok(unsafe { self.downcast_ref_unchecked() })
129 } else {
130 Err(TypeMismatch::new::<T, Self>(self))
131 }
132 }
133
134 unsafe fn downcast_mut_unchecked(&mut self) -> &mut T {
135 &mut *(to_trait_object(self).data as *mut T)
136 }
137
138 fn downcast_mut(&mut self) -> Result<&mut T, TypeMismatch> {
139 if self.is_type() {
140 Ok(unsafe { self.downcast_mut_unchecked() })
141 } else {
142 Err(TypeMismatch::new::<T, Self>(self))
143 }
144 }
145
146 #[cfg(feature = "std")]
147 unsafe fn downcast_unchecked(self: Box<Self>) -> Box<T> {
148 let ret: Box<T> = Box::from_raw(to_trait_object(&*self).data as *mut T);
149 mem::forget(self);
150 ret
151 }
152
153 #[cfg(feature = "std")]
154 fn downcast(self: Box<Self>) -> Result<Box<T>, DowncastError<Box<Self>>> {
155 if self.is_type() {
156 Ok(unsafe { self.downcast_unchecked() })
157 } else {
158 let mismatch = TypeMismatch::new::<T, Self>(&*self);
159 Err(DowncastError::new(mismatch, self))
160 }
161 }
162}
163
164#[doc(hidden)]
167pub mod _std {
168 pub use std::*;
169}
170
171#[macro_export]
195macro_rules! impl_downcast {
196 (<$($params:ident),+ $(,)*> $base:ty $(where $($bounds:tt)+)*) => {
197 impl<_T: $crate::Any, $($params),+> $crate::Downcast<_T> for $base
198 where _T: $crate::Any, $($params: 'static,)* $($($bounds)+)*
199 {}
200 };
201 ($base:ty) => {
202 impl<_T: $crate::Any> $crate::Downcast<_T> for $base
203 where _T: $crate::Any
204 {}
205 };
206}
207
208#[doc(hidden)]
209#[macro_export]
210macro_rules! downcast_methods_core {
211 (@items) => {
212 #[allow(unused)]
213 pub fn is<_T>(&self) -> bool
214 where _T: $crate::Any, Self: $crate::Downcast<_T>
215 {
216 $crate::Downcast::<_T>::is_type(self)
217 }
218
219 #[allow(unused)]
220 pub unsafe fn downcast_ref_unchecked<_T>(&self) -> &_T
221 where _T: $crate::Any, Self: $crate::Downcast<_T>
222 {
223 $crate::Downcast::<_T>::downcast_ref_unchecked(self)
224 }
225
226 #[allow(unused)]
227 pub fn downcast_ref<_T>(&self) -> $crate::_std::result::Result<&_T, $crate::TypeMismatch>
228 where _T: $crate::Any, Self: $crate::Downcast<_T>
229 {
230 $crate::Downcast::<_T>::downcast_ref(self)
231 }
232
233 #[allow(unused)]
234 pub unsafe fn downcast_mut_unchecked<_T>(&mut self) -> &mut _T
235 where _T: $crate::Any, Self: $crate::Downcast<_T>
236 {
237 $crate::Downcast::<_T>::downcast_mut_unchecked(self)
238 }
239
240 #[allow(unused)]
241 pub fn downcast_mut<_T>(&mut self) -> $crate::_std::result::Result<&mut _T, $crate::TypeMismatch>
242 where _T: $crate::Any, Self: $crate::Downcast<_T>
243 {
244 $crate::Downcast::<_T>::downcast_mut(self)
245 }
246 };
247 (<$($params:ident),+ $(,)*> $base:ty $(where $($bounds:tt)+)*) => {
248 impl<$($params),+> $base
249 where $($params: 'static,)* $($($bounds)+)*
250 {
251 downcast_methods_core!(@items);
252 }
253 };
254 ($base:ty) => {
255 impl $base {
256 downcast_methods_core!(@items);
257 }
258 };
259}
260
261#[doc(hidden)]
262#[macro_export]
263macro_rules! downcast_methods_std {
264 (@items) => {
265 downcast_methods_core!(@items);
266
267 #[allow(unused)]
268 pub unsafe fn downcast_unchecked<_T>(self: $crate::_std::boxed::Box<Self>) -> $crate::_std::boxed::Box<_T>
269 where _T: $crate::Any, Self: $crate::Downcast<_T>
270 {
271 $crate::Downcast::<_T>::downcast_unchecked(self)
272 }
273
274 #[allow(unused)]
275 pub fn downcast<_T>(self: $crate::_std::boxed::Box<Self>) -> $crate::_std::result::Result<$crate::_std::boxed::Box<_T>, $crate::DowncastError<Box<Self>>>
276 where _T: $crate::Any, Self: $crate::Downcast<_T>
277 {
278 $crate::Downcast::<_T>::downcast(self)
279 }
280 };
281 (<$($params:ident),+ $(,)*> $base:ty $(where $($bounds:tt)+)*) => {
282 impl<$($params),+> $base
283 $(where $($bounds)+)*
284 {
285 downcast_methods_std!(@items);
286 }
287 };
288 ($base:ty) => {
289 impl $base {
290 downcast_methods_std!(@items);
291 }
292 };
293}
294
295#[cfg(not(feature = "std"))]
334#[macro_export]
335macro_rules! downcast_methods {
336 ($($tt:tt)+) => { downcast_methods_core!($($tt)+); }
337}
338
339#[cfg(feature = "std")]
383#[macro_export]
384macro_rules! downcast_methods {
385 ($($tt:tt)+) => { downcast_methods_std!($($tt)+); }
386}
387
388#[macro_export]
394macro_rules! downcast {
395 ($($tt:tt)+) => {
396 impl_downcast!($($tt)+);
397 downcast_methods!($($tt)+);
398 }
399}
400
401mod any_impls {
404 use super::Any;
405
406 impl_downcast!(Any);
407 impl_downcast!((Any + Send));
408 impl_downcast!((Any + Sync));
409 impl_downcast!((Any + Send + Sync));
410}