Coverage Report

Created: 2024-09-08 06:35

/rust/registry/src/index.crates.io-6f17d22bba15001f/downcast-rs-1.2.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 = "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"))]
163
pub extern crate core as __std;
164
#[doc(hidden)]
165
#[cfg(feature = "std")]
166
pub extern crate std as __std;
167
#[doc(hidden)]
168
pub extern crate alloc as __alloc;
169
170
use __std::any::Any;
171
use __alloc::{boxed::Box, rc::Rc, sync::Arc};
172
173
/// Supports conversion to `Any`. Traits to be extended by `impl_downcast!` must extend `Downcast`.
174
pub 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
189
impl<T: Any> Downcast for T {
190
0
    fn into_any(self: Box<Self>) -> Box<dyn Any> { self }
Unexecuted instantiation: <devices::pci::msix::MsixStatus as downcast_rs::Downcast>::into_any
Unexecuted instantiation: <devices::pci::pm::PmStatusChange as downcast_rs::Downcast>::into_any
Unexecuted instantiation: <hypervisor::kvm::KvmVcpu as downcast_rs::Downcast>::into_any
191
0
    fn into_any_rc(self: Rc<Self>) -> Rc<dyn Any> { self }
Unexecuted instantiation: <devices::pci::msix::MsixStatus as downcast_rs::Downcast>::into_any_rc
Unexecuted instantiation: <devices::pci::pm::PmStatusChange as downcast_rs::Downcast>::into_any_rc
Unexecuted instantiation: <hypervisor::kvm::KvmVcpu as downcast_rs::Downcast>::into_any_rc
192
0
    fn as_any(&self) -> &dyn Any { self }
Unexecuted instantiation: <devices::pci::msix::MsixStatus as downcast_rs::Downcast>::as_any
Unexecuted instantiation: <devices::pci::pm::PmStatusChange as downcast_rs::Downcast>::as_any
Unexecuted instantiation: <hypervisor::kvm::KvmVcpu as downcast_rs::Downcast>::as_any
193
0
    fn as_any_mut(&mut self) -> &mut dyn Any { self }
Unexecuted instantiation: <devices::pci::msix::MsixStatus as downcast_rs::Downcast>::as_any_mut
Unexecuted instantiation: <devices::pci::pm::PmStatusChange as downcast_rs::Downcast>::as_any_mut
Unexecuted instantiation: <hypervisor::kvm::KvmVcpu as downcast_rs::Downcast>::as_any_mut
194
}
195
196
/// Extends `Downcast` to support `Sync` traits that thus support `Arc` downcasting as well.
197
pub 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
203
impl<T: Any + Send + Sync> DowncastSync for T {
204
0
    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)]
213
macro_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
0
        pub fn is<__T: $trait_<$($types)*>>(&self) -> bool {
251
0
            $crate::Downcast::as_any(self).is::<__T>()
252
0
        }
Unexecuted instantiation: <dyn devices::pci::pci_configuration::PciCapConfigWriteResult>::is::<_>
Unexecuted instantiation: <dyn hypervisor::x86_64::VcpuX86_64>::is::<_>
Unexecuted instantiation: <dyn hypervisor::Vcpu>::is::<_>
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
0
        pub fn downcast<__T: $trait_<$($types)*>>(
257
0
            self: $crate::__alloc::boxed::Box<Self>
258
0
        ) -> $crate::__std::result::Result<$crate::__alloc::boxed::Box<__T>, $crate::__alloc::boxed::Box<Self>> {
259
0
            if self.is::<__T>() {
260
0
                Ok($crate::Downcast::into_any(self).downcast::<__T>().unwrap())
261
            } else {
262
0
                Err(self)
263
            }
264
0
        }
Unexecuted instantiation: <dyn devices::pci::pci_configuration::PciCapConfigWriteResult>::downcast::<_>
Unexecuted instantiation: <dyn hypervisor::x86_64::VcpuX86_64>::downcast::<_>
Unexecuted instantiation: <dyn hypervisor::Vcpu>::downcast::<_>
265
0
        /// Returns an `Rc`-ed object from an `Rc`-ed trait object if the underlying object is of
266
0
        /// type `__T`. Returns the original `Rc`-ed trait if it isn't.
267
0
        #[inline]
268
0
        pub fn downcast_rc<__T: $trait_<$($types)*>>(
269
0
            self: $crate::__alloc::rc::Rc<Self>
270
0
        ) -> $crate::__std::result::Result<$crate::__alloc::rc::Rc<__T>, $crate::__alloc::rc::Rc<Self>> {
271
0
            if self.is::<__T>() {
272
0
                Ok($crate::Downcast::into_any_rc(self).downcast::<__T>().unwrap())
273
            } else {
274
0
                Err(self)
275
            }
276
0
        }
Unexecuted instantiation: <dyn devices::pci::pci_configuration::PciCapConfigWriteResult>::downcast_rc::<_>
Unexecuted instantiation: <dyn hypervisor::x86_64::VcpuX86_64>::downcast_rc::<_>
Unexecuted instantiation: <dyn hypervisor::Vcpu>::downcast_rc::<_>
277
0
        /// Returns a reference to the object within the trait object if it is of type `__T`, or
278
0
        /// `None` if it isn't.
279
0
        #[inline]
280
0
        pub fn downcast_ref<__T: $trait_<$($types)*>>(&self) -> $crate::__std::option::Option<&__T> {
281
0
            $crate::Downcast::as_any(self).downcast_ref::<__T>()
282
0
        }
Unexecuted instantiation: <dyn devices::pci::pci_configuration::PciCapConfigWriteResult>::downcast_ref::<devices::pci::pm::PmStatusChange>
Unexecuted instantiation: <dyn devices::pci::pci_configuration::PciCapConfigWriteResult>::downcast_ref::<devices::pci::msix::MsixStatus>
Unexecuted instantiation: <dyn hypervisor::Vcpu>::downcast_ref::<hypervisor::kvm::KvmVcpu>
Unexecuted instantiation: <dyn hypervisor::x86_64::VcpuX86_64>::downcast_ref::<_>
Unexecuted instantiation: <dyn hypervisor::Vcpu>::downcast_ref::<_>
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
0
        pub fn downcast_mut<__T: $trait_<$($types)*>>(&mut self) -> $crate::__std::option::Option<&mut __T> {
287
0
            $crate::Downcast::as_any_mut(self).downcast_mut::<__T>()
288
0
        }
Unexecuted instantiation: <dyn devices::pci::pci_configuration::PciCapConfigWriteResult>::downcast_mut::<_>
Unexecuted instantiation: <dyn hypervisor::x86_64::VcpuX86_64>::downcast_mut::<_>
Unexecuted instantiation: <dyn hypervisor::Vcpu>::downcast_mut::<_>
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
0
        pub fn downcast_arc<__T: $trait_<$($types)*> + $crate::__std::any::Any + $crate::__std::marker::Send + $crate::__std::marker::Sync>(
296
0
            self: $crate::__alloc::sync::Arc<Self>,
297
0
        ) -> $crate::__std::result::Result<$crate::__alloc::sync::Arc<__T>, $crate::__alloc::sync::Arc<Self>>
298
0
        {
299
0
            if self.is::<__T>() {
300
0
                Ok($crate::DowncastSync::into_any_arc(self).downcast::<__T>().unwrap())
301
            } else {
302
0
                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)]
424
mod 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
}