mirror of https://github.com/adri326/veccell
parent
18ef956a91
commit
2a1fbd7ca3
@ -0,0 +1,215 @@
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_create_vec() {
|
||||
let vec: VecCell<usize> = VecCell::new();
|
||||
assert_eq!(vec.len(), 0);
|
||||
let vec: VecCell<i8> = VecCell::new();
|
||||
assert_eq!(vec.len(), 0);
|
||||
let vec: VecCell<()> = VecCell::new();
|
||||
assert_eq!(vec.len(), 0);
|
||||
|
||||
let vec: VecCell<usize> = VecCell::with_capacity(16);
|
||||
assert_eq!(vec.len(), 0);
|
||||
assert_eq!(vec.capacity(), 16);
|
||||
let vec: VecCell<i8> = VecCell::with_capacity(16);
|
||||
assert_eq!(vec.len(), 0);
|
||||
assert_eq!(vec.capacity(), 16);
|
||||
let vec: VecCell<()> = VecCell::with_capacity(16);
|
||||
assert_eq!(vec.len(), 0);
|
||||
assert_eq!(vec.capacity(), usize::MAX);
|
||||
|
||||
|
||||
let vec: VecCell<usize> = VecCell::with_capacity(0);
|
||||
assert_eq!(vec.len(), 0);
|
||||
assert_eq!(vec.capacity(), 0);
|
||||
let vec: VecCell<i8> = VecCell::with_capacity(0);
|
||||
assert_eq!(vec.len(), 0);
|
||||
assert_eq!(vec.capacity(), 0);
|
||||
let vec: VecCell<()> = VecCell::with_capacity(0);
|
||||
assert_eq!(vec.len(), 0);
|
||||
assert_eq!(vec.capacity(), usize::MAX);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_push() {
|
||||
let mut vec: VecCell<usize> = VecCell::with_capacity(1);
|
||||
vec.push(0);
|
||||
assert_eq!(vec.len(), 1);
|
||||
vec.push(1);
|
||||
assert_eq!(vec.len(), 2);
|
||||
vec.push(2);
|
||||
assert_eq!(vec.len(), 3);
|
||||
|
||||
assert_eq!(vec, vec![0, 1, 2]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pop() {
|
||||
let mut vec: VecCell<usize> = VecCell::new();
|
||||
vec.push(1);
|
||||
assert_eq!(vec.len(), 1);
|
||||
vec.push(2);
|
||||
assert_eq!(vec.len(), 2);
|
||||
|
||||
assert_eq!(vec.pop(), Some(2));
|
||||
assert_eq!(vec.len(), 1);
|
||||
assert_eq!(vec.pop(), Some(1));
|
||||
assert_eq!(vec.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_borrow() {
|
||||
let mut vec: VecCell<usize> = VecCell::new();
|
||||
vec.push(1);
|
||||
vec.push(2);
|
||||
|
||||
let mut x = vec.borrow_mut(1).unwrap();
|
||||
|
||||
assert_eq!(vec.get(0).unwrap(), 1);
|
||||
assert_eq!(vec.get(1), None);
|
||||
|
||||
*x = 3;
|
||||
|
||||
std::mem::drop(x);
|
||||
|
||||
assert_eq!(vec.get(1).unwrap(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_double_borrow() {
|
||||
let mut vec: VecCell<usize> = VecCell::new();
|
||||
vec.push(1);
|
||||
vec.push(2);
|
||||
|
||||
let mut x = vec.borrow_mut(1).unwrap();
|
||||
let y = vec.borrow_mut(0);
|
||||
|
||||
assert!(y.is_none());
|
||||
assert_eq!(vec.mut_borrow(), Some(1));
|
||||
assert!(vec.borrow_mut(1).is_none());
|
||||
assert_eq!(vec.mut_borrow(), Some(1));
|
||||
|
||||
assert_eq!(vec.get(0).unwrap(), 1);
|
||||
assert_eq!(vec.get(1), None);
|
||||
|
||||
*x = 3;
|
||||
|
||||
std::mem::drop(x);
|
||||
std::mem::drop(y);
|
||||
|
||||
assert_eq!(vec.mut_borrow(), None);
|
||||
assert_eq!(vec.get(1).unwrap(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_out_of_bounds() {
|
||||
let mut vec: VecCell<usize> = VecCell::new();
|
||||
|
||||
assert!(vec.get(0).is_none());
|
||||
|
||||
vec.push(1);
|
||||
|
||||
assert!(vec.get(0).is_some());
|
||||
assert!(vec.get(1).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_borrow_clone() {
|
||||
let mut vec: VecCell<usize> = VecCell::new();
|
||||
|
||||
vec.push(1);
|
||||
vec.push(2);
|
||||
|
||||
let x = vec.get(0);
|
||||
assert_eq!(vec.borrows(), 1);
|
||||
assert_eq!(vec.borrows(), 1);
|
||||
assert_eq!(vec.mut_borrow(), None);
|
||||
|
||||
let y = x.clone();
|
||||
|
||||
assert_eq!(vec.borrows(), 2);
|
||||
assert_eq!(vec.borrows(), 2);
|
||||
assert_eq!(vec.mut_borrow(), None);
|
||||
|
||||
assert_eq!(x, y);
|
||||
|
||||
std::mem::drop(x);
|
||||
assert_eq!(vec.borrows(), 1);
|
||||
std::mem::drop(y);
|
||||
assert_eq!(vec.borrows(), 0);
|
||||
|
||||
let x = vec.get(0);
|
||||
assert_eq!(vec.borrows(), 1);
|
||||
let y = vec.get(0);
|
||||
assert_eq!(vec.borrows(), 2);
|
||||
let z = x.clone();
|
||||
assert_eq!(vec.borrows(), 3);
|
||||
|
||||
std::mem::drop(z);
|
||||
assert_eq!(vec.borrows(), 2);
|
||||
std::mem::drop(y);
|
||||
assert_eq!(vec.borrows(), 1);
|
||||
std::mem::drop(x);
|
||||
assert_eq!(vec.borrows(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_borrow_mut() {
|
||||
let mut vec: VecCell<usize> = VecCell::new();
|
||||
|
||||
vec.push(1);
|
||||
vec.push(2);
|
||||
|
||||
let x = vec.get(0);
|
||||
assert!(x.is_some());
|
||||
|
||||
let y = vec.borrow_mut(0);
|
||||
assert!(y.is_none());
|
||||
|
||||
let y = vec.borrow_mut(1);
|
||||
assert!(y.is_none());
|
||||
|
||||
std::mem::drop(x);
|
||||
|
||||
let y = vec.borrow_mut(0);
|
||||
assert!(y.is_some());
|
||||
|
||||
let z = vec.borrow_mut(1);
|
||||
assert!(z.is_none());
|
||||
|
||||
std::mem::drop(y);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iter() {
|
||||
let mut vec: Vec<usize> = Vec::new();
|
||||
let mut vec2: VecCell<usize> = VecCell::new();
|
||||
|
||||
for x in 0..10 {
|
||||
vec.push(x);
|
||||
vec2.push(x);
|
||||
}
|
||||
|
||||
let vec3 = vec2.iter().map(|x| *x).collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(vec, vec3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_iter_panic() {
|
||||
let mut vec: VecCell<usize> = VecCell::new();
|
||||
|
||||
for x in 0..10 {
|
||||
vec.push(x);
|
||||
}
|
||||
|
||||
let y = vec.borrow_mut(3);
|
||||
|
||||
for _x in vec.iter() {
|
||||
// noop
|
||||
}
|
||||
|
||||
std::mem::drop(y);
|
||||
}
|
@ -0,0 +1,134 @@
|
||||
use super::*;
|
||||
|
||||
/// Wraps a borrowed reference from a [`VecCell`].
|
||||
pub struct VecRef<'a, T: ?Sized> {
|
||||
borrows: &'a Cell<usize>,
|
||||
value: &'a T,
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized> VecRef<'a, T> {
|
||||
pub(crate) fn new(vec: &'a VecCell<T>, index: usize) -> Option<Self>
|
||||
where
|
||||
T: Sized
|
||||
{
|
||||
if vec.mut_borrow.get() == Some(index) {
|
||||
return None
|
||||
}
|
||||
|
||||
if index >= vec.len() {
|
||||
return None
|
||||
}
|
||||
|
||||
vec.borrows.set(vec.borrows.get().checked_add(1)?);
|
||||
|
||||
Some(Self {
|
||||
borrows: &vec.borrows,
|
||||
value: unsafe {
|
||||
// SAFETY: there are no mutable borrows of vec.inner[index]
|
||||
vec.get_unchecked(index)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn from(value: &'a T, borrows: &'a Cell<usize>) -> Option<Self> {
|
||||
borrows.set(borrows.get().checked_add(1)?);
|
||||
|
||||
Some(Self {
|
||||
borrows,
|
||||
value
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns a reference to the borrowed value.
|
||||
/// 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.get(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`.
|
||||
///
|
||||
/// This function does not use `self` and must be called explicitly via `VecRef::map(value, function)`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// This function comes in hand when you need to return a reference to a value in a [`VecCell`] from within a function/scope.
|
||||
/// For instance, the following is disallowed:
|
||||
///
|
||||
/// ```compile_fail
|
||||
/// # use veccell::*;
|
||||
/// fn return_favorite_value<'a>(array: &'a VecCell<Vec<u8>>) -> &'a u8 {
|
||||
/// &array.get(42).unwrap().get()[7]
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Instead, you would write it as follows:
|
||||
///
|
||||
/// ```
|
||||
/// # use veccell::*;
|
||||
/// fn return_favorite_value<'a>(array: &'a VecCell<Vec<u8>>) -> VecRef<'a, u8> {
|
||||
/// VecRef::map(array.get(42).unwrap(), |vec| &vec[7])
|
||||
/// }
|
||||
/// ```
|
||||
pub fn map<'b, U: ?Sized, F>(original: VecRef<'b, T>, f: F) -> VecRef<'b, U>
|
||||
where
|
||||
F: FnOnce(&T) -> &U
|
||||
{
|
||||
VecRef::from(f(original.value), original.borrows).expect("Error creating a new VecRef: integer overflow")
|
||||
// original is dropped here
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized> Deref for VecRef<'a, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
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")
|
||||
.field(self.value)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: PartialEq + ?Sized> PartialEq for VecRef<'a, T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.get() == other.get()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: PartialEq + ?Sized> PartialEq<T> for VecRef<'a, T> {
|
||||
fn eq(&self, other: &T) -> bool {
|
||||
self.get() == other
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized> Clone for VecRef<'a, T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self::from(self.value, self.borrows).expect("Error creating a new VecRef: integer overflow")
|
||||
}
|
||||
}
|
@ -0,0 +1,150 @@
|
||||
use super::*;
|
||||
|
||||
// Lets us safely destructure VecRefMut while implementing the Drop logic
|
||||
struct VecRefMutBorrow<'a>(&'a Cell<Option<usize>>);
|
||||
|
||||
/// Wraps a mutably borrowed value from a [`VecCell`].
|
||||
pub struct VecRefMut<'a, T: ?Sized> {
|
||||
mut_borrow: VecRefMutBorrow<'a>,
|
||||
value: &'a mut T,
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized> VecRefMut<'a, T> {
|
||||
/// # Safety
|
||||
///
|
||||
/// If this function returns Some(ref), then there are no mutable borrows of ∀x, vec.inner[x]:
|
||||
/// by contradiction, let `B: 'b` be a mutable borrow of lifetime `'b`. By conjunction on (IV):
|
||||
/// - either `B` had exclusive access, in which case calling `VecCell::borrow_mut` is UB
|
||||
/// - either `B` was obtained from a guard `VecRefMut<'c>`, in which case `'c: 'b` and `vec.mut_borrow.is_some()`, which contradicts our assertion
|
||||
///
|
||||
/// - The invariant (I) is upheld by the first assertion.
|
||||
/// - The invariant (II) is upheld by this function, as it sets `vec.mut_borrow` to `Some(index)`.
|
||||
pub(crate) fn new(vec: &'a VecCell<T>, index: usize) -> Option<Self>
|
||||
where
|
||||
T: Sized
|
||||
{
|
||||
if vec.borrows.get() > 0 || vec.mut_borrow.get().is_some() {
|
||||
return None
|
||||
}
|
||||
|
||||
if index >= vec.len() {
|
||||
return None
|
||||
}
|
||||
|
||||
vec.mut_borrow.set(Some(index));
|
||||
|
||||
Some(Self {
|
||||
mut_borrow: VecRefMutBorrow(&vec.mut_borrow),
|
||||
value: unsafe {
|
||||
vec.get_mut_unchecked(index)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns an immutable reference to the borrowed value.
|
||||
/// The reference may not outlive this `VecRefMut` 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_mut(0).unwrap();
|
||||
/// assert_eq!(guard.get(), "hello");
|
||||
/// ```
|
||||
pub fn get(&self) -> &T {
|
||||
&*self.value
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the borrowed value.
|
||||
/// The reference may not outlive this `VecRefMut` instance.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use veccell::*;
|
||||
/// let mut vec: VecCell<String> = VecCell::new();
|
||||
///
|
||||
/// vec.push(String::from("hello"));
|
||||
/// vec.push(String::from("world"));
|
||||
///
|
||||
/// let mut guard = vec.borrow_mut(0).unwrap();
|
||||
/// let hello = std::mem::replace(guard.get_mut(), String::from("potato"));
|
||||
/// assert_eq!(guard.get(), "potato");
|
||||
/// assert_eq!(hello, "hello");
|
||||
/// ```
|
||||
pub fn get_mut(&mut self) -> &mut T {
|
||||
&mut *self.value
|
||||
}
|
||||
|
||||
/// Transforms a `VecRefMut<'_, T>` into a `VecRefMut<'_, U>` from a function that maps `&mut T` to `&mut U`.
|
||||
///
|
||||
/// This function does not use `self` and must be called explicitly via `VecRefMut::map(value, function)`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use veccell::*;
|
||||
/// fn return_favorite_value_mut<'a>(array: &'a VecCell<Vec<u8>>) -> VecRefMut<'a, u8> {
|
||||
/// VecRefMut::map(array.borrow_mut(42).unwrap(), |vec| &mut vec[7])
|
||||
/// }
|
||||
/// ```
|
||||
pub fn map<'b, U: ?Sized, F>(original: VecRefMut<'b, T>, f: F) -> VecRefMut<'b, U>
|
||||
where
|
||||
F: FnOnce(&mut T) -> &mut U
|
||||
{
|
||||
let VecRefMut { value, mut_borrow } = original;
|
||||
VecRefMut {
|
||||
value: f(value),
|
||||
mut_borrow
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized> Deref for VecRefMut<'a, T> {
|
||||
type Target = T;
|
||||
|
||||
// SAFETY: Upholds invariant (IV)
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized> DerefMut for VecRefMut<'a, T> {
|
||||
// SAFETY: Upholds invariant (IV)
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for VecRefMutBorrow<'a> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
debug_assert!(self.0.get().is_some());
|
||||
self.0.set(None);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Debug + Sized> Debug for VecRefMut<'a, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_tuple("VecRefMut")
|
||||
.field(self.value)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: PartialEq + ?Sized> PartialEq for VecRefMut<'a, T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.get() == other.get()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: PartialEq + ?Sized> PartialEq<T> for VecRefMut<'a, T> {
|
||||
fn eq(&self, other: &T) -> bool {
|
||||
self.get() == other
|
||||
}
|
||||
}
|
Loading…
Reference in new issue