Replace VecRange<T> with VecRef<[T]>

pull/1/head
Shad Amethyst 2 years ago
parent 7806c473b1
commit 11aeeaae50
Signed by: amethyst
GPG Key ID: D970C8DD1D6DEE36

@ -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:

@ -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<T> VecCell<T> {
///
/// let s = vec.borrow_range(0..2).unwrap(); // Gets elements 0 and 1
/// ```
pub fn borrow_range<'b, R: std::ops::RangeBounds<usize>>(&'b self, range: R) -> Option<VecRange<'b, T>> {
VecRange::new(self, range)
pub fn borrow_range<'b, R: std::ops::RangeBounds<usize>>(&'b self, range: R) -> Option<VecRef<'b, [T]>> {
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<T: fmt::Debug> fmt::Debug for VecCell<T> {
impl<T: Debug> fmt::Debug for BorrowStatus<VecRef<'_, T>> {
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)"),
}
}

@ -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<T>, index: usize) -> Option<Self>
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<R: RangeBounds<usize>>(vec: &'a VecCell<T>, range: R) -> Option<VecRef<'a, [T]>>
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<T>] = &vec.inner[(low, high)];
let range: &[T] = unsafe {
let ptr: *const UnsafeCell<T> = range.as_ptr();
let len = range.len();
assert!(ptr as *const () == UnsafeCell::raw_get(ptr) as *const ());
assert!(size_of::<UnsafeCell<T>>() == size_of::<T>());
assert!(align_of::<UnsafeCell<T>>() == align_of::<T>());
// 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<T>`
// - UnsafeCell has repr(transparent)
// - size_of(UnsafeCell<T>) == size_of(T)
// - align_of(UnsafeCell<T>) == align_of(T)
// - thus, [UnsafeCell<T>] 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<String> = 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<String> = 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<VecRef<'a, T>> {
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<T> 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<T>],
}
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<R: RangeBounds<usize>>(vec: &'a VecCell<T>, range: R) -> Option<VecRange<'a, T>>
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<VecRef<'a, T>> {
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<VecRange<'a, T>> for VecRef<'a, [T]>?
impl<'a, T> From<VecRange<'a, T>> for VecRef<'a, [UnsafeCell<T>]> {
fn from(range: VecRange<'a, T>) -> Self {
Self {
borrows: range.borrows,
value: range.range, // :3
}
}
}
impl<'a, T> std::ops::Index<usize> 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<T>>,
}
impl<'a, T> Iterator for VecRangeIter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|x| {
unsafe {
// SAFETY: immutability is guaranteed by VecRange's type invariants
x.get().as_ref().unwrap()
}
})
}
}

Loading…
Cancel
Save