I would like to know if the following code is a valid use (maybe there is a builtin/safe way to downcast Rc<dyn SomeTrait>
to Rc<SomeType>
? I couldn't find any) and most importantly, is it safe?
use std::any::*;
use std::rc::*;
// NOTE: apparently adding Any here is REQUIRED
// otherwise it doesn't work at all,
// I have no idea why
trait SomeTrait: Any {}
struct SomeType;
impl SomeTrait for SomeType {}
fn rc_downcaster<A: 'static, B: ?Sized + 'static>(b: Rc<B>) -> Option<Rc<A>> {
if Any::type_id(&*b) == TypeId::of::<A>() {
Some(unsafe {
let p = Rc::into_raw(b);
Rc::from_raw(p as *const A)
})
} else {
None
}
}
fn main() {
let x: Rc<dyn SomeTrait> = Rc::new(SomeType);
let _: Rc<SomeType> = rc_downcaster(x).unwrap();
}
Without using nightly, I found this safe alternative solution:
use std::any::*;
use std::rc::*;
trait SomeTrait: AsAny {}
struct SomeType;
impl SomeTrait for SomeType {}
trait AsAny {
fn as_any(self: Rc<Self>) -> Rc<dyn Any>;
}
impl<T: 'static> AsAny for T {
fn as_any(self: Rc<Self>) -> Rc<dyn Any> where Self: Sized
{
self
}
}
fn main() {
let x: Rc<dyn SomeTrait> = Rc::new(SomeType);
let x: Rc<dyn Any> = x.as_any();
let _: Rc<SomeType> = Rc::downcast(x).unwrap();
}
But it is worth mentioning the solution of @cafce25 (in comment):
You can use Rc::downcast if you are on nightly and add #![feature(trait_upcasting)]. Since that works your code should be sound as well. Playground