How can I reinterpret a RefMut<T> as a RefMut<U>

Viewed 65

I have a collection containing elements wrapped in RefCell that I borrow. I have a wrapper struct to make the api usable like so:

pub struct RefWrapper<'a, T> {
    inner: RefMut<'a, T>,
}

impl<T> Deref for RefWrapper<T> {
    type Target = T;
    fn deref(&self) -> &T { &self.inner }
}

impl<T> DerefMut for RefWrapper<T> {
    fn deref_mut(&mut self) -> &mut T { &mut self.inner }
}

Foo and Bar have the same memory layout, so I can safely transmute between references of them, however RefMut is not repr(C) and transmuting would be unsound for other reasons, so I can't safely transmute RefWrapper<Foo> into RefWrapper<Bar>. is there any way to convert from RefWrapper<Foo> to RefWrapper<Bar>?

1 Answers

If you can get a &mut U from a &mut T, then you can use RefMut::map.

Here as a code example:

use std::cell::{RefCell, RefMut};

#[repr(C)]
#[derive(Debug)]
struct Foo {
    a: i32,
    b: i32,
}

#[repr(C)]
#[derive(Debug)]
struct Bar {
    a: i32,
    b: i32,
}

fn convert_foo_to_bar(foo: &mut Foo) -> &mut Bar {
    unsafe { std::mem::transmute(foo) }
}

fn main() {
    let foo = RefCell::new(Foo { a: 42, b: 69 });

    {
        let foo_ref = foo.borrow_mut();
        let mut bar_ref = RefMut::map(foo_ref, convert_foo_to_bar);

        println!("{:?}", bar_ref);

        bar_ref.b = 420;
    }

    println!("{:?}", foo);
}
Bar { a: 42, b: 69 }
RefCell { value: Foo { a: 42, b: 420 } }

Be aware that his requires manually keeping the memory layout of Foo and Bar in sync. This will create very subtle and hard-to-find bugs if Foo and Bar are not 100% identical.

Of course one could generalize the concept by implementing From/Into for &mut Foo and &mut Bar instead of using convert_foo_to_bar. You can then use this trait to for your RefWrapper to convert between the two.

Related