diff --git a/src/lib.rs b/src/lib.rs index b3b92f4..dafe60a 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; +pub use vecref::{VecRef, VecRange, VecRangeIter}; mod vecrefmut; pub use vecrefmut::VecRefMut; @@ -335,6 +335,28 @@ impl VecCell { VecRef::new(self, index) } + /// Borrows a range of elements, making sure that none of these elements are borrowed mutably already. + /// Returns `Some(VecRef(slice))` on success. + /// Returns `None` otherwise. + /// + /// To prevent aliasing, this function returns `None` if `self.mut_borrow().is_some()` and `self.mut_borrow().unwrap() ∈ range`. + /// + /// # Example + /// + /// ``` + /// # use veccell::*; + /// let mut vec: VecCell = VecCell::new(); + /// + /// vec.push(1); + /// vec.push(2); + /// vec.push(3); + /// + /// let s = vec.get_range(0..2); // Gets elements 0 and 1 + /// ``` + pub fn get_range<'b, R: std::ops::RangeBounds>(&'b self, range: R) -> Option> { + VecRange::new(self, range) + } + /// Borrows the `index`-th element mutably, if it exists and no mutable *or immutable* borrow are active. /// Returns `None` otherwise. /// diff --git a/src/vecref.rs b/src/vecref.rs index f1b9ea8..3c5e4d7 100644 --- a/src/vecref.rs +++ b/src/vecref.rs @@ -1,8 +1,10 @@ use super::*; +use std::ops::RangeBounds; /// Wraps a borrowed reference from a [`VecCell`]. +#[derive(Clone)] pub struct VecRef<'a, T: ?Sized> { - borrows: &'a Cell, + borrows: VecRefBorrow<'a>, value: &'a T, } @@ -19,10 +21,8 @@ impl<'a, T: ?Sized> VecRef<'a, T> { return None } - vec.borrows.set(vec.borrows.get().checked_add(1)?); - Some(Self { - borrows: &vec.borrows, + borrows: VecRefBorrow::new(&vec.borrows)?, value: unsafe { // SAFETY: there are no mutable borrows of vec.inner[index] vec.get_unchecked(index) @@ -31,10 +31,8 @@ impl<'a, T: ?Sized> VecRef<'a, T> { } fn from(value: &'a T, borrows: &'a Cell) -> Option { - borrows.set(borrows.get().checked_add(1)?); - Some(Self { - borrows, + borrows: VecRefBorrow::new(borrows)?, value }) } @@ -86,7 +84,7 @@ impl<'a, T: ?Sized> VecRef<'a, T> { where F: FnOnce(&T) -> &U { - VecRef::from(f(original.value), original.borrows).expect("Error creating a new VecRef: integer overflow") + VecRef::from(f(original.value), &original.borrows.0).expect("Error creating a new VecRef: integer overflow") // original is dropped here } } @@ -99,14 +97,6 @@ impl<'a, T: ?Sized> Deref for VecRef<'a, T> { } } -impl<'a, T: ?Sized> Drop for VecRef<'a, T> { - #[inline] - fn drop(&mut self) { - debug_assert!(self.borrows.get() > 0, "Borrow count was null yet there was still a borrow!"); - self.borrows.set(self.borrows.get() - 1); - } -} - impl<'a, T: Debug + Sized> Debug for VecRef<'a, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("VecRef") @@ -127,8 +117,115 @@ impl<'a, T: PartialEq + ?Sized> PartialEq for VecRef<'a, T> { } } -impl<'a, T: ?Sized> Clone for VecRef<'a, T> { +struct VecRefBorrow<'a>(&'a Cell); + +impl<'a> VecRefBorrow<'a> { + fn new(cell: &'a Cell) -> Option { + cell.set(cell.get().checked_add(1)?); + Some(Self(cell)) + } +} + +impl<'a> Clone for VecRefBorrow<'a> { fn clone(&self) -> Self { - Self::from(self.value, self.borrows).expect("Error creating a new VecRef: integer overflow") + VecRefBorrow::new(&self.0).expect("Error creating a new VecRef: integer overflow") + } +} + +impl<'a> Drop for VecRefBorrow<'a> { + #[inline] + fn drop(&mut self) { + debug_assert!(self.0.get() > 0, "Borrow count was null yet there was still a borrow!"); + 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 be immutable. +#[derive(Clone)] +pub struct VecRange<'a, T> { + borrows: VecRefBorrow<'a>, + range: &'a [UnsafeCell], +} + +impl<'a, T> VecRange<'a, T> { + 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)], + }) + } + + pub fn get(&self, index: usize) -> Option<&T> { + Some(unsafe { + // SAFETY: immutability is guaranteed by VecRange's type invariants + self.range.get(index)?.get().as_ref().unwrap() + }) + } +} + +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 { + unsafe { + // SAFETY: immutability is guaranteed by VecRange's type invariants + self.range[index].get().as_ref().unwrap() + } + } +} + +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() + } + }) } }