Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

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

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>?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

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 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.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading