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