[][src]Crate traitcast

Casting from 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.

let x: i32 = 7;
let y: &dyn std::any::Any = &x;

// Cast to i32 succeeds because x: i32
assert_eq!(y.downcast_ref::<i32>(), Some(&7));
// Cast to f32 fails
assert_eq!(y.downcast_ref::<f32>(), None);

However, it is not possible to downcast to a trait object.

This example deliberately fails to compile
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();

Traitcast

This library provides a way of casting between different trait objects.

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::traitcast_to_trait!(Foo, Foo_Traitcast);

trait Bar: TraitcastFrom {
    fn bar(&mut self) -> i32;
}

traitcast::traitcast_to_trait!(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::traitcast_to_impl!(Foo, A);
traitcast::traitcast_to_impl!(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);
    }
}

Modules

private

Macros

traitcast_to_impl

Register an implementation of a castable trait for a particular struct. The struct must implement the trait. This enables objects of this type to be cast into dynamic trait references of this trait, via an Any pointer. It is best not to invoke traitcast_to_impl! multiple times for the same implementation. This will have no effect but to slightly slow down program load time.

traitcast_to_trait

Register a trait to allow it to be cast into. Cannot cast from implementing structs unless traitcast_to_impl! is also invoked for that struct.

Traits

Traitcast

A convenience trait with a blanket implementation that adds methods to cast from any trait that implements TraitcastFrom, to any trait that implements TraitcastTo.

TraitcastFrom

Subtraits of TraitcastFrom may be cast into dyn Any, and thus may be cast into any other castable dynamic trait object, too. This is blanket implemented for all sized types with static lifetimes.

TraitcastTo

Trait objects that can be cast into implement this trait.

Functions

cast_box

Tries to cast the given pointer to a dynamic trait object. This will always return Err if the implementation of the target trait, for the concrete type of x, has not been registered via traitcast_to_impl!.

cast_mut

Tries to cast the given mutable reference to a dynamic trait object. This will always return None if the implementation of the target trait, for the concrete type of x, has not been registered via traitcast_to_impl!.

cast_ref

Tries to cast the given reference to a dynamic trait object. This will always return None if the implementation of the target trait, for the concrete type of x, has not been registered via traitcast_to_impl!.

implements_trait

Tests whether the given value is castable to some trait object. This will always return false if the implementation of the target trait, for the concrete type of x, has not been registered via traitcast_to_impl!.