Coverage Report

Created: 2025-08-29 06:55

/rust/registry/src/index.crates.io-6f17d22bba15001f/downcast-rs-2.0.1/src/lib.rs
Line
Count
Source (jump to first uncovered line)
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"))]
172
pub extern crate core as __std;
173
#[doc(hidden)]
174
#[cfg(feature = "std")]
175
pub extern crate std as __std;
176
#[doc(hidden)]
177
pub extern crate alloc as __alloc;
178
179
use __std::any::Any;
180
use __alloc::{boxed::Box, rc::Rc};
181
182
#[cfg(feature = "sync")]
183
use __alloc::sync::Arc;
184
185
/// Supports conversion to `Any`. Traits to be extended by `impl_downcast!` must extend `Downcast`.
186
pub 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
201
impl<T: Any> Downcast for T {
202
0
    fn into_any(self: Box<Self>) -> Box<dyn Any> { self }
Unexecuted instantiation: <mp4san::parse::trak::TrakBox as downcast_rs::Downcast>::into_any
Unexecuted instantiation: <mp4san::parse::stbl::StblBox as downcast_rs::Downcast>::into_any
Unexecuted instantiation: <mp4san::parse::minf::MinfBox as downcast_rs::Downcast>::into_any
Unexecuted instantiation: <mp4san::parse::co64::Co64Box as downcast_rs::Downcast>::into_any
Unexecuted instantiation: <mp4san::parse::mdia::MdiaBox as downcast_rs::Downcast>::into_any
Unexecuted instantiation: <mp4san::parse::stco::StcoBox as downcast_rs::Downcast>::into_any
203
0
    fn into_any_rc(self: Rc<Self>) -> Rc<dyn Any> { self }
Unexecuted instantiation: <mp4san::parse::trak::TrakBox as downcast_rs::Downcast>::into_any_rc
Unexecuted instantiation: <mp4san::parse::stbl::StblBox as downcast_rs::Downcast>::into_any_rc
Unexecuted instantiation: <mp4san::parse::minf::MinfBox as downcast_rs::Downcast>::into_any_rc
Unexecuted instantiation: <mp4san::parse::co64::Co64Box as downcast_rs::Downcast>::into_any_rc
Unexecuted instantiation: <mp4san::parse::mdia::MdiaBox as downcast_rs::Downcast>::into_any_rc
Unexecuted instantiation: <mp4san::parse::stco::StcoBox as downcast_rs::Downcast>::into_any_rc
204
0
    fn as_any(&self) -> &dyn Any { self }
Unexecuted instantiation: <mp4san::parse::trak::TrakBox as downcast_rs::Downcast>::as_any
Unexecuted instantiation: <mp4san::parse::stbl::StblBox as downcast_rs::Downcast>::as_any
Unexecuted instantiation: <mp4san::parse::minf::MinfBox as downcast_rs::Downcast>::as_any
Unexecuted instantiation: <mp4san::parse::co64::Co64Box as downcast_rs::Downcast>::as_any
Unexecuted instantiation: <mp4san::parse::mdia::MdiaBox as downcast_rs::Downcast>::as_any
Unexecuted instantiation: <mp4san::parse::stco::StcoBox as downcast_rs::Downcast>::as_any
205
176k
    fn as_any_mut(&mut self) -> &mut dyn Any { self }
<mp4san::parse::trak::TrakBox as downcast_rs::Downcast>::as_any_mut
Line
Count
Source
205
52.5k
    fn as_any_mut(&mut self) -> &mut dyn Any { self }
<mp4san::parse::stbl::StblBox as downcast_rs::Downcast>::as_any_mut
Line
Count
Source
205
31.4k
    fn as_any_mut(&mut self) -> &mut dyn Any { self }
<mp4san::parse::minf::MinfBox as downcast_rs::Downcast>::as_any_mut
Line
Count
Source
205
32.2k
    fn as_any_mut(&mut self) -> &mut dyn Any { self }
<mp4san::parse::co64::Co64Box as downcast_rs::Downcast>::as_any_mut
Line
Count
Source
205
11.8k
    fn as_any_mut(&mut self) -> &mut dyn Any { self }
<mp4san::parse::mdia::MdiaBox as downcast_rs::Downcast>::as_any_mut
Line
Count
Source
205
33.1k
    fn as_any_mut(&mut self) -> &mut dyn Any { self }
<mp4san::parse::stco::StcoBox as downcast_rs::Downcast>::as_any_mut
Line
Count
Source
205
15.6k
    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.
209
pub 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
215
impl<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.
222
pub 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")]
233
impl<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)]
244
macro_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
0
        pub fn is<__T: $trait_<$($types)*>>(&self) -> bool {
282
0
            $crate::Downcast::as_any(self).is::<__T>()
283
0
        }
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
0
        pub fn downcast<__T: $trait_<$($types)*>>(
288
0
            self: $crate::__alloc::boxed::Box<Self>
289
0
        ) -> $crate::__std::result::Result<$crate::__alloc::boxed::Box<__T>, $crate::__alloc::boxed::Box<Self>> {
290
0
            if self.is::<__T>() {
291
0
                Ok($crate::Downcast::into_any(self).downcast::<__T>().unwrap())
292
            } else {
293
0
                Err(self)
294
            }
295
0
        }
296
0
        /// Returns an `Rc`-ed object from an `Rc`-ed trait object if the underlying object is of
297
0
        /// type `__T`. Returns the original `Rc`-ed trait if it isn't.
298
0
        #[inline]
299
0
        pub fn downcast_rc<__T: $trait_<$($types)*>>(
300
0
            self: $crate::__alloc::rc::Rc<Self>
301
0
        ) -> $crate::__std::result::Result<$crate::__alloc::rc::Rc<__T>, $crate::__alloc::rc::Rc<Self>> {
302
0
            if self.is::<__T>() {
303
0
                Ok($crate::Downcast::into_any_rc(self).downcast::<__T>().unwrap())
304
            } else {
305
0
                Err(self)
306
            }
307
0
        }
308
0
        /// Returns a reference to the object within the trait object if it is of type `__T`, or
309
0
        /// `None` if it isn't.
310
0
        #[inline]
311
0
        pub fn downcast_ref<__T: $trait_<$($types)*>>(&self) -> $crate::__std::option::Option<&__T> {
312
0
            $crate::Downcast::as_any(self).downcast_ref::<__T>()
313
0
        }
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
0
        pub fn downcast_mut<__T: $trait_<$($types)*>>(&mut self) -> $crate::__std::option::Option<&mut __T> {
318
0
            $crate::Downcast::as_any_mut(self).downcast_mut::<__T>()
319
0
        }
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"))]
455
mod 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
}