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