Any
In the standard library, the std::any::Any trait comes with downcast methods
which let you cast from an Any
trait object to a concrete type.
```rust let x: i32 = 7; let y: &dyn std::any::Any = &x;
// Cast to i32 succeeds because x: i32
asserteq!(y.downcastref::
However, it is not possible to downcast to a trait object.
```compile_fail trait Foo { fn foo(&self) -> i32; }
struct A { x: i32 }
impl Foo for A { fn foo(&self) -> i32 { self.x } }
let x = A { x: 7 }; let y: &dyn std::any::Any = &x;
// This cast is not possible, because it is only possible to cast to types that // are Sized. Among other things, this precludes trait objects. let z: Option<&dyn Foo> = y.downcast_ref(); ```
This library provides a way of casting between different trait objects.
```rust use traitcast::{TraitcastFrom, TraitcastTo, Traitcast};
// Extending TraitcastFrom
is optional. This allows Foo
objects themselves
// to be cast to other trait objects. If you do not extend TraitcastFrom
,
// then Foo may only be cast into, not out of.
trait Foo: TraitcastFrom {
fn foo(&self) -> i32;
}
// Invoking traitcast_to_trait!
implements TraitcastTo for this Foo, allowing
// other trait objects to be cast into Foo trait objects.
traitcast::traitcasttotrait!(Foo, Foo_Traitcast);
trait Bar: TraitcastFrom { fn bar(&mut self) -> i32; }
traitcast::traitcasttotrait!(Bar, Bar_Traitcast);
struct A { x: i32 }
// No implementation of TraitcastFrom is necessary, because it is covered by // the blanket impl for any sized type with a static lifetime. impl Foo for A { fn foo(&self) -> i32 { self.x } }
impl Bar for A { fn bar(&mut self) -> i32 { self.x *= 2; self.x } }
// Register the traits.
// For each struct that implements each trait, register the implementation. traitcast::traitcasttoimpl!(Foo, A); traitcast::traitcasttoimpl!(Bar, A);
fn main() { let mut x = A { x: 7 };
{
let x: &dyn Foo = &x;
// Test whether x is of a type that implements Bar.
assert!(traitcast::implements_trait::<dyn Foo, dyn Bar>(x));
}
{
let x: &dyn Bar = &x;
// Cast an immutable reference using the `cast_ref` method (via the
// `Traitcast` trait, which is blanket implemented for all pairs of
// traits that may be cast between).
let x: &dyn Foo = x.cast_ref().unwrap();
assert_eq!(x.foo(), 7);
// We can also cast using the top-level `cast_ref` function, which can
// be more convenient when type arguments cannot be inferred.
assert!(traitcast::cast_ref::<dyn Foo, dyn Bar>(x).is_some());
}
{
let x: &mut dyn Foo = &mut x;
// Cast a mutable reference using the `cast_mut` method
let x: &mut dyn Bar = x.cast_mut().unwrap();
assert_eq!(x.bar(), 14);
}
{
// We can cast from `Any` too!
let y: Box<dyn std::any::Any> = Box::new(x);
// Cast a boxed reference
let z: Box<dyn Foo> = y.cast_box().unwrap();
assert_eq!(z.foo(), 14);
}
}