1#![cfg_attr(not(feature = "std"), no_std)]
2
3#[cfg(not(feature = "std"))]
4mod std {
5 pub use core::*;
6}
7
8use std::any::{Any as StdAny, TypeId, type_name};
9use std::fmt::{self, Debug, Display};
10
11#[cfg(feature = "std")]
12use std::{error::Error, rc::Rc, sync::Arc};
13
14// ++++++++++++++++++++ Any ++++++++++++++++++++
15
16pub trait Any: StdAny {
17 #[doc(hidden)]
18 fn as_any(&self) -> &dyn StdAny;
19
20 #[doc(hidden)]
21 fn as_any_mut(&mut self) -> &mut dyn StdAny;
22
23 #[doc(hidden)]
24 #[cfg(feature = "std")]
25 fn into_any(self: Box<Self>) -> Box<dyn StdAny>;
26
27 #[doc(hidden)]
28 #[cfg(feature = "std")]
29 fn into_any_rc(self: Rc<Self>) -> Rc<dyn StdAny>;
30
31 fn type_name(&self) -> &'static str;
32}
33
34impl<T> Any for T where T: StdAny {
35 #[doc(hidden)]
36 fn as_any(&self) -> &dyn StdAny { self }
37
38 #[doc(hidden)]
39 fn as_any_mut(&mut self) -> &mut dyn StdAny { self }
40
41 #[cfg(feature = "std")]
42 fn into_any(self: Box<Self>) -> Box<dyn StdAny> { self }
43
44 #[cfg(feature = "std")]
45 fn into_any_rc(self: Rc<Self>) -> Rc<dyn StdAny> { self }
46
47 fn type_name(&self) -> &'static str { type_name::<Self>() }
48}
49
50#[cfg(feature = "std")]
51pub trait AnySync: Any + Send + Sync {
52 fn into_any_arc(self: Arc<Self>) -> Arc<dyn StdAny + Send + Sync>;
53}
54
55#[cfg(feature = "std")]
56impl<T> AnySync for T where T: Any + Send + Sync {
57 fn into_any_arc(self: Arc<Self>) -> Arc<dyn StdAny + Send + Sync> { self }
58}
59
60// ++++++++++++++++++++ TypeMismatch ++++++++++++++++++++
61
62#[derive(Debug, Clone, Copy)]
63pub struct TypeMismatch {
64 pub expected: &'static str,
65 pub found: &'static str,
66}
67
68impl TypeMismatch {
69 pub fn new<T, O>(found_obj: &O) -> Self
70 where T: Any + ?Sized, O: Any + ?Sized
71 {
72 TypeMismatch {
73 expected: type_name::<T>(),
74 found: found_obj.type_name(),
75 }
76 }
77}
78
79impl Display for TypeMismatch {
80 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
81 write!(fmt, "Type mismatch: Expected '{}', found '{}'!", self.expected, self.found)
82 }
83}
84
85#[cfg(feature = "std")]
86impl Error for TypeMismatch {}
87
88// ++++++++++++++++++++ DowncastError ++++++++++++++++++++
89
90pub struct DowncastError<O> {
91 mismatch: TypeMismatch,
92 object: O,
93}
94
95impl<O> DowncastError<O> {
96 pub fn new(mismatch: TypeMismatch, object: O) -> Self {
97 Self{ mismatch, object }
98 }
99 pub fn type_mismatch(&self) -> TypeMismatch { self.mismatch }
100 pub fn into_object(self) -> O { self.object }
101}
102
103impl<O> Debug for DowncastError<O> {
104 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
105 fmt.debug_struct("DowncastError")
106 .field("mismatch", &self.mismatch)
107 .finish()
108 }
109}
110
111impl<O> Display for DowncastError<O> {
112 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
113 Display::fmt(&self.mismatch, fmt)
114 }
115}
116
117#[cfg(feature = "std")]
118impl<O> Error for DowncastError<O> {}
119
120// ++++++++++++++++++++ Downcast ++++++++++++++++++++
121
122pub trait Downcast<T>: Any
123 where T: Any
124{
125 fn is_type(&self) -> bool { self.type_id() == TypeId::of::<T>() }
126
127 fn downcast_ref(&self) -> Result<&T, TypeMismatch> {
128 if self.is_type() {
129 Ok(self.as_any().downcast_ref().unwrap())
130 } else {
131 Err(TypeMismatch::new::<T, Self>(self))
132 }
133 }
134
135 fn downcast_mut(&mut self) -> Result<&mut T, TypeMismatch> {
136 if self.is_type() {
137 Ok(self.as_any_mut().downcast_mut().unwrap())
138 } else {
139 Err(TypeMismatch::new::<T, Self>(self))
140 }
141 }
142
143 #[cfg(feature = "std")]
144 fn downcast(self: Box<Self>) -> Result<Box<T>, DowncastError<Box<Self>>> {
145 if self.is_type() {
146 Ok(self.into_any().downcast().unwrap())
147 } else {
148 let mismatch = TypeMismatch::new::<T, Self>(&*self);
149 Err(DowncastError::new(mismatch, self))
150 }
151 }
152
153 #[cfg(feature = "std")]
154 fn downcast_rc(self: Rc<Self>) -> Result<Rc<T>, DowncastError<Rc<Self>>> {
155 if self.is_type() {
156 Ok(self.into_any_rc().downcast().unwrap())
157 } else {
158 let mismatch = TypeMismatch::new::<T, Self>(&*self);
159 Err(DowncastError::new(mismatch, self))
160 }
161 }
162}
163
164#[cfg(feature = "std")]
165pub trait DowncastSync<T>: Downcast<T> + AnySync
166 where T: AnySync
167{
168 fn downcast_arc(self: Arc<Self>) -> Result<Arc<T>, DowncastError<Arc<Self>>> {
169 if self.is_type() {
170 Ok(self.into_any_arc().downcast().unwrap())
171 } else {
172 let mismatch = TypeMismatch::new::<T, Self>(&*self);
173 Err(DowncastError::new(mismatch, self))
174 }
175 }
176}
177
178// ++++++++++++++++++++ macros ++++++++++++++++++++
179
180#[doc(hidden)]
181pub mod _std {
182 #[cfg(feature = "std")]
183 pub use std::*;
184 #[cfg(not(feature = "std"))]
185 pub use core::*;
186}
187
188/// Implements [`Downcast`](trait.Downcast.html) for your trait-object-type.
189///
190/// ```ignore
191/// impl_downcast!(Foo);
192/// impl_downcast!(<B> Foo<B> where B: Bar);
193/// impl_downcast!(<B> Foo<Bar = B>);
194/// ```
195///
196/// expands to
197///
198/// ```ignore
199/// impl<T> Downcast<T> for Foo
200/// where T: Any
201/// {}
202///
203/// impl<T, B> Downcast<T> for Foo<B>
204/// where T: Any, B: Bar
205/// {}
206///
207/// impl<T, B> Downcast<T> for Foo<Bar = B>
208/// where T: Any
209/// {}
210/// ```
211#[macro_export]
212macro_rules! impl_downcast {
213 (<$($params:ident),+ $(,)*> $base:ty $(where $($bounds:tt)+)*) => {
214 impl<_T, $($params),+> $crate::Downcast<_T> for $base
215 where _T: $crate::Any, $($params: 'static,)* $($($bounds)+)*
216 {}
217 };
218 ($base:ty) => {
219 impl<_T> $crate::Downcast<_T> for $base
220 where _T: $crate::Any
221 {}
222 };
223}
224
225/// Implements [`Downcast`](trait.Downcast.html) and [`DowncastSync`](trait.DowncastSync.html) for your trait-object-type.
226#[cfg(feature = "std")]
227#[macro_export]
228macro_rules! impl_downcast_sync {
229 (<$($params:ident),+ $(,)*> $base:ty $(where $($bounds:tt)+)*) => {
230 impl<_T, $($params),+> $crate::Downcast<_T> for $base
231 where _T: $crate::Any, $($params: 'static,)* $($($bounds)+)*
232 {}
233
234 impl<_T, $($params),+> $crate::DowncastSync<_T> for $base
235 where _T: $crate::AnySync, $($params: 'static,)* $($($bounds)+)*
236 {}
237 };
238 ($base:ty) => {
239 impl<_T> $crate::Downcast<_T> for $base
240 where _T: $crate::Any
241 {}
242
243 impl<_T> $crate::DowncastSync<_T> for $base
244 where _T: $crate::AnySync
245 {}
246 };
247}
248
249#[doc(hidden)]
250#[macro_export]
251macro_rules! downcast_methods_core {
252 (@items) => {
253 #[allow(unused, missing_docs)]
254 pub fn is<_T>(&self) -> bool
255 where _T: $crate::Any, Self: $crate::Downcast<_T>
256 {
257 $crate::Downcast::<_T>::is_type(self)
258 }
259
260 #[allow(unused, missing_docs)]
261 pub fn downcast_ref<_T>(&self) -> $crate::_std::result::Result<&_T, $crate::TypeMismatch>
262 where _T: $crate::Any, Self: $crate::Downcast<_T>
263 {
264 $crate::Downcast::<_T>::downcast_ref(self)
265 }
266
267 #[allow(unused, missing_docs)]
268 pub fn downcast_mut<_T>(&mut self) -> $crate::_std::result::Result<&mut _T, $crate::TypeMismatch>
269 where _T: $crate::Any, Self: $crate::Downcast<_T>
270 {
271 $crate::Downcast::<_T>::downcast_mut(self)
272 }
273 };
274 (<$($params:ident),+ $(,)*> $base:ty $(where $($bounds:tt)+)*) => {
275 impl<$($params),+> $base
276 where $($params: 'static,)* $($($bounds)+)*
277 {
278 $crate::downcast_methods_core!(@items);
279 }
280 };
281 ($base:ty) => {
282 impl $base {
283 $crate::downcast_methods_core!(@items);
284 }
285 };
286}
287
288#[doc(hidden)]
289#[macro_export]
290macro_rules! downcast_methods_std {
291 (@items) => {
292 $crate::downcast_methods_core!(@items);
293
294 #[allow(unused, missing_docs)]
295 pub fn downcast<_T>(self: $crate::_std::boxed::Box<Self>) -> $crate::_std::result::Result<$crate::_std::boxed::Box<_T>, $crate::DowncastError<$crate::_std::boxed::Box<Self>>>
296 where _T: $crate::Any, Self: $crate::Downcast<_T>
297 {
298 $crate::Downcast::<_T>::downcast(self)
299 }
300
301 #[allow(unused, missing_docs)]
302 pub fn downcast_rc<_T>(self: $crate::_std::rc::Rc<Self>) -> $crate::_std::result::Result<$crate::_std::rc::Rc<_T>, $crate::DowncastError<$crate::_std::rc::Rc<Self>>>
303 where _T: $crate::Any, Self: $crate::Downcast<_T>
304 {
305 $crate::Downcast::<_T>::downcast_rc(self)
306 }
307 };
308 (<$($params:ident),+ $(,)*> $base:ty $(where $($bounds:tt)+)*) => {
309 impl<$($params),+> $base
310 $(where $($bounds)+)*
311 {
312 $crate::downcast_methods_std!(@items);
313 }
314 };
315 ($base:ty) => {
316 impl $base {
317 $crate::downcast_methods_std!(@items);
318 }
319 };
320}
321
322#[doc(hidden)]
323#[cfg(feature = "std")]
324#[macro_export]
325macro_rules! downcast_sync_methods {
326 (@items) => {
327 $crate::downcast_methods_std!(@items);
328
329 #[allow(unused, missing_docs)]
330 pub fn downcast_arc<_T>(self: $crate::_std::sync::Arc<Self>) -> $crate::_std::result::Result<$crate::_std::sync::Arc<_T>, $crate::DowncastError<$crate::_std::sync::Arc<Self>>>
331 where _T: $crate::AnySync, Self: $crate::DowncastSync<_T>
332 {
333 $crate::DowncastSync::<_T>::downcast_arc(self)
334 }
335 };
336 (<$($params:ident),+ $(,)*> $base:ty $(where $($bounds:tt)+)*) => {
337 impl<$($params),+> $base
338 $(where $($bounds)+)*
339 {
340 $crate::downcast_sync_methods!(@items);
341 }
342 };
343 ($base:ty) => {
344 impl $base {
345 $crate::downcast_sync_methods!(@items);
346 }
347 };
348}
349
350
351/// Generate `downcast`-methods for your trait-object-type.
352///
353/// ```ignore
354/// downcast_methods!(Foo);
355/// downcast_methods!(<B> Foo<B> where B: Bar);
356/// downcast_methods!(<B> Foo<Bar = B>);
357/// ```
358///
359/// ```ignore
360/// impl dyn Foo {
361/// /* impl<B> dyn Foo<B> where B: Bar { */
362/// /* impl<B> dyn Foo<Bar = B> { */
363///
364/// pub fn is<T>(&self) -> bool
365/// where T: Any, Self: Downcast<T>
366/// { ... }
367///
368/// pub fn downcast_ref<T>(&self) -> Result<&T, TypeMismatch>
369/// where T: Any, Self: Downcast<T>
370/// { ... }
371///
372/// pub fn downcast_mut<T>(&mut self) -> Result<&mut T, TypeMismatch>
373/// where T: Any, Self: Downcast<T>
374/// { ... }
375/// }
376/// ```
377#[cfg(not(feature = "std"))]
378#[macro_export]
379macro_rules! downcast_methods {
380 ($($tt:tt)+) => { $crate::downcast_methods_core!($($tt)+); }
381}
382
383/// Generate `downcast`-methods for your trait-object-type.
384///
385/// ```ignore
386/// downcast_methods!(Foo);
387/// downcast_methods!(<B> Foo<B> where B: Bar);
388/// downcast_methods!(<B> Foo<Bar = B>);
389/// ```
390///
391/// ```ignore
392/// impl dyn Foo {
393/// /* impl<B> dyn Foo<B> where B: Bar { */
394/// /* impl<B> dyn Foo<Bar = B> { */
395///
396/// pub fn is<T>(&self) -> bool
397/// where T: Any, Self: Downcast<T>
398/// { ... }
399///
400/// pub fn downcast_ref<T>(&self) -> Result<&T, TypeMismatch>
401/// where T: Any, Self: Downcast<T>
402/// { ... }
403///
404/// pub fn downcast_mut<T>(&mut self) -> Result<&mut T, TypeMismatch>
405/// where T: Any, Self: Downcast<T>
406/// { ... }
407///
408/// pub fn downcast<T>(self: Box<Self>) -> Result<Box<T>, DowncastError<Box<T>>>
409/// where T: Any, Self: Downcast<T>
410/// { ... }
411/// }
412/// ```
413#[cfg(feature = "std")]
414#[macro_export]
415macro_rules! downcast_methods {
416 ($($tt:tt)+) => { $crate::downcast_methods_std!($($tt)+); }
417}
418
419/// Implements [`Downcast`](trait.Downcast.html) and generates
420/// `downcast`-methods for your trait-object-type.
421///
422/// See [`impl_downcast`](macro.impl_downcast.html),
423/// [`downcast_methods`](macro.downcast_methods.html).
424#[macro_export]
425macro_rules! downcast {
426 ($($tt:tt)+) => {
427 $crate::impl_downcast!($($tt)+);
428 $crate::downcast_methods!($($tt)+);
429 }
430}
431
432/// Implements [`DowncastSync`](trait.DowncastSync.html) and generates
433/// `downcast`-methods for your trait-object-type.
434///
435/// See [`impl_downcast_sync`](macro.impl_downcast.html),
436/// [`downcast_sync_methods`](macro.downcast_methods.html).
437#[cfg(feature = "std")]
438#[macro_export]
439macro_rules! downcast_sync {
440 ($($tt:tt)+) => {
441 $crate::impl_downcast_sync!($($tt)+);
442 $crate::downcast_sync_methods!($($tt)+);
443 }
444}
445
446// NOTE: We only implement the trait, because implementing the methods won't
447// be possible when we replace downcast::Any by std::any::Any.
448downcast!(dyn Any);
449downcast!((dyn Any + Send));
450downcast!((dyn Any + Sync));
451#[cfg(feature = "std")]
452downcast_sync!(dyn AnySync);
453
454