i'm implementing a custom version of Rc (without the logic for weak pointers & support for allocators).
but i'm having an issue, where i can't create an Rc<dyn Any> using Rc::new(42i32), it's giving me an Rc<i32> instead. it does work with rust's std::rc::Rc.
so the question is: does the rust compiler implement some magic to make this happen? and if not, what am i missing, some trait maybe? or how else could i make this work?
below, i've copy pasted all the relevant code from std to make TestTc::new(42i32) "compile".
but it doesn't work either, same issue as with my custom Rc.
use core::cell::Cell;
use core::marker::PhantomData;
use core::any::Any;
#[repr(C)]
struct RcBox<T: ?Sized> {
strong: Cell<usize>,
weak: Cell<usize>,
value: T,
}
pub struct TestRc<T: ?Sized> {
ptr: core::ptr::NonNull<RcBox<T>>,
phantom: PhantomData<RcBox<T>>,
}
impl<T> TestRc<T> {
unsafe fn from_inner(ptr: core::ptr::NonNull<RcBox<T>>) -> Self {
Self { ptr, phantom: PhantomData }
}
#[cfg(not(no_global_oom_handling))]
pub fn new(value: T) -> TestRc<T> {
// There is an implicit weak pointer owned by all the strong
// pointers, which ensures that the weak destructor never frees
// the allocation while the strong destructor is running, even
// if the weak pointer is stored inside the strong one.
unsafe {
Self::from_inner(
Box::leak(Box::new(RcBox { strong: Cell::new(1), weak: Cell::new(1), value }))
.into(),
)
}
}
}
fn main() {
// error: expected `TestRc<dyn Any>`, got `TestRc<i32>`
let foo: TestRc<dyn Any> = TestRc::new(42i32);
}
haha, that was quick, thanks!
sadly that requires nightly rust.
is there some way i could achieve this on stable?
perhaps not with the regular new function, but some other hack new_dyn, until CoerceUnsized becomes stable.
since there's no "trait polymorphism", i'm not sure what the signature would be.
i only need dyn Any for now, maybe i can make that work.
No it wouldn't. dyn Trait is not the only kind of unsized type. That signature wouldn't work with slices, str, or custom DSTs.
That seems like a lot of unnecessary pointer gymnastics going through mutable references. That's usually UB because you end up accidentally aliasing stuff behind the &mut; if you are managing memory yourself, stick with raw pointers. You should do this instead:
pub fn new(value: T) -> TestRc<dyn Any> {
let bx: Box<RcBox<dyn Any>> = Box::new(RcBox { strong: Cell::new(1), weak: Cell::new(1), value });
let ptr = Box::into_raw(bx);
let ptr = NonNull::new(ptr).unwrap();
TestRc { ptr, phantom: PhantomData }
}
Note that Rc does have some special compiler support in regard to Rc<Self> as method receiver. See Special types and traits in the Rust reference. If I understand it right, then you can't do these things with your own Rc type.