1 #![deny(unsafe_code,rustdoc::bare_urls)] 2 #![cfg_attr(not(feature = "std"), no_std)] 3 //! [](https://github.com/marcianx/downcast-rs/actions) 4 //! [](https://crates.io/crates/downcast-rs) 5 //! [](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`. into_any(self: Box<Self>) -> Box<dyn Any>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`. into_any_rc(self: Rc<Self>) -> Rc<dyn Any>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. as_any(&self) -> &dyn Any183 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. as_any_mut(&mut self) -> &mut dyn Any186 fn as_any_mut(&mut self) -> &mut dyn Any; 187 } 188 189 impl<T: Any> Downcast for T { into_any(self: Box<Self>) -> Box<dyn Any>190 fn into_any(self: Box<Self>) -> Box<dyn Any> { self } into_any_rc(self: Rc<Self>) -> Rc<dyn Any>191 fn into_any_rc(self: Rc<Self>) -> Rc<dyn Any> { self } as_any(&self) -> &dyn Any192 fn as_any(&self) -> &dyn Any { self } as_any_mut(&mut self) -> &mut dyn Any193 fn as_any_mut(&mut self) -> &mut dyn Any { self } 194 } 195 196 /// Extends `Downcast` to support `Sync` traits that thus support `Arc` downcasting as well. 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`. into_any_arc(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>200 fn into_any_arc(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>; 201 } 202 203 impl<T: Any + Send + Sync> DowncastSync for T { into_any_arc(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>204 fn into_any_arc(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> { self } 205 } 206 207 /// Adds downcasting support to traits that extend `downcast::Downcast` by defining forwarding 208 /// methods to the corresponding implementations on `std::any::Any` in the standard library. 209 /// 210 /// See <https://users.rust-lang.org/t/how-to-create-a-macro-to-impl-a-provided-type-parametrized-trait/5289> 211 /// for why this is implemented this way to support templatized traits. 212 #[macro_export(local_inner_macros)] 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 pub fn is<__T: $trait_<$($types)*>>(&self) -> bool { 251 $crate::Downcast::as_any(self).is::<__T>() 252 } 253 /// Returns a boxed object from a boxed trait object if the underlying object is of type 254 /// `__T`. Returns the original boxed trait if it isn't. 255 #[inline] 256 pub fn downcast<__T: $trait_<$($types)*>>( 257 self: $crate::__alloc::boxed::Box<Self> 258 ) -> $crate::__std::result::Result<$crate::__alloc::boxed::Box<__T>, $crate::__alloc::boxed::Box<Self>> { 259 if self.is::<__T>() { 260 Ok($crate::Downcast::into_any(self).downcast::<__T>().unwrap()) 261 } else { 262 Err(self) 263 } 264 } 265 /// Returns an `Rc`-ed object from an `Rc`-ed trait object if the underlying object is of 266 /// type `__T`. Returns the original `Rc`-ed trait if it isn't. 267 #[inline] 268 pub fn downcast_rc<__T: $trait_<$($types)*>>( 269 self: $crate::__alloc::rc::Rc<Self> 270 ) -> $crate::__std::result::Result<$crate::__alloc::rc::Rc<__T>, $crate::__alloc::rc::Rc<Self>> { 271 if self.is::<__T>() { 272 Ok($crate::Downcast::into_any_rc(self).downcast::<__T>().unwrap()) 273 } else { 274 Err(self) 275 } 276 } 277 /// Returns a reference to the object within the trait object if it is of type `__T`, or 278 /// `None` if it isn't. 279 #[inline] 280 pub fn downcast_ref<__T: $trait_<$($types)*>>(&self) -> $crate::__std::option::Option<&__T> { 281 $crate::Downcast::as_any(self).downcast_ref::<__T>() 282 } 283 /// Returns a mutable reference to the object within the trait object if it is of type 284 /// `__T`, or `None` if it isn't. 285 #[inline] 286 pub fn downcast_mut<__T: $trait_<$($types)*>>(&mut self) -> $crate::__std::option::Option<&mut __T> { 287 $crate::Downcast::as_any_mut(self).downcast_mut::<__T>() 288 } 289 }; 290 291 (@impl_body_sync $trait_:ident [$($types:tt)*]) => { 292 /// Returns an `Arc`-ed object from an `Arc`-ed trait object if the underlying object is of 293 /// type `__T`. Returns the original `Arc`-ed trait if it isn't. 294 #[inline] 295 pub fn downcast_arc<__T: $trait_<$($types)*> + $crate::__std::any::Any + $crate::__std::marker::Send + $crate::__std::marker::Sync>( 296 self: $crate::__alloc::sync::Arc<Self>, 297 ) -> $crate::__std::result::Result<$crate::__alloc::sync::Arc<__T>, $crate::__alloc::sync::Arc<Self>> 298 { 299 if self.is::<__T>() { 300 Ok($crate::DowncastSync::into_any_arc(self).downcast::<__T>().unwrap()) 301 } else { 302 Err(self) 303 } 304 } 305 }; 306 307 (@inject_where [$($before:tt)*] types [] where [] [$($after:tt)*]) => { 308 impl_downcast! { @as_item $($before)* $($after)* } 309 }; 310 311 (@inject_where [$($before:tt)*] types [$($types:ident),*] where [] [$($after:tt)*]) => { 312 impl_downcast! { 313 @as_item 314 $($before)* 315 where $( $types: $crate::__std::any::Any + 'static ),* 316 $($after)* 317 } 318 }; 319 (@inject_where [$($before:tt)*] types [$($types:ident),*] where [$($preds:tt)+] [$($after:tt)*]) => { 320 impl_downcast! { 321 @as_item 322 $($before)* 323 where 324 $( $types: $crate::__std::any::Any + 'static, )* 325 $($preds)* 326 $($after)* 327 } 328 }; 329 330 (@as_item $i:item) => { $i }; 331 332 // No type parameters. 333 ($trait_:ident ) => { impl_downcast! { @impl_full $trait_ [] for [] where [] } }; 334 ($trait_:ident <>) => { impl_downcast! { @impl_full $trait_ [] for [] where [] } }; 335 (sync $trait_:ident ) => { impl_downcast! { @impl_full_sync $trait_ [] for [] where [] } }; 336 (sync $trait_:ident <>) => { impl_downcast! { @impl_full_sync $trait_ [] for [] where [] } }; 337 // Type parameters. 338 ($trait_:ident < $($types:ident),* >) => { 339 impl_downcast! { @impl_full $trait_ [$($types),*] for [$($types),*] where [] } 340 }; 341 (sync $trait_:ident < $($types:ident),* >) => { 342 impl_downcast! { @impl_full_sync $trait_ [$($types),*] for [$($types),*] where [] } 343 }; 344 // Type parameters and where clauses. 345 ($trait_:ident < $($types:ident),* > where $($preds:tt)+) => { 346 impl_downcast! { @impl_full $trait_ [$($types),*] for [$($types),*] where [$($preds)*] } 347 }; 348 (sync $trait_:ident < $($types:ident),* > where $($preds:tt)+) => { 349 impl_downcast! { @impl_full_sync $trait_ [$($types),*] for [$($types),*] where [$($preds)*] } 350 }; 351 // Associated types. 352 ($trait_:ident assoc $($atypes:ident),*) => { 353 impl_downcast! { @impl_full $trait_ [$($atypes = $atypes),*] for [$($atypes),*] where [] } 354 }; 355 (sync $trait_:ident assoc $($atypes:ident),*) => { 356 impl_downcast! { @impl_full_sync $trait_ [$($atypes = $atypes),*] for [$($atypes),*] where [] } 357 }; 358 // Associated types and where clauses. 359 ($trait_:ident assoc $($atypes:ident),* where $($preds:tt)+) => { 360 impl_downcast! { @impl_full $trait_ [$($atypes = $atypes),*] for [$($atypes),*] where [$($preds)*] } 361 }; 362 (sync $trait_:ident assoc $($atypes:ident),* where $($preds:tt)+) => { 363 impl_downcast! { @impl_full_sync $trait_ [$($atypes = $atypes),*] for [$($atypes),*] where [$($preds)*] } 364 }; 365 // Type parameters and associated types. 366 ($trait_:ident < $($types:ident),* > assoc $($atypes:ident),*) => { 367 impl_downcast! { 368 @impl_full 369 $trait_ [$($types),*, $($atypes = $atypes),*] 370 for [$($types),*, $($atypes),*] 371 where [] 372 } 373 }; 374 (sync $trait_:ident < $($types:ident),* > assoc $($atypes:ident),*) => { 375 impl_downcast! { 376 @impl_full_sync 377 $trait_ [$($types),*, $($atypes = $atypes),*] 378 for [$($types),*, $($atypes),*] 379 where [] 380 } 381 }; 382 // Type parameters, associated types, and where clauses. 383 ($trait_:ident < $($types:ident),* > assoc $($atypes:ident),* where $($preds:tt)+) => { 384 impl_downcast! { 385 @impl_full 386 $trait_ [$($types),*, $($atypes = $atypes),*] 387 for [$($types),*, $($atypes),*] 388 where [$($preds)*] 389 } 390 }; 391 (sync $trait_:ident < $($types:ident),* > assoc $($atypes:ident),* where $($preds:tt)+) => { 392 impl_downcast! { 393 @impl_full_sync 394 $trait_ [$($types),*, $($atypes = $atypes),*] 395 for [$($types),*, $($atypes),*] 396 where [$($preds)*] 397 } 398 }; 399 // Concretely-parametrized types. 400 (concrete $trait_:ident < $($types:ident),* >) => { 401 impl_downcast! { @impl_full $trait_ [$($types),*] for [] where [] } 402 }; 403 (sync concrete $trait_:ident < $($types:ident),* >) => { 404 impl_downcast! { @impl_full_sync $trait_ [$($types),*] for [] where [] } 405 }; 406 // Concretely-associated types types. 407 (concrete $trait_:ident assoc $($atypes:ident = $aty:ty),*) => { 408 impl_downcast! { @impl_full $trait_ [$($atypes = $aty),*] for [] where [] } 409 }; 410 (sync concrete $trait_:ident assoc $($atypes:ident = $aty:ty),*) => { 411 impl_downcast! { @impl_full_sync $trait_ [$($atypes = $aty),*] for [] where [] } 412 }; 413 // Concretely-parametrized types with concrete associated types. 414 (concrete $trait_:ident < $($types:ident),* > assoc $($atypes:ident = $aty:ty),*) => { 415 impl_downcast! { @impl_full $trait_ [$($types),*, $($atypes = $aty),*] for [] where [] } 416 }; 417 (sync concrete $trait_:ident < $($types:ident),* > assoc $($atypes:ident = $aty:ty),*) => { 418 impl_downcast! { @impl_full_sync $trait_ [$($types),*, $($atypes = $aty),*] for [] where [] } 419 }; 420 } 421 422 423 #[cfg(test)] 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 } 691