downcast_rs/
lib.rs

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