I've searched everywhere for this and found various answers for similar things but nothing specific yet.
Context: my networking subsystem is extendable with new message types. That rules out using an enum.
Is it valid to convert a Box<dyn Trait>
to a Box<Concrete>
using x_ptr as *const Box<Concrete>
where x_ptr
is an unsafe pointer to Trait
?
If so what restrictions does it place on Concrete
or Trait
?
I looked at downcast() implementations for Any in the repo, and indeed it seems to just be casting between pointer types. So I assume what I am trying to do is indeed valid.
Full example below:
use std::rc::Rc;
trait A {
fn name(&self) -> &str;
}
struct B {
x: u32
}
impl B {
}
impl A for B {
fn name(&self) -> &str {
"hello"
}
}
fn main() {
let x: Rc<Box<dyn A>> = Rc::new(Box::new(B { x: 110 }));
println!("count after creating x = {}", Rc::strong_count(&x));
let x_ptr = Rc::into_raw(x.clone());
println!("count after creating x = {}", Rc::strong_count(&x));
let y = unsafe {
// Convert back to an `Rc` to prevent leak.
let x: Rc<Box<B>> = Rc::from_raw(x_ptr as *const Box<B>);
println!("{}", x.x);
println!("{}", x.name());
x
// Further calls to `Rc::from_raw(x_ptr)` would be memory-unsafe.
};
let z = y.clone();
println!("count after creating x = {}", Rc::strong_count(&x));
// The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling!
}
Yields desired output of:
count after creating x = 1
count after creating x = 2
110
hello
count after creating x = 3