Obtain Rc<RefCell<T>> from *const T

Rc provides from_raw(), but RefCell does not. Thus Rc<RefCell<T>> can not be obtained from *const T.

Is it good idea to provide RefCell::from_raw()?

Two things:

  • you can't obtain a RefCell from arbitrary pointer to T, because the RefCell has some extra inline data
  • Rc::from_raw is only valid is only valid to call on pointers from Rc::into_raw, so you can't call it on arbitrary pointers
3 Likes

Ok I forgot that Rc introduces one level of indirection.

However my purpose is to obtain Rc<RefCell<T>> from *const T and wonder if it is feasible.

If it's really *const T type, then it's not possible at all, because both Rc and RefCell have a memory layout that is different from T and are incompatible with it (T has no room to store refcount and mutability flag).

If you've used Rc::into_raw, then you can get it back from *const RefCell<T>.

I see there's no non-hacky way to get a raw owning T pointer from Rc<RefCell>, because RefCell doesn't expose its internal layout. So yeah, it would be nice to have a dedicated method for it.

Here's a workaround with a hacky pointer arithmetic:

    let rcell = Rc::new(RefCell::new(123));
    let cell_start = (&*rcell) as *const RefCell<_> as *const u8;
    let tmp = rcell.borrow();
    let data_start = (&*tmp) as *const i32 as *const u8;
    drop(tmp);
    let cell_offset = unsafe { data_start.offset_from(cell_start) };
    let cell_raw = Rc::into_raw(rcell);
    let data_raw = unsafe { (cell_raw as *mut u8).offset(cell_offset) as *mut i32 };
    eprintln!("{}", unsafe { *data_raw });
    
    unsafe { *data_raw = 456; }
    
    let rc_raw = unsafe { (data_raw as *mut u8).offset(-cell_offset) as *mut RefCell<i32> };
    let rc = unsafe { Rc::from_raw(rc_raw) };
    eprintln!("{}", rc.borrow());
2 Likes

Seems exactly what I want.