use core::{convert::Infallible, mem, ptr};
use crate::ghost_cell::*;
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
pub struct GhostAliasingError;
impl From<Infallible> for GhostAliasingError {
fn from(_: Infallible) -> Self {
unreachable!("Infallible cannot be constructed")
}
}
pub trait GhostBorrowMut<'a, 'brand> {
type Result;
type Error: Into<GhostAliasingError>;
fn borrow_mut(self, token: &'a mut GhostToken<'brand>) -> Result<Self::Result, Self::Error>;
unsafe fn borrow_mut_unchecked(self, token: &'a mut GhostToken<'brand>) -> Self::Result;
}
impl<'a, 'brand, T> GhostBorrowMut<'a, 'brand> for &'a [GhostCell<'brand, T>] {
type Result = &'a mut [T];
type Error = Infallible;
fn borrow_mut(self, token: &'a mut GhostToken<'brand>) -> Result<Self::Result, Self::Error> {
Ok(unsafe { self.borrow_mut_unchecked(token) })
}
unsafe fn borrow_mut_unchecked(self, _: &'a mut GhostToken<'brand>) -> Self::Result {
#[allow(mutable_transmutes)]
mem::transmute::<Self, Self::Result>(self)
}
}
impl<'a, 'brand, T, const N: usize> GhostBorrowMut<'a, 'brand> for &'a [GhostCell<'brand, T>; N] {
type Result = &'a mut [T; N];
type Error = Infallible;
fn borrow_mut(self, token: &'a mut GhostToken<'brand>) -> Result<Self::Result, Self::Error> {
Ok(unsafe { self.borrow_mut_unchecked(token) })
}
unsafe fn borrow_mut_unchecked(self, _: &'a mut GhostToken<'brand>) -> Self::Result {
#[allow(mutable_transmutes)]
mem::transmute::<Self, Self::Result>(self)
}
}
impl<'a, 'brand, T: ?Sized, const N: usize> GhostBorrowMut<'a, 'brand> for [&'a GhostCell<'brand, T>; N] {
type Result = [&'a mut T; N];
type Error = GhostAliasingError;
fn borrow_mut(self, token: &'a mut GhostToken<'brand>) -> Result<Self::Result, Self::Error> {
check_distinct(self.map(get_span))?;
Ok(unsafe { self.borrow_mut_unchecked(token) })
}
unsafe fn borrow_mut_unchecked(self, _: &'a mut GhostToken<'brand>) -> Self::Result {
ptr::read(&self as *const _ as *const Self::Result)
}
}
macro_rules! last {
() => {};
($head:ident $(,)?) => {
$head
};
($head:ident, $($tail:ident),+ $(,)?) => {
last!($($tail),+)
};
}
macro_rules! generate_public_instance {
( $($name:ident),* ; $($type_letter:ident),* ) => {
impl<'a, 'brand, $($type_letter: ?Sized,)*> GhostBorrowMut<'a, 'brand>
for ( $(&'a GhostCell<'brand, $type_letter>, )* )
{
type Result = ( $(&'a mut $type_letter, )* );
type Error = GhostAliasingError;
fn borrow_mut(self, token: &'a mut GhostToken<'brand>) -> Result<Self::Result, Self::Error> {
let ($($name,)*) = self;
check_distinct([ $( get_span($name), )* ])?;
Ok(unsafe { self.borrow_mut_unchecked(token) })
}
unsafe fn borrow_mut_unchecked(self, _: &'a mut GhostToken<'brand>) -> Self::Result {
let ($($name,)*) = self;
( $( &mut * $name.as_ptr(),)* )
}
}
impl<'a, 'brand, $($type_letter,)*> GhostBorrowMut<'a, 'brand>
for &'a ( $(GhostCell<'brand, $type_letter>, )* )
where
last!( $($type_letter),* ): ?Sized
{
type Result = &'a mut ( $($type_letter, )* );
type Error = Infallible;
fn borrow_mut(self, token: &'a mut GhostToken<'brand>) -> Result<Self::Result, Self::Error> {
Ok(unsafe { self.borrow_mut_unchecked(token) })
}
unsafe fn borrow_mut_unchecked(self, _: &'a mut GhostToken<'brand>) -> Self::Result {
#[allow(mutable_transmutes)]
core::mem::transmute::<Self, Self::Result>(self)
}
}
};
}
generate_public_instance!(a ; T0);
generate_public_instance!(a, b ; T0, T1);
generate_public_instance!(a, b, c ; T0, T1, T2);
generate_public_instance!(a, b, c, d ; T0, T1, T2, T3);
generate_public_instance!(a, b, c, d, e ; T0, T1, T2, T3, T4);
generate_public_instance!(a, b, c, d, e, f ; T0, T1, T2, T3, T4, T5);
generate_public_instance!(a, b, c, d, e, f, g ; T0, T1, T2, T3, T4, T5, T6);
generate_public_instance!(a, b, c, d, e, f, g, h ; T0, T1, T2, T3, T4, T5, T6, T7);
generate_public_instance!(a, b, c, d, e, f, g, h, i ; T0, T1, T2, T3, T4, T5, T6, T7, T8);
generate_public_instance!(a, b, c, d, e, f, g, h, i, j ; T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
generate_public_instance!(a, b, c, d, e, f, g, h, i, j, k ; T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA);
generate_public_instance!(a, b, c, d, e, f, g, h, i, j, k, l ; T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB);
fn get_span<T: ?Sized>(value: &T) -> (usize, usize) {
let value_size = mem::size_of_val(value);
let offset = if value_size == 0 { 0 } else { value_size - 1 };
let start = value as *const T as *const u8 as usize;
(start, start + offset)
}
fn check_distinct<const N: usize>(mut array: [(usize, usize); N]) -> Result<(), GhostAliasingError> {
array.sort_unstable_by_key(|t| t.0);
for window in array.windows(2) {
let (left, right) = unsafe { (window.get_unchecked(0), window.get_unchecked(1)) };
if left.1 >= right.0 {
return Err(GhostAliasingError);
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn multiple_borrows_tuple() {
let value = GhostToken::new(|mut token| {
let cell1 = GhostCell::new(42);
let cell2 = GhostCell::new(47);
let cell3 = GhostCell::new(7);
let cell4 = GhostCell::new(9);
let (reference1, reference2, reference3, reference4): (&mut i32, &mut i32, &mut i32, &mut i32) =
(&cell1, &cell2, &cell3, &cell4).borrow_mut(&mut token).unwrap();
*reference1 = 33;
*reference2 = 34;
*reference3 = 35;
*reference4 = 36;
(*cell1.borrow(&token), *cell2.borrow(&token), *cell3.borrow(&token))
});
assert_eq!((33, 34, 35), value);
}
#[test]
#[should_panic]
fn multiple_borrows_tuple_aliased() {
GhostToken::new(|mut token| {
let cell1 = GhostCell::new(42);
let cell2 = GhostCell::new(47);
let cell3 = GhostCell::new(7);
let _: (&mut i32, &mut i32, &mut i32, &mut i32) =
(&cell1, &cell2, &cell3, &cell2).borrow_mut(&mut token).unwrap();
});
}
#[test]
fn multiple_borrows_tuple_ref() {
let value = GhostToken::new(|mut token| {
let cell1 = GhostCell::new(42);
let cell2 = GhostCell::new(47);
let cell3 = GhostCell::new(7);
let cell4 = GhostCell::new(9);
let tuple = (cell1, cell2, cell3, cell4);
let reference: &mut (i32, i32, i32, i32) = tuple.borrow_mut(&mut token).unwrap();
reference.0 = 33;
reference.1 = 34;
reference.2 = 35;
reference.3 = 36;
(
*tuple.0.borrow(&token),
*tuple.1.borrow(&token),
*tuple.2.borrow(&token),
)
});
assert_eq!((33, 34, 35), value);
}
#[test]
fn multiple_borrows_array_ref() {
let value = GhostToken::new(|mut token| {
let cell1 = GhostCell::new(42);
let cell2 = GhostCell::new(47);
let cell3 = GhostCell::new(7);
let cell4 = GhostCell::new(9);
let array = [cell1, cell2, cell3, cell4];
let reference: &mut [i32; 4] = array.borrow_mut(&mut token).unwrap();
reference[0] = 33;
reference[1] = 34;
reference[2] = 35;
reference[3] = 36;
(
*array[0].borrow(&token),
*array[1].borrow(&token),
*array[2].borrow(&token),
)
});
assert_eq!((33, 34, 35), value);
}
#[test]
#[should_panic]
fn multiple_borrows_single_slice_overlap() {
GhostToken::new(|mut token| {
let mut array = [3, 7];
let cell_of_slice = &*GhostCell::from_mut(&mut array[..]);
let slice_of_cells = cell_of_slice.as_slice_of_cells();
let second_cell = &slice_of_cells[1];
let _ = (second_cell, cell_of_slice).borrow_mut(&mut token).unwrap();
});
}
#[test]
#[should_panic]
fn multiple_borrows_single_array_overlap() {
GhostToken::new(|mut token| {
let cell_of_array = GhostCell::new([3, 7]);
let slice_of_cells = (&cell_of_array as &GhostCell<[i32]>).as_slice_of_cells();
let second_cell = &slice_of_cells[1];
let _ = (second_cell, &cell_of_array).borrow_mut(&mut token).unwrap();
});
}
trait Store {
type Item;
fn get(&self) -> Self::Item;
fn set(&mut self, x: Self::Item);
}
impl Store for i32 {
type Item = Self;
fn get(&self) -> Self::Item {
*self
}
fn set(&mut self, x: Self::Item) {
*self = x;
}
}
#[test]
fn multiple_borrows_tuple_unsized() {
let value = GhostToken::new(|mut token| {
let mut data1 = 42;
let mut data2 = [47];
let mut data3 = 7;
let mut data4 = [9];
let cell1 = &*GhostCell::from_mut(&mut data1 as &mut dyn Store<Item = i32>);
let cell2 = &*GhostCell::from_mut(&mut data2 as &mut [i32]);
let cell3 = &*GhostCell::from_mut(&mut data3 as &mut dyn Store<Item = i32>);
let cell4 = &*GhostCell::from_mut(&mut data4 as &mut [i32]);
let (reference1, reference2, reference3, reference4) =
(cell1, cell2, cell3, cell4).borrow_mut(&mut token).unwrap();
reference1.set(7);
reference3.set(42);
mem::swap(&mut reference2[0], &mut reference4[0]);
(reference1.get(), reference2[0], reference3.get(), reference4[0])
});
assert_eq!((7, 9, 42, 47), value);
}
#[test]
fn multiple_borrows_array_unsized_slice() {
let value = GhostToken::new(|mut token| {
let mut data1 = [42];
let mut data2 = [47];
let mut data3 = [7];
let mut data4 = [9];
let cell1 = &*GhostCell::from_mut(&mut data1 as &mut [i32]);
let cell2 = &*GhostCell::from_mut(&mut data2 as &mut [i32]);
let cell3 = &*GhostCell::from_mut(&mut data3 as &mut [i32]);
let cell4 = &*GhostCell::from_mut(&mut data4 as &mut [i32]);
let array = [cell1, cell2, cell3, cell4];
let reference: [&mut [i32]; 4] = array.borrow_mut(&mut token).unwrap();
reference[0][0] = 33;
reference[1][0] = 34;
reference[2][0] = 35;
reference[3][0] = 36;
(
array[0].borrow(&token)[0],
array[1].borrow(&token)[0],
array[2].borrow(&token)[0],
)
});
assert_eq!((33, 34, 35), value);
}
#[test]
fn multiple_borrows_array_unsized_dyn_trait() {
let value = GhostToken::new(|mut token| {
let mut data1 = 42;
let mut data2 = 47;
let mut data3 = 7;
let mut data4 = 9;
let cell1 = &*GhostCell::from_mut(&mut data1 as &mut dyn Store<Item = i32>);
let cell2 = &*GhostCell::from_mut(&mut data2 as &mut dyn Store<Item = i32>);
let cell3 = &*GhostCell::from_mut(&mut data3 as &mut dyn Store<Item = i32>);
let cell4 = &*GhostCell::from_mut(&mut data4 as &mut dyn Store<Item = i32>);
let array = [cell1, cell2, cell3, cell4];
let reference: [&mut dyn Store<Item = i32>; 4] = array.borrow_mut(&mut token).unwrap();
reference[0].set(33);
reference[1].set(34);
reference[2].set(35);
reference[3].set(36);
(
array[0].borrow(&token).get(),
array[1].borrow(&token).get(),
array[2].borrow(&token).get(),
)
});
assert_eq!((33, 34, 35), value);
}
#[test]
#[should_panic]
fn multiple_borrows_tuple_unsized_aliased() {
GhostToken::new(|mut token| {
let mut data1 = 42;
let mut data2 = [47];
let mut data3 = 7;
let cell1 = &*GhostCell::from_mut(&mut data1 as &mut dyn Store<Item = i32>);
let cell2 = &*GhostCell::from_mut(&mut data2 as &mut [i32]);
let cell3 = &*GhostCell::from_mut(&mut data3 as &mut dyn ToString);
let _: (&mut dyn Store<Item = i32>, &mut [i32], &mut dyn ToString, &mut [i32]) =
(cell1, cell2, cell3, cell2).borrow_mut(&mut token).unwrap();
});
}
#[test]
#[should_panic]
fn multiple_borrows_array_unsized_slice_aliased() {
GhostToken::new(|mut token| {
let mut data1 = [42];
let mut data2 = [47];
let mut data3 = [7];
let cell1 = &*GhostCell::from_mut(&mut data1 as &mut [i32]);
let cell2 = &*GhostCell::from_mut(&mut data2 as &mut [i32]);
let cell3 = &*GhostCell::from_mut(&mut data3 as &mut [i32]);
let array = [cell1, cell2, cell3, cell2];
let _: [&mut [i32]; 4] = array.borrow_mut(&mut token).unwrap();
});
}
#[test]
#[should_panic]
fn multiple_borrows_array_unsized_dyn_trait_aliased() {
GhostToken::new(|mut token| {
let mut data1 = 42;
let mut data2 = 47;
let mut data3 = 7;
let cell1 = &*GhostCell::from_mut(&mut data1 as &mut dyn Store<Item = i32>);
let cell2 = &*GhostCell::from_mut(&mut data2 as &mut dyn Store<Item = i32>);
let cell3 = &*GhostCell::from_mut(&mut data3 as &mut dyn Store<Item = i32>);
let array = [cell1, cell2, cell3, cell2];
let _: [&mut dyn Store<Item = i32>; 4] = array.borrow_mut(&mut token).unwrap();
});
}
#[test]
fn check_distinct() {
GhostToken::new(|mut token| {
let cells = [
GhostCell::new(1),
GhostCell::new(2),
GhostCell::new(3),
GhostCell::new(4),
GhostCell::new(5),
GhostCell::new(6),
];
let tuple1 = (&cells[0], &cells[1], &cells[2], &cells[3], &cells[4], &cells[5]);
assert!(tuple1.borrow_mut(&mut token).is_ok());
let tuple2 = (&cells[0], &cells[1], &cells[2], &cells[3], &cells[4], &cells[0]);
assert!(tuple2.borrow_mut(&mut token).is_err());
});
GhostToken::new(|mut token| {
let cells = [
GhostCell::new(1),
GhostCell::new(2),
GhostCell::new(3),
GhostCell::new(4),
GhostCell::new(5),
GhostCell::new(6),
GhostCell::new(7),
GhostCell::new(8),
GhostCell::new(9),
GhostCell::new(10),
GhostCell::new(11),
GhostCell::new(12),
];
let tuple1 = (
&cells[0], &cells[1], &cells[2], &cells[3], &cells[4], &cells[5], &cells[6], &cells[7], &cells[8],
&cells[9], &cells[10], &cells[11],
);
assert!(tuple1.borrow_mut(&mut token).is_ok());
let tuple2 = (
&cells[0], &cells[1], &cells[2], &cells[3], &cells[4], &cells[5], &cells[6], &cells[7], &cells[8],
&cells[9], &cells[10], &cells[0],
);
assert!(tuple2.borrow_mut(&mut token).is_err());
let tuple3 = (
&cells[0], &cells[0], &cells[1], &cells[3], &cells[4], &cells[5], &cells[6], &cells[7], &cells[8],
&cells[9], &cells[10], &cells[11],
);
assert!(tuple3.borrow_mut(&mut token).is_err());
let tuple4 = (
&cells[0], &cells[1], &cells[2], &cells[3], &cells[4], &cells[5], &cells[6], &cells[7], &cells[8],
&cells[9], &cells[10], &cells[10],
);
assert!(tuple4.borrow_mut(&mut token).is_err());
let tuple5 = (
&cells[0], &cells[1], &cells[2], &cells[3], &cells[4], &cells[5], &cells[5], &cells[7], &cells[8],
&cells[9], &cells[10], &cells[11],
);
assert!(tuple5.borrow_mut(&mut token).is_err());
});
}
#[test]
fn check_distinct_zst() {
GhostToken::new(|mut token| {
let zst = GhostCell::new(());
let tuple = (&zst, &zst);
assert!(tuple.borrow_mut(&mut token).is_err());
});
}
#[test]
fn check_distinct_inner_zst() {
GhostToken::new(|mut token| {
let outer = GhostCell::new((1, (), 2));
let (_, inner, _) = outer.as_tuple_of_cells();
let tuple = (&outer, inner);
assert!(tuple.borrow_mut(&mut token).is_err());
});
}
}