1# downcast-rs 2 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 7Rust enums are great for types where all variations are known beforehand. But a 8container of user-defined types requires an open-ended type like a **trait 9object**. Some applications may want to cast these trait objects back to the 10original concrete types to access additional functionality and performant 11inlined implementations. 12 13`downcast-rs` adds this downcasting support to trait objects using only safe 14Rust. It supports **type parameters**, **associated types**, and **constraints**. 15 16## Usage 17 18Add the following to your `Cargo.toml`: 19 20```toml 21[dependencies] 22downcast-rs = "1.2.0" 23``` 24 25This crate is `no_std` compatible. To use it without `std`: 26 27```toml 28[dependencies] 29downcast-rs = { version = "1.2.0", default-features = false } 30``` 31 32To make a trait downcastable, make it extend either `downcast::Downcast` or 33`downcast::DowncastSync` and invoke `impl_downcast!` on it as in the examples 34below. 35 36Since 1.1.0, the minimum supported Rust version is 1.33 to support `Rc` and `Arc` 37in the receiver position. 38 39```rust 40trait Trait: Downcast {} 41impl_downcast!(Trait); 42 43// Also supports downcasting `Arc`-ed trait objects by extending `DowncastSync` 44// and starting `impl_downcast!` with `sync`. 45trait TraitSync: DowncastSync {} 46impl_downcast!(sync TraitSync); 47 48// With type parameters. 49trait TraitGeneric1<T>: Downcast {} 50impl_downcast!(TraitGeneric1<T>); 51 52// With associated types. 53trait TraitGeneric2: Downcast { type G; type H; } 54impl_downcast!(TraitGeneric2 assoc G, H); 55 56// With constraints on types. 57trait TraitGeneric3<T: Copy>: Downcast { 58 type H: Clone; 59} 60impl_downcast!(TraitGeneric3<T> assoc H where T: Copy, H: Clone); 61 62// With concrete types. 63trait TraitConcrete1<T: Copy>: Downcast {} 64impl_downcast!(concrete TraitConcrete1<u32>); 65 66trait TraitConcrete2<T: Copy>: Downcast { type H; } 67impl_downcast!(concrete TraitConcrete2<u32> assoc H=f64); 68``` 69 70## Example without generics 71 72```rust 73// Import macro via `macro_use` pre-1.30. 74#[macro_use] 75extern crate downcast_rs; 76use downcast_rs::DowncastSync; 77 78// To create a trait with downcasting methods, extend `Downcast` or `DowncastSync` 79// and run `impl_downcast!()` on the trait. 80trait Base: DowncastSync {} 81impl_downcast!(sync Base); // `sync` => also produce `Arc` downcasts. 82 83// Concrete types implementing Base. 84#[derive(Debug)] 85struct Foo(u32); 86impl Base for Foo {} 87#[derive(Debug)] 88struct Bar(f64); 89impl Base for Bar {} 90 91fn main() { 92 // Create a trait object. 93 let mut base: Box<Base> = Box::new(Foo(42)); 94 95 // Try sequential downcasts. 96 if let Some(foo) = base.downcast_ref::<Foo>() { 97 assert_eq!(foo.0, 42); 98 } else if let Some(bar) = base.downcast_ref::<Bar>() { 99 assert_eq!(bar.0, 42.0); 100 } 101 102 assert!(base.is::<Foo>()); 103 104 // Fail to convert `Box<Base>` into `Box<Bar>`. 105 let res = base.downcast::<Bar>(); 106 assert!(res.is_err()); 107 let base = res.unwrap_err(); 108 // Convert `Box<Base>` into `Box<Foo>`. 109 assert_eq!(42, base.downcast::<Foo>().map_err(|_| "Shouldn't happen.").unwrap().0); 110 111 // Also works with `Rc`. 112 let mut rc: Rc<Base> = Rc::new(Foo(42)); 113 assert_eq!(42, rc.downcast_rc::<Foo>().map_err(|_| "Shouldn't happen.").unwrap().0); 114 115 // Since this trait is `Sync`, it also supports `Arc` downcasts. 116 let mut arc: Arc<Base> = Arc::new(Foo(42)); 117 assert_eq!(42, arc.downcast_arc::<Foo>().map_err(|_| "Shouldn't happen.").unwrap().0); 118} 119``` 120 121## Example with a generic trait with associated types and constraints 122 123```rust 124// Can call macro via namespace since rust 1.30. 125extern crate downcast_rs; 126use downcast_rs::Downcast; 127 128// To create a trait with downcasting methods, extend `Downcast` or `DowncastSync` 129// and run `impl_downcast!()` on the trait. 130trait Base<T: Clone>: Downcast { type H: Copy; } 131downcast_rs::impl_downcast!(Base<T> assoc H where T: Clone, H: Copy); 132// or: impl_downcast!(concrete Base<u32> assoc H=f32) 133 134// Concrete types implementing Base. 135struct Foo(u32); 136impl Base<u32> for Foo { type H = f32; } 137struct Bar(f64); 138impl Base<u32> for Bar { type H = f32; } 139 140fn main() { 141 // Create a trait object. 142 let mut base: Box<Base<u32, H=f32>> = Box::new(Bar(42.0)); 143 144 // Try sequential downcasts. 145 if let Some(foo) = base.downcast_ref::<Foo>() { 146 assert_eq!(foo.0, 42); 147 } else if let Some(bar) = base.downcast_ref::<Bar>() { 148 assert_eq!(bar.0, 42.0); 149 } 150 151 assert!(base.is::<Bar>()); 152} 153``` 154 155## License 156 157Copyright 2020, Ashish Myles (maintainer) and contributors. 158This software is dual-licensed under the [MIT](LICENSE-MIT) and 159[Apache 2.0](LICENSE-APACHE) licenses. 160 161### Contribution 162 163Unless you explicitly state otherwise, any contribution intentionally submitted 164for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 165dual licensed as above, without any additional terms or conditions. 166