diff --git a/src/lib.rs b/src/lib.rs index 35140b0..b3b92f4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,12 @@ use std::cell::{Cell, UnsafeCell}; use std::fmt::{self, Debug}; use std::ops::{Deref, DerefMut}; +mod vecref; +pub use vecref::VecRef; + +mod vecrefmut; +pub use vecrefmut::VecRefMut; + /// A contiguous, growable array type with interior mutability. /// /// This type allows to get a mutable reference ([`VecRefMut`]) to an index `i`, while letting you access immutably ([`VecRef`]) elements at indices `j != i`. @@ -706,506 +712,8 @@ impl From> for VecCell { } } -/// Wraps a borrowed reference from a [`VecCell`]. -pub struct VecRef<'a, T: ?Sized> { - borrows: &'a Cell, - value: &'a T, -} - -impl<'a, T: ?Sized> VecRef<'a, T> { - fn new(vec: &'a VecCell, index: usize) -> Option - 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) -> Option { - 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 = 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>) -> &'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>) -> 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 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") - } -} - -// Lets us safely destructure VecRefMut while implementing the Drop logic -struct VecRefMutBorrow<'a>(&'a Cell>); - -/// 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)`. - fn new(vec: &'a VecCell, index: usize) -> Option - 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 = 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 = 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>) -> 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 for VecRefMut<'a, T> { - fn eq(&self, other: &T) -> bool { - self.get() == other - } -} - #[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_create_vec() { - let vec: VecCell = VecCell::new(); - assert_eq!(vec.len(), 0); - let vec: VecCell = VecCell::new(); - assert_eq!(vec.len(), 0); - let vec: VecCell<()> = VecCell::new(); - assert_eq!(vec.len(), 0); - - let vec: VecCell = 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(), 16); - let vec: VecCell<()> = VecCell::with_capacity(16); - assert_eq!(vec.len(), 0); - assert_eq!(vec.capacity(), usize::MAX); - - - let vec: VecCell = 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(), 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = Vec::new(); - let mut vec2: VecCell = VecCell::new(); - - for x in 0..10 { - vec.push(x); - vec2.push(x); - } - - let vec3 = vec2.iter().map(|x| *x).collect::>(); - - assert_eq!(vec, vec3); - } - - #[test] - #[should_panic] - fn test_iter_panic() { - let mut vec: VecCell = 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); - } -} +mod test; #[doc = include_str!("../README.md")] #[cfg(doctest)] diff --git a/src/test.rs b/src/test.rs new file mode 100644 index 0000000..15698f9 --- /dev/null +++ b/src/test.rs @@ -0,0 +1,215 @@ +use super::*; + +#[test] +fn test_create_vec() { + let vec: VecCell = VecCell::new(); + assert_eq!(vec.len(), 0); + let vec: VecCell = VecCell::new(); + assert_eq!(vec.len(), 0); + let vec: VecCell<()> = VecCell::new(); + assert_eq!(vec.len(), 0); + + let vec: VecCell = 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(), 16); + let vec: VecCell<()> = VecCell::with_capacity(16); + assert_eq!(vec.len(), 0); + assert_eq!(vec.capacity(), usize::MAX); + + + let vec: VecCell = 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(), 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = Vec::new(); + let mut vec2: VecCell = VecCell::new(); + + for x in 0..10 { + vec.push(x); + vec2.push(x); + } + + let vec3 = vec2.iter().map(|x| *x).collect::>(); + + assert_eq!(vec, vec3); +} + +#[test] +#[should_panic] +fn test_iter_panic() { + let mut vec: VecCell = 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); +} diff --git a/src/vecref.rs b/src/vecref.rs new file mode 100644 index 0000000..f1b9ea8 --- /dev/null +++ b/src/vecref.rs @@ -0,0 +1,134 @@ +use super::*; + +/// Wraps a borrowed reference from a [`VecCell`]. +pub struct VecRef<'a, T: ?Sized> { + borrows: &'a Cell, + value: &'a T, +} + +impl<'a, T: ?Sized> VecRef<'a, T> { + pub(crate) fn new(vec: &'a VecCell, index: usize) -> Option + 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) -> Option { + 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 = 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>) -> &'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>) -> 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 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") + } +} diff --git a/src/vecrefmut.rs b/src/vecrefmut.rs new file mode 100644 index 0000000..5619c40 --- /dev/null +++ b/src/vecrefmut.rs @@ -0,0 +1,150 @@ +use super::*; + +// Lets us safely destructure VecRefMut while implementing the Drop logic +struct VecRefMutBorrow<'a>(&'a Cell>); + +/// 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, index: usize) -> Option + 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 = 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 = 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>) -> 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 for VecRefMut<'a, T> { + fn eq(&self, other: &T) -> bool { + self.get() == other + } +}