After someone mentioned it (cannot remember who), I was trying to find a way to only borrow few fields of a struct, instead of borrowing the whole struct.
struct Foo {
a: i32,
b: String,
}
impl Foo {
fn a_as_ref(&self) -> &i32 {
&self.a
}
fn b_as_ref_mut(&mut self) -> &mut String {
&mut self.b
}
fn do_a_thing(mut self) {
// This wont compile:
// error[E0502]: cannot borrow `self` as mutable because it is also borrowed as immutable
let a = self.a_as_ref();
// ---- immutable borrow occurs here
let b = self.b_as_ref_mut();
// ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
fn use_a_and_b(_: &i32, _: &mut String) { /* code */ }
use_a_and_b(a, b);
// - immutable borrow later used here
}
fn do_a_thing_fixed(mut self) {
// Sometimes this can avoided by cloning or accessing the fields directly,
// but depending on the use case this may not be possible
fn use_a_and_b(_: &i32, _: &mut String) { /* code */ }
use_a_and_b(&self.a, &mut self.b)
}
}
So I came up with this code which is possibly sound (?) (at least MIRI doesn't complain)
Code
#![feature(arbitrary_self_types)]
use core::ptr::NonNull;
use core::ptr::addr_of;
use core::ptr::addr_of_mut;
use core::ops::Deref;
use core::ops::DerefMut;
use core::marker::PhantomData;
#[derive(Debug, Default)]
struct Vecs<T> {
from: Vec<T>,
into: Vec<T>,
}
struct MayAlias<'a, T>(
///
/// # Invariant
///
/// This pointer is always valid to dereference
///
NonNull<T>,
PhantomData<&'a mut T>,
);
impl<'a, T> MayAlias<'a, T> {
fn new(ref_mut: &'a mut T) -> Self {
Self(NonNull::from(ref_mut), PhantomData)
}
unsafe fn as_ref<U>(&self, f: impl FnOnce(&Self) -> *const U) -> &'a U {
&*f(self)
}
unsafe fn as_ref_mut<U>(&mut self, f: impl FnOnce(&mut Self) -> *mut U) -> &'a mut U {
&mut *f(self)
}
}
impl<'a, T> Deref for MayAlias<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { self.as_ref(|this| this.0.as_ptr()) }
}
}
impl<'a, T> DerefMut for MayAlias<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { self.as_ref_mut(|this| this.0.as_ptr()) }
}
}
impl<T> Vecs<T> {
fn push(&mut self, item: T) {
self.from.push(item)
}
fn _iter(from: &Vec<T>) -> impl Iterator<Item = &T> {
from.iter()
}
fn _extend(into: &mut Vec<T>, iter: impl IntoIterator<Item = T>) {
into.extend(iter)
}
///
/// # Invariant
///
/// This function borrows `self.from`
///
/// # Safety
///
/// `self.from` may not be mutably borrowed (`self` may not be mutably borrowed either)
///
unsafe fn iter<'a>(self: &MayAlias<'a, Self>) -> impl Iterator<Item = &'a T> {
Self::_iter(self.as_ref(|this| addr_of!(this.from)))
}
///
/// # Invariant
///
/// This funcion borrows `self.into` as mutable
///
/// # Safety
///
/// `self.into` may not be borrowed (`self` may not be borrowed either)
///
unsafe fn extend<'a>(self: &mut MayAlias<'a, Self>, iter: impl IntoIterator<Item = T>) {
Self::_extend(self.as_ref_mut(|this| addr_of_mut!(this.into)), iter)
}
}
fn main() {
let mut vr = Vecs::default();
vr.push(0);
vr.push(1);
vr.push(2);
vr.push(3);
let mut may_alias = MayAlias::new(&mut vr);
unsafe {
//
// This is possibly safe because:
//
// * `Self::iter` only borrows `self.from`
// * `Self::extend` only borrows `self.into`
//
may_alias.extend(
may_alias
.iter()
.filter(|a| *a % 3 == 0)
.copied()
.flat_map(|n| [n + 1, n + 4]),
)
};
println!("{:#?}", vr)
}