1# downcast-rs 2 3[](https://github.com/marcianx/downcast-rs/actions) 4[](https://crates.io/crates/downcast-rs) 5[](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.1" 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.2.0, the minimum supported Rust version is 1.36 due to needing stable access to alloc. 37 38```rust 39trait Trait: Downcast {} 40impl_downcast!(Trait); 41 42// Also supports downcasting `Arc`-ed trait objects by extending `DowncastSync` 43// and starting `impl_downcast!` with `sync`. 44trait TraitSync: DowncastSync {} 45impl_downcast!(sync TraitSync); 46 47// With type parameters. 48trait TraitGeneric1<T>: Downcast {} 49impl_downcast!(TraitGeneric1<T>); 50 51// With associated types. 52trait TraitGeneric2: Downcast { type G; type H; } 53impl_downcast!(TraitGeneric2 assoc G, H); 54 55// With constraints on types. 56trait TraitGeneric3<T: Copy>: Downcast { 57 type H: Clone; 58} 59impl_downcast!(TraitGeneric3<T> assoc H where T: Copy, H: Clone); 60 61// With concrete types. 62trait TraitConcrete1<T: Copy>: Downcast {} 63impl_downcast!(concrete TraitConcrete1<u32>); 64 65trait TraitConcrete2<T: Copy>: Downcast { type H; } 66impl_downcast!(concrete TraitConcrete2<u32> assoc H=f64); 67``` 68 69## Example without generics 70 71```rust 72// Import macro via `macro_use` pre-1.30. 73#[macro_use] 74extern crate downcast_rs; 75use downcast_rs::DowncastSync; 76 77// To create a trait with downcasting methods, extend `Downcast` or `DowncastSync` 78// and run `impl_downcast!()` on the trait. 79trait Base: DowncastSync {} 80impl_downcast!(sync Base); // `sync` => also produce `Arc` downcasts. 81 82// Concrete types implementing Base. 83#[derive(Debug)] 84struct Foo(u32); 85impl Base for Foo {} 86#[derive(Debug)] 87struct Bar(f64); 88impl Base for Bar {} 89 90fn main() { 91 // Create a trait object. 92 let mut base: Box<Base> = Box::new(Foo(42)); 93 94 // Try sequential downcasts. 95 if let Some(foo) = base.downcast_ref::<Foo>() { 96 assert_eq!(foo.0, 42); 97 } else if let Some(bar) = base.downcast_ref::<Bar>() { 98 assert_eq!(bar.0, 42.0); 99 } 100 101 assert!(base.is::<Foo>()); 102 103 // Fail to convert `Box<Base>` into `Box<Bar>`. 104 let res = base.downcast::<Bar>(); 105 assert!(res.is_err()); 106 let base = res.unwrap_err(); 107 // Convert `Box<Base>` into `Box<Foo>`. 108 assert_eq!(42, base.downcast::<Foo>().map_err(|_| "Shouldn't happen.").unwrap().0); 109 110 // Also works with `Rc`. 111 let mut rc: Rc<Base> = Rc::new(Foo(42)); 112 assert_eq!(42, rc.downcast_rc::<Foo>().map_err(|_| "Shouldn't happen.").unwrap().0); 113 114 // Since this trait is `Sync`, it also supports `Arc` downcasts. 115 let mut arc: Arc<Base> = Arc::new(Foo(42)); 116 assert_eq!(42, arc.downcast_arc::<Foo>().map_err(|_| "Shouldn't happen.").unwrap().0); 117} 118``` 119 120## Example with a generic trait with associated types and constraints 121 122```rust 123// Can call macro via namespace since rust 1.30. 124extern crate downcast_rs; 125use downcast_rs::Downcast; 126 127// To create a trait with downcasting methods, extend `Downcast` or `DowncastSync` 128// and run `impl_downcast!()` on the trait. 129trait Base<T: Clone>: Downcast { type H: Copy; } 130downcast_rs::impl_downcast!(Base<T> assoc H where T: Clone, H: Copy); 131// or: impl_downcast!(concrete Base<u32> assoc H=f32) 132 133// Concrete types implementing Base. 134struct Foo(u32); 135impl Base<u32> for Foo { type H = f32; } 136struct Bar(f64); 137impl Base<u32> for Bar { type H = f32; } 138 139fn main() { 140 // Create a trait object. 141 let mut base: Box<Base<u32, H=f32>> = Box::new(Bar(42.0)); 142 143 // Try sequential downcasts. 144 if let Some(foo) = base.downcast_ref::<Foo>() { 145 assert_eq!(foo.0, 42); 146 } else if let Some(bar) = base.downcast_ref::<Bar>() { 147 assert_eq!(bar.0, 42.0); 148 } 149 150 assert!(base.is::<Bar>()); 151} 152``` 153 154## Why no changes in a while? 155 156This library is a thoroughly-tested boilerplate generator, is code complete, has 157no unsafe, and is vanishingly unlikely to have any security issues to patch. 158 159## License 160 161Copyright 2020, Ashish Myles (maintainer) and contributors. 162This software is dual-licensed under the [MIT](LICENSE-MIT) and 163[Apache 2.0](LICENSE-APACHE) licenses. 164 165### Contribution 166 167Unless you explicitly state otherwise, any contribution intentionally submitted 168for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 169dual licensed as above, without any additional terms or conditions. 170