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