downcast_rs/
lib.rs

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"))]
163pub extern crate core as __std;
164#[doc(hidden)]
165#[cfg(feature = "std")]
166pub extern crate std as __std;
167#[doc(hidden)]
168pub extern crate alloc as __alloc;
169
170use __std::any::Any;
171use __alloc::{boxed::Box, rc::Rc, sync::Arc};
172
173/// Supports conversion to `Any`. Traits to be extended by `impl_downcast!` must extend `Downcast`.
174pub 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`.
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`.
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.
183    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.
186    fn as_any_mut(&mut self) -> &mut dyn Any;
187}
188
189impl<T: Any> Downcast for T {
190    fn into_any(self: Box<Self>) -> Box<dyn Any> { self }
191    fn into_any_rc(self: Rc<Self>) -> Rc<dyn Any> { self }
192    fn as_any(&self) -> &dyn Any { self }
193    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.
197pub 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`.
200    fn into_any_arc(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
201}
202
203impl<T: Any + Send + Sync> DowncastSync for T {
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)]
213macro_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)]
424mod 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}