In Rusts standard library, Rc::from_box_in
copies the memory, why not just do it like.
fn foo<T>(box_val: Box<T>) -> Rc<T> {
let val_ptr = &*box_val as *const T;
let rc_val: Rc<T> = unsafe { Rc::from_raw(val_ptr) };
rc_val
}
I have not found any problem with this impl;
An RcBox<T>
is not just T. In the current version on docs.rs:
#[repr(C)]
struct RcBox<T: ?Sized> {
strong: Cell<usize>,
weak: Cell<usize>,
value: T,
}
Note two counts (as cells) and the value.
Further, note that Rc::from_raw
calls Rc::from_raw_in
, which subsequently does the following:
pub unsafe fn from_raw_in(ptr: *const T, alloc: A) -> Self {
let offset = unsafe { data_offset(ptr) };
// Reverse the offset to find the original RcBox.
let rc_ptr = unsafe { ptr.byte_sub(offset) as *mut RcBox<T> };
unsafe { Self::from_ptr_in(rc_ptr, alloc) }
}
The original RcBox is found by pointer arithmetic. If that pointer wasn't pointing into the data field of an RcBox (and a raw pointer into a normal box does not point into the data field of an RcBox), then this is simply unsound, as it transmutes a wayward pointer into a pointer to an RcBox, then returns an Rc with that pointer. As soon as you use that Rc in any meaningful way, an invalid &RcBox-not-referencing-a-real-RcBox is produced.
On the other hand, from_box_in
(with the current implementation), does a bytewise copy, and then frees the original box allocation without calling drop glue on the contents, which is what we want. Essentially, it's manually performing something analogous to a rust move (which is just a bytewise copy) with the appropriate drop semantics.