diff --git a/README.md b/README.md index 02db5ea..fee2c6c 100644 --- a/README.md +++ b/README.md @@ -43,10 +43,10 @@ let first = arr.borrow(0).unwrap(); // Borrow the first element immutably *third *= *first; // Multiply the third element by the first element -println!("{}", third.get()); // Prints 64 +println!("{}", &*third); // Prints 64 std::mem::drop(third); // Drop the mutable borrow -println!("{}", arr.borrow(2).unwrap().get()); // Also prints 64 +println!("{}", *arr.borrow(2).unwrap()); // Also prints 64 ``` However, to prevent aliasing, while an element is borrowed mutably, it cannot be borrowed immutably: diff --git a/src/lib.rs b/src/lib.rs index 52e1821..67d6143 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,7 @@ use std::fmt::{self, Debug}; use std::ops::{Deref, DerefMut}; mod vecref; -pub use vecref::{VecRef, VecRange, VecRangeIter}; +pub use vecref::VecRef; mod vecrefmut; pub use vecrefmut::VecRefMut; @@ -65,7 +65,7 @@ pub use vecrefmut::VecRefMut; /// let prev = vec.borrow(index - 1).unwrap(); /// /// // Give both references to update -/// update(current.get_mut(), prev.get()); +/// update(&mut *current, &*prev); /// } /// /// assert_eq!(vec, vec![0, 1, 3, 6, 10, 15, 21, 28, 36, 45]); @@ -353,8 +353,8 @@ impl VecCell { /// /// let s = vec.borrow_range(0..2).unwrap(); // Gets elements 0 and 1 /// ``` - pub fn borrow_range<'b, R: std::ops::RangeBounds>(&'b self, range: R) -> Option> { - VecRange::new(self, range) + pub fn borrow_range<'b, R: std::ops::RangeBounds>(&'b self, range: R) -> Option> { + VecRef::from_range(self, range) } /// Borrows the `index`-th element mutably, if it exists and no mutable *or immutable* borrow are active. @@ -587,7 +587,7 @@ impl fmt::Debug for VecCell { impl fmt::Debug for BorrowStatus> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - BorrowStatus::Ok(x) => fmt::Debug::fmt(x.get(), f), + BorrowStatus::Ok(x) => fmt::Debug::fmt(&*x, f), BorrowStatus::Borrowed => write!(f, "(borrowed)"), } } diff --git a/src/vecref.rs b/src/vecref.rs index 5c6ccaa..10f0213 100644 --- a/src/vecref.rs +++ b/src/vecref.rs @@ -18,12 +18,13 @@ impl<'a, T: ?Sized> VecRef<'a, T> { /// /// If `Some(self)` is returned, then: /// - no mutable reference exist to `*self` - /// - `∀ t: min('a, 'self)`, no new mutable reference can be made to `*self` + /// - `∀ t: min('a, 'self)`, no new mutable reference can be made to `*self` during `'t` pub(crate) fn new(vec: &'a VecCell, index: usize) -> Option where T: Sized { if vec.mut_borrow.get() == Some(index) { + // `vec[index]` is already borrowed mutably, return None return None } @@ -34,12 +35,67 @@ impl<'a, T: ?Sized> VecRef<'a, T> { Some(Self { borrows: VecRefBorrow::new(&vec.borrows)?, value: unsafe { - // SAFETY: there are no mutable borrows of vec.inner[index] + // SAFETY: there are no mutable borrows of vec.inner[index] (from vec.mut_borrow == None) vec.get_unchecked(index) } }) } + pub(crate) fn from_range>(vec: &'a VecCell, range: R) -> Option> + where + T: Sized + { + use std::mem::{size_of, align_of}; + + match vec.mut_borrow() { + Some(index) => { + if range.contains(&index) { + // There is a mutable borrow to an index within the range, return None + return None; + } + }, + None => {} + } + + let low = range.start_bound().cloned(); + let high = range.end_bound().cloned(); + + let range: &[UnsafeCell] = &vec.inner[(low, high)]; + let range: &[T] = unsafe { + let ptr: *const UnsafeCell = range.as_ptr(); + let len = range.len(); + + assert!(ptr as *const () == UnsafeCell::raw_get(ptr) as *const ()); + assert!(size_of::>() == size_of::()); + assert!(align_of::>() == align_of::()); + + // SAFETY: + // - ptr is a valid pointer + // - there are no mutable reference to any element within (low, high) + // - ptr == old(ptr), since UnsafeCell has repr(transparent) (also asserted) + let ptr: *mut T = UnsafeCell::raw_get(ptr); + let ptr = ptr as *const T; + + // SAFETY: + // - `ptr` is a valid pointer + // - `ptr` points to an array of `len` elements of type `UnsafeCell` + // - UnsafeCell has repr(transparent) + // - size_of(UnsafeCell) == size_of(T) + // - align_of(UnsafeCell) == align_of(T) + // - thus, [UnsafeCell] and [T] have the same representation in memory + // - thus, ptr points to an array of `len` elements of type `T` + // - there are no mutable reference to any element of `slice` + let slice: &[T] = std::slice::from_raw_parts(ptr, len); + + slice + }; + + Some(VecRef { + borrows: VecRefBorrow::new(&vec.borrows)?, + value: range, + }) + } + fn from(value: &'a T, borrows: VecRefBorrow<'a>) -> Self { Self { borrows, @@ -47,26 +103,26 @@ impl<'a, T: ?Sized> VecRef<'a, T> { } } - /// Returns a reference to the borrowed value. - /// Equivalent to `&*vec_ref`. - /// - /// The reference may not outlive this `VecRef` instance. - /// - /// # Example - /// - /// ``` - /// # use veccell::*; - /// let mut vec: VecCell = VecCell::new(); - /// - /// vec.push(String::from("hello")); - /// vec.push(String::from("world")); - /// - /// let guard = vec.borrow(0).unwrap(); - /// assert_eq!(guard.get(), "hello"); - /// ``` - pub fn get(&self) -> &T { - &*self.value - } + // /// Returns a reference to the borrowed value. + // /// Equivalent to `&*vec_ref`. + // /// + // /// The reference may not outlive this `VecRef` instance. + // /// + // /// # Example + // /// + // /// ``` + // /// # use veccell::*; + // /// let mut vec: VecCell = VecCell::new(); + // /// + // /// vec.push(String::from("hello")); + // /// vec.push(String::from("world")); + // /// + // /// let guard = vec.borrow(0).unwrap(); + // /// assert_eq!(guard.get(), "hello"); + // /// ``` + // pub fn get(&self) -> &T { + // &*self.value + // } /// Transforms a `VecRef<'_, T>` into a `VecRef<'_, U>` from a function that maps `&T` to `&U`. /// @@ -112,6 +168,14 @@ impl<'a, T: ?Sized> VecRef<'a, T> { } } +impl<'a, T: Sized> VecRef<'a, [T]> { + /// Returns an immutable borrow to the `index`-th element of the array. + /// Returns `None` if `index` is out of bounds. + pub fn borrow(&self, index: usize) -> Option> { + Some(VecRef::from(self.value.get(index)?, self.borrows.clone())) + } +} + impl<'a, T: ?Sized> Deref for VecRef<'a, T> { type Target = T; @@ -130,13 +194,13 @@ impl<'a, T: Debug + Sized> Debug for VecRef<'a, T> { impl<'a, T: PartialEq + ?Sized> PartialEq for VecRef<'a, T> { fn eq(&self, other: &Self) -> bool { - self.get() == other.get() + self.value == other.value } } impl<'a, T: PartialEq + ?Sized> PartialEq for VecRef<'a, T> { fn eq(&self, other: &T) -> bool { - self.get() == other + self.value == other } } @@ -162,134 +226,3 @@ impl<'a> Drop for VecRefBorrow<'a> { self.0.set(self.0.get() - 1); } } - -/// Represents an immutable slice for a [`VecCell`]. -/// -/// # Guarantees -/// -/// All of the elements of the VecRange are guaranteed to only be borrowed immutably. -pub struct VecRange<'a, T> { - borrows: VecRefBorrow<'a>, - range: &'a [UnsafeCell], -} - -impl<'a, T> VecRange<'a, T> { - /// # Guarantees - /// - /// If `Some(self)` is returned, then: - /// - no mutable reference exist to `∀ x ∈ self.range` - /// - `∀ t ∈ min('a, 'self), ∀ x ∈ self.range`, no mutable borrow can be made to `x` - pub(crate) fn new>(vec: &'a VecCell, range: R) -> Option> - where - T: Sized - { - match vec.mut_borrow() { - Some(index) => { - if range.contains(&index) { - return None; // There is still a mutable borrow to an index within the range - } - }, - None => {} - } - - let low = range.start_bound().cloned(); - let high = range.end_bound().cloned(); - - Some(VecRange { - borrows: VecRefBorrow::new(&vec.borrows)?, - range: &vec.inner[(low, high)], - }) - } - - /// Returns an immutable reference to the `index`-th element of the slice, if it is within bounds. - /// - /// The reference may not outlive this instance of `VecRange`. - pub fn get<'b>(&'b self, index: usize) -> Option<&'b T> where 'a: 'b { - let elem = self.range.get(index)?; - Some(unsafe { - // SAFETY: VecRange's type invariants guarantee that no mutable reference to self.range[index] exist now - // elem.get() is a valid pointer - // ('a: 'b) -> the &'b T reference cannot outlive 'a - // (self.borrows: VecRefBorrow<'a>) -> no new mutable reference can be made for 'b to self.range[index] - elem.get().as_ref().unwrap() - }) - } - - /// Returns an immutable borrow to the `index`-th element of the slice, if it is within bounds. - /// - /// The returned [`VecRef`] increments the immutable reference counter of the parent [`VecCell`]. - pub fn borrow(self: &VecRange<'a, T>, index: usize) -> Option> { - let VecRange { borrows, range } = self.clone(); - let elem = range.get(index)?; - - Some(unsafe { - // SAFETY: VecRange's type invariants guarantee that no mutable reference to self.range[index] exist now - // elem.get() is a valid pointer - // borrows: VecRefBorrow<'a>, thus under VecRef's invariants, no access beyond 'a to elem can be made - VecRef::from(elem.get().as_ref().unwrap(), borrows) - }) - } - - pub fn len(&self) -> usize { - self.range.len() - } -} - -// TODO: use std::mem::transmute to implement From> for VecRef<'a, [T]>? -impl<'a, T> From> for VecRef<'a, [UnsafeCell]> { - fn from(range: VecRange<'a, T>) -> Self { - Self { - borrows: range.borrows, - value: range.range, // :3 - } - } -} - -impl<'a, T> std::ops::Index for VecRange<'a, T> { - type Output = T; - - fn index(&self, index: usize) -> &Self::Output { - match self.get(index) { - Some(elem) => elem, - None => panic!("Index out of bounds: len is {} but index is {}", self.len(), index) - } - } -} - -impl<'a, T> Clone for VecRange<'a, T> { - /// The data pointed to by VecRange is already borrows immutably, so it can be safely cloned. - fn clone(&self) -> Self { - Self { - borrows: self.borrows.clone(), - range: self.range, - } - } -} - -impl<'a, T> IntoIterator for VecRange<'a, T> { - type Item = &'a T; - type IntoIter = VecRangeIter<'a, T>; - - fn into_iter(self) -> Self::IntoIter { - VecRangeIter { - iter: self.range.iter() - } - } -} - -pub struct VecRangeIter<'a, T> { - iter: std::slice::Iter<'a, UnsafeCell>, -} - -impl<'a, T> Iterator for VecRangeIter<'a, T> { - type Item = &'a T; - - fn next(&mut self) -> Option { - self.iter.next().map(|x| { - unsafe { - // SAFETY: immutability is guaranteed by VecRange's type invariants - x.get().as_ref().unwrap() - } - }) - } -}