VecRange

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

@ -20,7 +20,7 @@ use std::fmt::{self, Debug};
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
mod vecref; mod vecref;
pub use vecref::VecRef; pub use vecref::{VecRef, VecRange, VecRangeIter};
mod vecrefmut; mod vecrefmut;
pub use vecrefmut::VecRefMut; pub use vecrefmut::VecRefMut;
@ -335,6 +335,28 @@ impl<T> VecCell<T> {
VecRef::new(self, index) 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<usize> = 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<usize>>(&'b self, range: R) -> Option<VecRange<'b, T>> {
VecRange::new(self, range)
}
/// Borrows the `index`-th element mutably, if it exists and no mutable *or immutable* borrow are active. /// Borrows the `index`-th element mutably, if it exists and no mutable *or immutable* borrow are active.
/// Returns `None` otherwise. /// Returns `None` otherwise.
/// ///

@ -1,8 +1,10 @@
use super::*; use super::*;
use std::ops::RangeBounds;
/// Wraps a borrowed reference from a [`VecCell`]. /// Wraps a borrowed reference from a [`VecCell`].
#[derive(Clone)]
pub struct VecRef<'a, T: ?Sized> { pub struct VecRef<'a, T: ?Sized> {
borrows: &'a Cell<usize>, borrows: VecRefBorrow<'a>,
value: &'a T, value: &'a T,
} }
@ -19,10 +21,8 @@ impl<'a, T: ?Sized> VecRef<'a, T> {
return None return None
} }
vec.borrows.set(vec.borrows.get().checked_add(1)?);
Some(Self { Some(Self {
borrows: &vec.borrows, borrows: VecRefBorrow::new(&vec.borrows)?,
value: unsafe { value: unsafe {
// SAFETY: there are no mutable borrows of vec.inner[index] // SAFETY: there are no mutable borrows of vec.inner[index]
vec.get_unchecked(index) vec.get_unchecked(index)
@ -31,10 +31,8 @@ impl<'a, T: ?Sized> VecRef<'a, T> {
} }
fn from(value: &'a T, borrows: &'a Cell<usize>) -> Option<Self> { fn from(value: &'a T, borrows: &'a Cell<usize>) -> Option<Self> {
borrows.set(borrows.get().checked_add(1)?);
Some(Self { Some(Self {
borrows, borrows: VecRefBorrow::new(borrows)?,
value value
}) })
} }
@ -86,7 +84,7 @@ impl<'a, T: ?Sized> VecRef<'a, T> {
where where
F: FnOnce(&T) -> &U 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 // 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> { impl<'a, T: Debug + Sized> Debug for VecRef<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("VecRef") f.debug_tuple("VecRef")
@ -127,8 +117,115 @@ impl<'a, T: PartialEq + ?Sized> PartialEq<T> for VecRef<'a, T> {
} }
} }
impl<'a, T: ?Sized> Clone for VecRef<'a, T> { struct VecRefBorrow<'a>(&'a Cell<usize>);
impl<'a> VecRefBorrow<'a> {
fn new(cell: &'a Cell<usize>) -> Option<Self> {
cell.set(cell.get().checked_add(1)?);
Some(Self(cell))
}
}
impl<'a> Clone for VecRefBorrow<'a> {
fn clone(&self) -> Self { 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<T>],
}
impl<'a, T> VecRange<'a, T> {
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)],
})
}
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<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 {
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<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