downcast/
lib.rs

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