Search code examples
rusttype-conversiontraitscoercion

Rust Trait object conversion


The following code won't compile due to two instances of this error:

error[E0277]: the trait bound Self: std::marker::Sized is not satisfied

I don't understand why Sized is required in this instance as both &self and &Any are pointers and the operation does not require knowledge of the size of the structure that implements the trait, it only requires knowledge of the pointer itself and the type it is converting from and to, which it will have because &self is generic when implemented inside a trait.

I think this may be an instance of the compiler enforcing unnecessary constraints and I've considered filing an issue with the rust-lang GitHub repo but I figured I should probably see if someone here knows something I don't before I go file an issue.

use std::any::Any;

trait Component: Any {
    fn as_any(&self) -> &Any {
        self
    }

    fn as_any_mut(&mut self) -> &mut Any {
        self
    }
}

The alternative to this is to make as_any() and as_any_mut() required functions for the structs that implement this trait, but for those structures the implementation would always be exactly as displayed here down to each individual character, resulting in several instances of identical boilerplate code.


Solution

  • I found what I consider to be a great solution that didn't require new compiler features.

    pub trait Component {
        // ...
    }
    
    pub trait ComponentAny: Component + Any {
        fn as_any(&self) -> &Any;
        fn as_any_mut(&mut self) -> &mut Any;
    }
    
    impl<T> ComponentAny for T
        where T: Component + Any
    {
        fn as_any(&self) -> &Any {
            self
        }
    
        fn as_any_mut(&mut self) -> &mut Any {
            self
        }
    }
    

    From here, I just change all my APIs to accept ComponentAny instead of Component. Because Any is automatically implemented for any 'static type, ComponentAny is now automatically implemented for any 'static type that implements Component. Thanks to Is there a way to combine multiple traits in order to define a new trait? for the idea.