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