1 #![deny(unsafe_code,rustdoc::bare_urls)]
2 #![cfg_attr(not(feature = "std"), no_std)]
3 //! [![Build status](https://img.shields.io/github/actions/workflow/status/marcianx/downcast-rs/main.yml?branch=master)](https://github.com/marcianx/downcast-rs/actions)
4 //! [![Latest version](https://img.shields.io/crates/v/downcast-rs.svg)](https://crates.io/crates/downcast-rs)
5 //! [![Documentation](https://docs.rs/downcast-rs/badge.svg)](https://docs.rs/downcast-rs)
6 //!
7 //! Rust enums are great for types where all variations are known beforehand. But a
8 //! container of user-defined types requires an open-ended type like a **trait
9 //! object**. Some applications may want to cast these trait objects back to the
10 //! original concrete types to access additional functionality and performant
11 //! inlined implementations.
12 //!
13 //! `downcast-rs` adds this downcasting support to trait objects using only safe
14 //! Rust. It supports **type parameters**, **associated types**, and **constraints**.
15 //!
16 //! # Usage
17 //!
18 //! Add the following to your `Cargo.toml`:
19 //!
20 //! ```toml
21 //! [dependencies]
22 //! downcast-rs = "1.2.1"
23 //! ```
24 //!
25 //! This crate is `no_std` compatible. To use it without `std`:
26 //!
27 //! ```toml
28 //! [dependencies]
29 //! downcast-rs = { version = "1.2.0", default-features = false }
30 //! ```
31 //!
32 //! To make a trait downcastable, make it extend either `downcast::Downcast` or
33 //! `downcast::DowncastSync` and invoke `impl_downcast!` on it as in the examples
34 //! below.
35 //!
36 //! Since 1.2.0, the minimum supported Rust version is 1.36 due to needing stable access to alloc.
37 //!
38 //! ```
39 //! # #[macro_use]
40 //! # extern crate downcast_rs;
41 //! # use downcast_rs::{Downcast, DowncastSync};
42 //! trait Trait: Downcast {}
43 //! impl_downcast!(Trait);
44 //!
45 //! // Also supports downcasting `Arc`-ed trait objects by extending `DowncastSync`
46 //! // and starting `impl_downcast!` with `sync`.
47 //! trait TraitSync: DowncastSync {}
48 //! impl_downcast!(sync TraitSync);
49 //!
50 //! // With type parameters.
51 //! trait TraitGeneric1<T>: Downcast {}
52 //! impl_downcast!(TraitGeneric1<T>);
53 //!
54 //! // With associated types.
55 //! trait TraitGeneric2: Downcast { type G; type H; }
56 //! impl_downcast!(TraitGeneric2 assoc G, H);
57 //!
58 //! // With constraints on types.
59 //! trait TraitGeneric3<T: Copy>: Downcast {
60 //!     type H: Clone;
61 //! }
62 //! impl_downcast!(TraitGeneric3<T> assoc H where T: Copy, H: Clone);
63 //!
64 //! // With concrete types.
65 //! trait TraitConcrete1<T: Copy>: Downcast {}
66 //! impl_downcast!(concrete TraitConcrete1<u32>);
67 //!
68 //! trait TraitConcrete2<T: Copy>: Downcast { type H; }
69 //! impl_downcast!(concrete TraitConcrete2<u32> assoc H=f64);
70 //! # fn main() {}
71 //! ```
72 //!
73 //! # Example without generics
74 //!
75 //! ```
76 //! # use std::rc::Rc;
77 //! # use std::sync::Arc;
78 //! // Import macro via `macro_use` pre-1.30.
79 //! #[macro_use]
80 //! extern crate downcast_rs;
81 //! use downcast_rs::DowncastSync;
82 //!
83 //! // To create a trait with downcasting methods, extend `Downcast` or `DowncastSync`
84 //! // and run `impl_downcast!()` on the trait.
85 //! trait Base: DowncastSync {}
86 //! impl_downcast!(sync Base);  // `sync` => also produce `Arc` downcasts.
87 //!
88 //! // Concrete types implementing Base.
89 //! #[derive(Debug)]
90 //! struct Foo(u32);
91 //! impl Base for Foo {}
92 //! #[derive(Debug)]
93 //! struct Bar(f64);
94 //! impl Base for Bar {}
95 //!
96 //! fn main() {
97 //!     // Create a trait object.
98 //!     let mut base: Box<Base> = Box::new(Foo(42));
99 //!
100 //!     // Try sequential downcasts.
101 //!     if let Some(foo) = base.downcast_ref::<Foo>() {
102 //!         assert_eq!(foo.0, 42);
103 //!     } else if let Some(bar) = base.downcast_ref::<Bar>() {
104 //!         assert_eq!(bar.0, 42.0);
105 //!     }
106 //!
107 //!     assert!(base.is::<Foo>());
108 //!
109 //!     // Fail to convert `Box<Base>` into `Box<Bar>`.
110 //!     let res = base.downcast::<Bar>();
111 //!     assert!(res.is_err());
112 //!     let base = res.unwrap_err();
113 //!     // Convert `Box<Base>` into `Box<Foo>`.
114 //!     assert_eq!(42, base.downcast::<Foo>().map_err(|_| "Shouldn't happen.").unwrap().0);
115 //!
116 //!     // Also works with `Rc`.
117 //!     let mut rc: Rc<Base> = Rc::new(Foo(42));
118 //!     assert_eq!(42, rc.downcast_rc::<Foo>().map_err(|_| "Shouldn't happen.").unwrap().0);
119 //!
120 //!     // Since this trait is `Sync`, it also supports `Arc` downcasts.
121 //!     let mut arc: Arc<Base> = Arc::new(Foo(42));
122 //!     assert_eq!(42, arc.downcast_arc::<Foo>().map_err(|_| "Shouldn't happen.").unwrap().0);
123 //! }
124 //! ```
125 //!
126 //! # Example with a generic trait with associated types and constraints
127 //!
128 //! ```
129 //! // Can call macro via namespace since rust 1.30.
130 //! extern crate downcast_rs;
131 //! use downcast_rs::Downcast;
132 //!
133 //! // To create a trait with downcasting methods, extend `Downcast` or `DowncastSync`
134 //! // and run `impl_downcast!()` on the trait.
135 //! trait Base<T: Clone>: Downcast { type H: Copy; }
136 //! downcast_rs::impl_downcast!(Base<T> assoc H where T: Clone, H: Copy);
137 //! // or: impl_downcast!(concrete Base<u32> assoc H=f32)
138 //!
139 //! // Concrete types implementing Base.
140 //! struct Foo(u32);
141 //! impl Base<u32> for Foo { type H = f32; }
142 //! struct Bar(f64);
143 //! impl Base<u32> for Bar { type H = f32; }
144 //!
145 //! fn main() {
146 //!     // Create a trait object.
147 //!     let mut base: Box<Base<u32, H=f32>> = Box::new(Bar(42.0));
148 //!
149 //!     // Try sequential downcasts.
150 //!     if let Some(foo) = base.downcast_ref::<Foo>() {
151 //!         assert_eq!(foo.0, 42);
152 //!     } else if let Some(bar) = base.downcast_ref::<Bar>() {
153 //!         assert_eq!(bar.0, 42.0);
154 //!     }
155 //!
156 //!     assert!(base.is::<Bar>());
157 //! }
158 //! ```
159 
160 // for compatibility with no std and macros
161 #[doc(hidden)]
162 #[cfg(not(feature = "std"))]
163 pub extern crate core as __std;
164 #[doc(hidden)]
165 #[cfg(feature = "std")]
166 pub extern crate std as __std;
167 #[doc(hidden)]
168 pub extern crate alloc as __alloc;
169 
170 use __std::any::Any;
171 use __alloc::{boxed::Box, rc::Rc, sync::Arc};
172 
173 /// Supports conversion to `Any`. Traits to be extended by `impl_downcast!` must extend `Downcast`.
174 pub trait Downcast: Any {
175     /// Convert `Box<dyn Trait>` (where `Trait: Downcast`) to `Box<dyn Any>`. `Box<dyn Any>` can
176     /// then be further `downcast` into `Box<ConcreteType>` where `ConcreteType` implements `Trait`.
into_any(self: Box<Self>) -> Box<dyn Any>177     fn into_any(self: Box<Self>) -> Box<dyn Any>;
178     /// Convert `Rc<Trait>` (where `Trait: Downcast`) to `Rc<Any>`. `Rc<Any>` can then be
179     /// further `downcast` into `Rc<ConcreteType>` where `ConcreteType` implements `Trait`.
into_any_rc(self: Rc<Self>) -> Rc<dyn Any>180     fn into_any_rc(self: Rc<Self>) -> Rc<dyn Any>;
181     /// Convert `&Trait` (where `Trait: Downcast`) to `&Any`. This is needed since Rust cannot
182     /// generate `&Any`'s vtable from `&Trait`'s.
as_any(&self) -> &dyn Any183     fn as_any(&self) -> &dyn Any;
184     /// Convert `&mut Trait` (where `Trait: Downcast`) to `&Any`. This is needed since Rust cannot
185     /// generate `&mut Any`'s vtable from `&mut Trait`'s.
as_any_mut(&mut self) -> &mut dyn Any186     fn as_any_mut(&mut self) -> &mut dyn Any;
187 }
188 
189 impl<T: Any> Downcast for T {
into_any(self: Box<Self>) -> Box<dyn Any>190     fn into_any(self: Box<Self>) -> Box<dyn Any> { self }
into_any_rc(self: Rc<Self>) -> Rc<dyn Any>191     fn into_any_rc(self: Rc<Self>) -> Rc<dyn Any> { self }
as_any(&self) -> &dyn Any192     fn as_any(&self) -> &dyn Any { self }
as_any_mut(&mut self) -> &mut dyn Any193     fn as_any_mut(&mut self) -> &mut dyn Any { self }
194 }
195 
196 /// Extends `Downcast` to support `Sync` traits that thus support `Arc` downcasting as well.
197 pub trait DowncastSync: Downcast + Send + Sync {
198     /// Convert `Arc<Trait>` (where `Trait: Downcast`) to `Arc<Any>`. `Arc<Any>` can then be
199     /// further `downcast` into `Arc<ConcreteType>` where `ConcreteType` implements `Trait`.
into_any_arc(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>200     fn into_any_arc(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
201 }
202 
203 impl<T: Any + Send + Sync> DowncastSync for T {
into_any_arc(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>204     fn into_any_arc(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> { self }
205 }
206 
207 /// Adds downcasting support to traits that extend `downcast::Downcast` by defining forwarding
208 /// methods to the corresponding implementations on `std::any::Any` in the standard library.
209 ///
210 /// See <https://users.rust-lang.org/t/how-to-create-a-macro-to-impl-a-provided-type-parametrized-trait/5289>
211 /// for why this is implemented this way to support templatized traits.
212 #[macro_export(local_inner_macros)]
213 macro_rules! impl_downcast {
214     (@impl_full
215         $trait_:ident [$($param_types:tt)*]
216         for [$($forall_types:ident),*]
217         where [$($preds:tt)*]
218     ) => {
219         impl_downcast! {
220             @inject_where
221                 [impl<$($forall_types),*> dyn $trait_<$($param_types)*>]
222                 types [$($forall_types),*]
223                 where [$($preds)*]
224                 [{
225                     impl_downcast! { @impl_body $trait_ [$($param_types)*] }
226                 }]
227         }
228     };
229 
230     (@impl_full_sync
231         $trait_:ident [$($param_types:tt)*]
232         for [$($forall_types:ident),*]
233         where [$($preds:tt)*]
234     ) => {
235         impl_downcast! {
236             @inject_where
237                 [impl<$($forall_types),*> dyn $trait_<$($param_types)*>]
238                 types [$($forall_types),*]
239                 where [$($preds)*]
240                 [{
241                     impl_downcast! { @impl_body $trait_ [$($param_types)*] }
242                     impl_downcast! { @impl_body_sync $trait_ [$($param_types)*] }
243                 }]
244         }
245     };
246 
247     (@impl_body $trait_:ident [$($types:tt)*]) => {
248         /// Returns true if the trait object wraps an object of type `__T`.
249         #[inline]
250         pub fn is<__T: $trait_<$($types)*>>(&self) -> bool {
251             $crate::Downcast::as_any(self).is::<__T>()
252         }
253         /// Returns a boxed object from a boxed trait object if the underlying object is of type
254         /// `__T`. Returns the original boxed trait if it isn't.
255         #[inline]
256         pub fn downcast<__T: $trait_<$($types)*>>(
257             self: $crate::__alloc::boxed::Box<Self>
258         ) -> $crate::__std::result::Result<$crate::__alloc::boxed::Box<__T>, $crate::__alloc::boxed::Box<Self>> {
259             if self.is::<__T>() {
260                 Ok($crate::Downcast::into_any(self).downcast::<__T>().unwrap())
261             } else {
262                 Err(self)
263             }
264         }
265         /// Returns an `Rc`-ed object from an `Rc`-ed trait object if the underlying object is of
266         /// type `__T`. Returns the original `Rc`-ed trait if it isn't.
267         #[inline]
268         pub fn downcast_rc<__T: $trait_<$($types)*>>(
269             self: $crate::__alloc::rc::Rc<Self>
270         ) -> $crate::__std::result::Result<$crate::__alloc::rc::Rc<__T>, $crate::__alloc::rc::Rc<Self>> {
271             if self.is::<__T>() {
272                 Ok($crate::Downcast::into_any_rc(self).downcast::<__T>().unwrap())
273             } else {
274                 Err(self)
275             }
276         }
277         /// Returns a reference to the object within the trait object if it is of type `__T`, or
278         /// `None` if it isn't.
279         #[inline]
280         pub fn downcast_ref<__T: $trait_<$($types)*>>(&self) -> $crate::__std::option::Option<&__T> {
281             $crate::Downcast::as_any(self).downcast_ref::<__T>()
282         }
283         /// Returns a mutable reference to the object within the trait object if it is of type
284         /// `__T`, or `None` if it isn't.
285         #[inline]
286         pub fn downcast_mut<__T: $trait_<$($types)*>>(&mut self) -> $crate::__std::option::Option<&mut __T> {
287             $crate::Downcast::as_any_mut(self).downcast_mut::<__T>()
288         }
289     };
290 
291     (@impl_body_sync $trait_:ident [$($types:tt)*]) => {
292         /// Returns an `Arc`-ed object from an `Arc`-ed trait object if the underlying object is of
293         /// type `__T`. Returns the original `Arc`-ed trait if it isn't.
294         #[inline]
295         pub fn downcast_arc<__T: $trait_<$($types)*> + $crate::__std::any::Any + $crate::__std::marker::Send + $crate::__std::marker::Sync>(
296             self: $crate::__alloc::sync::Arc<Self>,
297         ) -> $crate::__std::result::Result<$crate::__alloc::sync::Arc<__T>, $crate::__alloc::sync::Arc<Self>>
298         {
299             if self.is::<__T>() {
300                 Ok($crate::DowncastSync::into_any_arc(self).downcast::<__T>().unwrap())
301             } else {
302                 Err(self)
303             }
304         }
305     };
306 
307     (@inject_where [$($before:tt)*] types [] where [] [$($after:tt)*]) => {
308         impl_downcast! { @as_item $($before)* $($after)* }
309     };
310 
311     (@inject_where [$($before:tt)*] types [$($types:ident),*] where [] [$($after:tt)*]) => {
312         impl_downcast! {
313             @as_item
314                 $($before)*
315                 where $( $types: $crate::__std::any::Any + 'static ),*
316                 $($after)*
317         }
318     };
319     (@inject_where [$($before:tt)*] types [$($types:ident),*] where [$($preds:tt)+] [$($after:tt)*]) => {
320         impl_downcast! {
321             @as_item
322                 $($before)*
323                 where
324                     $( $types: $crate::__std::any::Any + 'static, )*
325                     $($preds)*
326                 $($after)*
327         }
328     };
329 
330     (@as_item $i:item) => { $i };
331 
332     // No type parameters.
333     ($trait_:ident   ) => { impl_downcast! { @impl_full $trait_ [] for [] where [] } };
334     ($trait_:ident <>) => { impl_downcast! { @impl_full $trait_ [] for [] where [] } };
335     (sync $trait_:ident   ) => { impl_downcast! { @impl_full_sync $trait_ [] for [] where [] } };
336     (sync $trait_:ident <>) => { impl_downcast! { @impl_full_sync $trait_ [] for [] where [] } };
337     // Type parameters.
338     ($trait_:ident < $($types:ident),* >) => {
339         impl_downcast! { @impl_full $trait_ [$($types),*] for [$($types),*] where [] }
340     };
341     (sync $trait_:ident < $($types:ident),* >) => {
342         impl_downcast! { @impl_full_sync $trait_ [$($types),*] for [$($types),*] where [] }
343     };
344     // Type parameters and where clauses.
345     ($trait_:ident < $($types:ident),* > where $($preds:tt)+) => {
346         impl_downcast! { @impl_full $trait_ [$($types),*] for [$($types),*] where [$($preds)*] }
347     };
348     (sync $trait_:ident < $($types:ident),* > where $($preds:tt)+) => {
349         impl_downcast! { @impl_full_sync $trait_ [$($types),*] for [$($types),*] where [$($preds)*] }
350     };
351     // Associated types.
352     ($trait_:ident assoc $($atypes:ident),*) => {
353         impl_downcast! { @impl_full $trait_ [$($atypes = $atypes),*] for [$($atypes),*] where [] }
354     };
355     (sync $trait_:ident assoc $($atypes:ident),*) => {
356         impl_downcast! { @impl_full_sync $trait_ [$($atypes = $atypes),*] for [$($atypes),*] where [] }
357     };
358     // Associated types and where clauses.
359     ($trait_:ident assoc $($atypes:ident),* where $($preds:tt)+) => {
360         impl_downcast! { @impl_full $trait_ [$($atypes = $atypes),*] for [$($atypes),*] where [$($preds)*] }
361     };
362     (sync $trait_:ident assoc $($atypes:ident),* where $($preds:tt)+) => {
363         impl_downcast! { @impl_full_sync $trait_ [$($atypes = $atypes),*] for [$($atypes),*] where [$($preds)*] }
364     };
365     // Type parameters and associated types.
366     ($trait_:ident < $($types:ident),* > assoc $($atypes:ident),*) => {
367         impl_downcast! {
368             @impl_full
369                 $trait_ [$($types),*, $($atypes = $atypes),*]
370                 for [$($types),*, $($atypes),*]
371                 where []
372         }
373     };
374     (sync $trait_:ident < $($types:ident),* > assoc $($atypes:ident),*) => {
375         impl_downcast! {
376             @impl_full_sync
377                 $trait_ [$($types),*, $($atypes = $atypes),*]
378                 for [$($types),*, $($atypes),*]
379                 where []
380         }
381     };
382     // Type parameters, associated types, and where clauses.
383     ($trait_:ident < $($types:ident),* > assoc $($atypes:ident),* where $($preds:tt)+) => {
384         impl_downcast! {
385             @impl_full
386                 $trait_ [$($types),*, $($atypes = $atypes),*]
387                 for [$($types),*, $($atypes),*]
388                 where [$($preds)*]
389         }
390     };
391     (sync $trait_:ident < $($types:ident),* > assoc $($atypes:ident),* where $($preds:tt)+) => {
392         impl_downcast! {
393             @impl_full_sync
394                 $trait_ [$($types),*, $($atypes = $atypes),*]
395                 for [$($types),*, $($atypes),*]
396                 where [$($preds)*]
397         }
398     };
399     // Concretely-parametrized types.
400     (concrete $trait_:ident < $($types:ident),* >) => {
401         impl_downcast! { @impl_full $trait_ [$($types),*] for [] where [] }
402     };
403     (sync concrete $trait_:ident < $($types:ident),* >) => {
404         impl_downcast! { @impl_full_sync $trait_ [$($types),*] for [] where [] }
405     };
406     // Concretely-associated types types.
407     (concrete $trait_:ident assoc $($atypes:ident = $aty:ty),*) => {
408         impl_downcast! { @impl_full $trait_ [$($atypes = $aty),*] for [] where [] }
409     };
410     (sync concrete $trait_:ident assoc $($atypes:ident = $aty:ty),*) => {
411         impl_downcast! { @impl_full_sync $trait_ [$($atypes = $aty),*] for [] where [] }
412     };
413     // Concretely-parametrized types with concrete associated types.
414     (concrete $trait_:ident < $($types:ident),* > assoc $($atypes:ident = $aty:ty),*) => {
415         impl_downcast! { @impl_full $trait_ [$($types),*, $($atypes = $aty),*] for [] where [] }
416     };
417     (sync concrete $trait_:ident < $($types:ident),* > assoc $($atypes:ident = $aty:ty),*) => {
418         impl_downcast! { @impl_full_sync $trait_ [$($types),*, $($atypes = $aty),*] for [] where [] }
419     };
420 }
421 
422 
423 #[cfg(test)]
424 mod test {
425     macro_rules! test_mod {
426         (
427             $test_mod_name:ident,
428             trait $base_trait:path { $($base_impl:tt)* },
429             non_sync: { $($non_sync_def:tt)+ },
430             sync: { $($sync_def:tt)+ }
431         ) => {
432             test_mod! {
433                 $test_mod_name,
434                 trait $base_trait { $($base_impl:tt)* },
435                 type dyn $base_trait,
436                 non_sync: { $($non_sync_def)* },
437                 sync: { $($sync_def)* }
438             }
439         };
440 
441         (
442             $test_mod_name:ident,
443             trait $base_trait:path { $($base_impl:tt)* },
444             type $base_type:ty,
445             non_sync: { $($non_sync_def:tt)+ },
446             sync: { $($sync_def:tt)+ }
447         ) => {
448             mod $test_mod_name {
449                 test_mod!(
450                     @test
451                     $test_mod_name,
452                     test_name: test_non_sync,
453                     trait $base_trait { $($base_impl)* },
454                     type $base_type,
455                     { $($non_sync_def)+ },
456                     []);
457 
458                 test_mod!(
459                     @test
460                     $test_mod_name,
461                     test_name: test_sync,
462                     trait $base_trait { $($base_impl)* },
463                     type $base_type,
464                     { $($sync_def)+ },
465                     [{
466                         // Fail to convert Arc<Base> into Arc<Bar>.
467                         let arc: $crate::__alloc::sync::Arc<$base_type> = $crate::__alloc::sync::Arc::new(Foo(42));
468                         let res = arc.downcast_arc::<Bar>();
469                         assert!(res.is_err());
470                         let arc = res.unwrap_err();
471                         // Convert Arc<Base> into Arc<Foo>.
472                         assert_eq!(
473                             42, arc.downcast_arc::<Foo>().map_err(|_| "Shouldn't happen.").unwrap().0);
474                     }]);
475             }
476         };
477 
478         (
479             @test
480             $test_mod_name:ident,
481             test_name: $test_name:ident,
482             trait $base_trait:path { $($base_impl:tt)* },
483             type $base_type:ty,
484             { $($def:tt)+ },
485             [ $($more_tests:block)* ]
486         ) => {
487             #[test]
488             fn $test_name() {
489                 #[allow(unused_imports)]
490                 use super::super::{Downcast, DowncastSync};
491 
492                 // Should work even if standard objects (especially those in the prelude) are
493                 // aliased to something else.
494                 #[allow(dead_code)] struct Any;
495                 #[allow(dead_code)] struct Arc;
496                 #[allow(dead_code)] struct Box;
497                 #[allow(dead_code)] struct Option;
498                 #[allow(dead_code)] struct Result;
499                 #[allow(dead_code)] struct Rc;
500                 #[allow(dead_code)] struct Send;
501                 #[allow(dead_code)] struct Sync;
502 
503                 // A trait that can be downcast.
504                 $($def)*
505 
506                 // Concrete type implementing Base.
507                 #[derive(Debug)]
508                 struct Foo(u32);
509                 impl $base_trait for Foo { $($base_impl)* }
510                 #[derive(Debug)]
511                 struct Bar(f64);
512                 impl $base_trait for Bar { $($base_impl)* }
513 
514                 // Functions that can work on references to Base trait objects.
515                 fn get_val(base: &$crate::__alloc::boxed::Box<$base_type>) -> u32 {
516                     match base.downcast_ref::<Foo>() {
517                         Some(val) => val.0,
518                         None => 0
519                     }
520                 }
521                 fn set_val(base: &mut $crate::__alloc::boxed::Box<$base_type>, val: u32) {
522                     if let Some(foo) = base.downcast_mut::<Foo>() {
523                         foo.0 = val;
524                     }
525                 }
526 
527                 let mut base: $crate::__alloc::boxed::Box<$base_type> = $crate::__alloc::boxed::Box::new(Foo(42));
528                 assert_eq!(get_val(&base), 42);
529 
530                 // Try sequential downcasts.
531                 if let Some(foo) = base.downcast_ref::<Foo>() {
532                     assert_eq!(foo.0, 42);
533                 } else if let Some(bar) = base.downcast_ref::<Bar>() {
534                     assert_eq!(bar.0, 42.0);
535                 }
536 
537                 set_val(&mut base, 6*9);
538                 assert_eq!(get_val(&base), 6*9);
539 
540                 assert!(base.is::<Foo>());
541 
542                 // Fail to convert Box<Base> into Box<Bar>.
543                 let res = base.downcast::<Bar>();
544                 assert!(res.is_err());
545                 let base = res.unwrap_err();
546                 // Convert Box<Base> into Box<Foo>.
547                 assert_eq!(
548                     6*9, base.downcast::<Foo>().map_err(|_| "Shouldn't happen.").unwrap().0);
549 
550                 // Fail to convert Rc<Base> into Rc<Bar>.
551                 let rc: $crate::__alloc::rc::Rc<$base_type> = $crate::__alloc::rc::Rc::new(Foo(42));
552                 let res = rc.downcast_rc::<Bar>();
553                 assert!(res.is_err());
554                 let rc = res.unwrap_err();
555                 // Convert Rc<Base> into Rc<Foo>.
556                 assert_eq!(
557                     42, rc.downcast_rc::<Foo>().map_err(|_| "Shouldn't happen.").unwrap().0);
558 
559                 $($more_tests)*
560             }
561         };
562         (
563             $test_mod_name:ident,
564             trait $base_trait:path { $($base_impl:tt)* },
565             non_sync: { $($non_sync_def:tt)+ },
566             sync: { $($sync_def:tt)+ }
567         ) => {
568             test_mod! {
569                 $test_mod_name,
570                 trait $base_trait { $($base_impl:tt)* },
571                 type $base_trait,
572                 non_sync: { $($non_sync_def)* },
573                 sync: { $($sync_def)* }
574             }
575         };
576 
577     }
578 
579     test_mod!(non_generic, trait Base {},
580         non_sync: {
581             trait Base: Downcast {}
582             impl_downcast!(Base);
583         },
584         sync: {
585             trait Base: DowncastSync {}
586             impl_downcast!(sync Base);
587         });
588 
589     test_mod!(generic, trait Base<u32> {},
590         non_sync: {
591             trait Base<T>: Downcast {}
592             impl_downcast!(Base<T>);
593         },
594         sync: {
595             trait Base<T>: DowncastSync {}
596             impl_downcast!(sync Base<T>);
597         });
598 
599     test_mod!(constrained_generic, trait Base<u32> {},
600         non_sync: {
601             trait Base<T: Copy>: Downcast {}
602             impl_downcast!(Base<T> where T: Copy);
603         },
604         sync: {
605             trait Base<T: Copy>: DowncastSync {}
606             impl_downcast!(sync Base<T> where T: Copy);
607         });
608 
609     test_mod!(associated,
610         trait Base { type H = f32; },
611         type dyn Base<H=f32>,
612         non_sync: {
613             trait Base: Downcast { type H; }
614             impl_downcast!(Base assoc H);
615         },
616         sync: {
617             trait Base: DowncastSync { type H; }
618             impl_downcast!(sync Base assoc H);
619         });
620 
621     test_mod!(constrained_associated,
622         trait Base { type H = f32; },
623         type dyn Base<H=f32>,
624         non_sync: {
625             trait Base: Downcast { type H: Copy; }
626             impl_downcast!(Base assoc H where H: Copy);
627         },
628         sync: {
629             trait Base: DowncastSync { type H: Copy; }
630             impl_downcast!(sync Base assoc H where H: Copy);
631         });
632 
633     test_mod!(param_and_associated,
634         trait Base<u32> { type H = f32; },
635         type dyn Base<u32, H=f32>,
636         non_sync: {
637             trait Base<T>: Downcast { type H; }
638             impl_downcast!(Base<T> assoc H);
639         },
640         sync: {
641             trait Base<T>: DowncastSync { type H; }
642             impl_downcast!(sync Base<T> assoc H);
643         });
644 
645     test_mod!(constrained_param_and_associated,
646         trait Base<u32> { type H = f32; },
647         type dyn Base<u32, H=f32>,
648         non_sync: {
649             trait Base<T: Clone>: Downcast { type H: Copy; }
650             impl_downcast!(Base<T> assoc H where T: Clone, H: Copy);
651         },
652         sync: {
653             trait Base<T: Clone>: DowncastSync { type H: Copy; }
654             impl_downcast!(sync Base<T> assoc H where T: Clone, H: Copy);
655         });
656 
657     test_mod!(concrete_parametrized, trait Base<u32> {},
658         non_sync: {
659             trait Base<T>: Downcast {}
660             impl_downcast!(concrete Base<u32>);
661         },
662         sync: {
663             trait Base<T>: DowncastSync {}
664             impl_downcast!(sync concrete Base<u32>);
665         });
666 
667     test_mod!(concrete_associated,
668         trait Base { type H = u32; },
669         type dyn Base<H=u32>,
670         non_sync: {
671             trait Base: Downcast { type H; }
672             impl_downcast!(concrete Base assoc H=u32);
673         },
674         sync: {
675             trait Base: DowncastSync { type H; }
676             impl_downcast!(sync concrete Base assoc H=u32);
677         });
678 
679     test_mod!(concrete_parametrized_associated,
680         trait Base<u32> { type H = f32; },
681         type dyn Base<u32, H=f32>,
682         non_sync: {
683             trait Base<T>: Downcast { type H; }
684             impl_downcast!(concrete Base<u32> assoc H=f32);
685         },
686         sync: {
687             trait Base<T>: DowncastSync { type H; }
688             impl_downcast!(sync concrete Base<u32> assoc H=f32);
689         });
690 }
691