❇️ VecRange improvements

pull/1/head
Shad Amethyst 2 years ago
parent b090e7a2df
commit 54349d1d26
Signed by: amethyst
GPG Key ID: D970C8DD1D6DEE36

@ -351,9 +351,9 @@ impl<T> VecCell<T> {
/// vec.push(2);
/// vec.push(3);
///
/// let s = vec.get_range(0..2); // Gets elements 0 and 1
/// let s = vec.borrow_range(0..2); // Gets elements 0 and 1
/// ```
pub fn get_range<'b, R: std::ops::RangeBounds<usize>>(&'b self, range: R) -> Option<VecRange<'b, T>> {
pub fn borrow_range<'b, R: std::ops::RangeBounds<usize>>(&'b self, range: R) -> Option<VecRange<'b, T>> {
VecRange::new(self, range)
}

@ -213,3 +213,61 @@ fn test_iter_panic() {
std::mem::drop(y);
}
#[test]
fn test_range() {
let mut vec: VecCell<usize> = VecCell::new();
for x in 0..10 {
vec.push(x);
}
let mut_ref = vec.borrow_mut(3);
// Check that it is impossible to reference the same element as mut_ref
assert!(vec.borrow_range(0..10).is_none());
assert!(vec.borrow_range(0..=3).is_none());
assert!(vec.borrow_range(0..4).is_none());
assert!(vec.borrow_range(3..4).is_none());
assert!(vec.borrow_range(3..=3).is_none());
assert!(vec.borrow_range(3..).is_none());
assert!(vec.borrow_range(0..).is_none());
assert!(vec.borrow_range(..4).is_none());
assert!(vec.borrow_range(..=4).is_none());
let range = vec.borrow_range(4..7).unwrap();
for x in 0..5 {
if x < 3 {
assert!(range.get(x).is_some());
assert!(range.borrow(x).is_some());
assert_eq!(range[x], x + 4);
} else {
assert!(range.get(x).is_none());
assert!(range.borrow(x).is_none());
}
}
let range = vec.borrow_range(5..).unwrap();
for x in 0..10 {
if x < 5 {
assert!(range.get(x).is_some());
assert!(range.borrow(x).is_some());
assert_eq!(range[x], x + 5);
} else {
assert!(range.get(x).is_none());
assert!(range.borrow(x).is_none());
}
}
let elem = vec.borrow_range(5..).unwrap().borrow(1).unwrap();
assert_eq!(*elem, 6);
std::mem::drop(mut_ref);
assert!(vec.borrow_mut(1).is_none()); // elem is still borrowed
std::mem::drop(elem);
}

@ -1,7 +1,12 @@
use super::*;
use std::ops::RangeBounds;
// `'self`: lifetime of `Self`
/// Wraps a borrowed reference from a [`VecCell`].
///
/// When an instance of `VecRef` is created, the immutable borrow counter of its parent [`VecCell`] is incremented.
/// Once that instance is [`Drop`ped](Drop), the immutable borrow counter is decremented.
#[derive(Clone)]
pub struct VecRef<'a, T: ?Sized> {
borrows: VecRefBorrow<'a>,
@ -9,6 +14,11 @@ pub struct VecRef<'a, T: ?Sized> {
}
impl<'a, T: ?Sized> VecRef<'a, T> {
/// # Guarantees
///
/// 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`
pub(crate) fn new(vec: &'a VecCell<T>, index: usize) -> Option<Self>
where
T: Sized
@ -30,11 +40,11 @@ impl<'a, T: ?Sized> VecRef<'a, T> {
})
}
fn from(value: &'a T, borrows: &'a Cell<usize>) -> Option<Self> {
Some(Self {
borrows: VecRefBorrow::new(borrows)?,
fn from(value: &'a T, borrows: VecRefBorrow<'a>) -> Self {
Self {
borrows,
value
})
}
}
/// Returns a reference to the borrowed value.
@ -84,7 +94,7 @@ impl<'a, T: ?Sized> VecRef<'a, T> {
where
F: FnOnce(&T) -> &U
{
VecRef::from(f(original.value), &original.borrows.0).expect("Error creating a new VecRef: integer overflow")
VecRef::from(f(original.value), original.borrows.clone())
// original is dropped here
}
}
@ -144,14 +154,18 @@ impl<'a> Drop for VecRefBorrow<'a> {
///
/// # Guarantees
///
/// All of the elements of the VecRange are guaranteed to be immutable.
#[derive(Clone)]
/// 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
@ -174,12 +188,38 @@ impl<'a, T> VecRange<'a, T> {
})
}
pub fn get(&self, index: usize) -> Option<&T> {
/// 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: immutability is guaranteed by VecRange's type invariants
self.range.get(index)?.get().as_ref().unwrap()
// 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()
}
}
impl<'a, T> From<VecRange<'a, T>> for VecRef<'a, [UnsafeCell<T>]> {
@ -195,9 +235,19 @@ impl<'a, T> std::ops::Index<usize> for VecRange<'a, T> {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
unsafe {
// SAFETY: immutability is guaranteed by VecRange's type invariants
self.range[index].get().as_ref().unwrap()
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,
}
}
}

Loading…
Cancel
Save