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}
691