Search code examples
rustcastingunsafe

Upcasting an `Arc<dyn Trait>` to an `Arc<dyn Any>`?


Suppose I have a trait object of type Asset, which is stored in an Arc, and I want to convert it to an Arc<dyn Any> to facilitate later downcasting.

Is there any safe way to do this? I have tried this (unsafe) strategy using the as-any crate, but it seems to break the type information as I can't downcast the resulting Arc<dyn Any> to its base type:

    let res: Box<dyn Asset> = thing_that_returns_dyn_asset();
    let res: Arc<dyn Asset> = Arc::from(res);

    // Unsafe: Cast an Arc<dyn Asset> to an Arc<dyn Any>.
    let res : Arc<dyn Any> = unsafe {
         Arc::from_raw(Arc::into_raw(res).as_any())
    };

But it does not seem to work. I'm aware that there's a currently experimental feature to upcast objects, but that doesn't seem to help.


Solution

  • The easiest way is to add a method that casts from Arc<Asset> to Arc<dyn Any>. Following as-any, we can do that in a custom trait and have a blanket implementation for it:

    pub trait AsAnyArc {
        fn as_any_arc(self: Arc<Self>) -> Arc<dyn Any>;
    }
    
    impl<T: 'static> AsAnyArc for T {
        fn as_any_arc(self: Arc<Self>) -> Arc<dyn Any> { self }
    }
    
    pub trait Asset: AsAnyArc { ... }
    
    let res: Box<dyn Asset> = thing_that_returns_dyn_asset();
    let res: Arc<dyn Asset> = Arc::from(res);
    
    let res: Arc<dyn Any> = res.as_any_arc();