It feels like this shouldn’t require unsafe; here’s what I came up with:
use std::ops::{Deref,DerefMut};
pub struct HoistMut<Ptr>(Ptr);
impl<Ptr> Deref for HoistMut<Ptr>
where Ptr: Proxy, Ptr::InnerPtr: Deref {
type Target=Ptr;
fn deref(&self)->&Ptr { &self.0 }
}
impl<Ptr> DerefMut for HoistMut<Ptr>
where Self:Deref<Target=Ptr>, Ptr: Proxy, Ptr::InnerPtr: DerefMut {
fn deref_mut(&mut self)->&mut Ptr { &mut self.0 }
}
pub trait Proxy {
type InnerPtr;
}
pub struct S;
pub struct R<Ptr> {
s: Ptr,
i: u32,
}
impl<Ptr:Deref> R<Ptr> {
fn as_ref(&self)->R<&'_ Ptr::Target> {
R { s:self.s.deref(), i: self.i }
}
pub fn new(s:Ptr, i: u32)->HoistMut<Self>
where Ptr: Deref<Target=S> {
HoistMut ( R { s, i } )
}
}
impl<Ptr> Proxy for R<Ptr> {
type InnerPtr=Ptr;
}
trait T {
fn by_ref(&self);
fn by_mut(&mut self);
}
impl<'a> T for R<&'a S> {
fn by_ref(&self) { dbg!("&'a by_ref"); }
fn by_mut(&mut self) {
// module only provides HoistMut<R<_>> to outside
unreachable!();
}
}
impl<'a> T for R<&'a mut S> {
fn by_ref(&self) { self.as_ref().by_ref() }
fn by_mut(&mut self) { dbg!("&'a mut by_mut"); }
}