summaryrefslogtreecommitdiff
path: root/src/collection
diff options
context:
space:
mode:
authorMica White <botahamec@gmail.com>2024-12-25 17:58:38 -0500
committerMica White <botahamec@gmail.com>2024-12-25 22:44:03 -0500
commit311842d28d1fbb6da945f0d98f1655f77a58abf9 (patch)
tree4da3c8ab6fb3732c1ebb11306dab3799decd6b2c /src/collection
parent37ab873d21ca1fcd43db8d6a26d5bac4f5285f71 (diff)
as_mut re-organization
Diffstat (limited to 'src/collection')
-rw-r--r--src/collection/boxed.rs66
-rw-r--r--src/collection/owned.rs87
-rw-r--r--src/collection/ref.rs26
-rw-r--r--src/collection/retry.rs93
4 files changed, 178 insertions, 94 deletions
diff --git a/src/collection/boxed.rs b/src/collection/boxed.rs
index 3766bed..fca1db2 100644
--- a/src/collection/boxed.rs
+++ b/src/collection/boxed.rs
@@ -3,7 +3,7 @@ use std::cell::UnsafeCell;
use std::fmt::Debug;
use std::marker::PhantomData;
-use crate::lockable::{Lockable, OwnedLockable, RawLock, Sharable};
+use crate::lockable::{Lockable, LockableIntoInner, OwnedLockable, RawLock, Sharable};
use crate::Keyable;
use super::{utils, BoxedLockCollection, LockGuard};
@@ -17,7 +17,8 @@ fn contains_duplicates(l: &[&dyn RawLock]) -> bool {
}
l.windows(2)
- .any(|window| std::ptr::eq(window[0], window[1]))
+ // NOTE: addr_eq is necessary because eq would also compare the v-table pointers
+ .any(|window| std::ptr::addr_eq(window[0], window[1]))
}
unsafe impl<L: Lockable> RawLock for BoxedLockCollection<L> {
@@ -67,7 +68,7 @@ unsafe impl<L: Lockable> Lockable for BoxedLockCollection<L> {
}
unsafe fn guard(&self) -> Self::Guard<'_> {
- self.data().guard()
+ self.child().guard()
}
}
@@ -78,12 +79,20 @@ unsafe impl<L: Sharable> Sharable for BoxedLockCollection<L> {
Self: 'g;
unsafe fn read_guard(&self) -> Self::ReadGuard<'_> {
- self.data().read_guard()
+ self.child().read_guard()
}
}
unsafe impl<L: OwnedLockable> OwnedLockable for BoxedLockCollection<L> {}
+impl<L: LockableIntoInner> LockableIntoInner for BoxedLockCollection<L> {
+ type Inner = L::Inner;
+
+ fn into_inner(self) -> Self::Inner {
+ LockableIntoInner::into_inner(self.into_child())
+ }
+}
+
impl<L> IntoIterator for BoxedLockCollection<L>
where
L: IntoIterator,
@@ -92,7 +101,7 @@ where
type IntoIter = <L as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
- self.into_inner().into_iter()
+ self.into_child().into_iter()
}
}
@@ -104,7 +113,7 @@ where
type IntoIter = <&'a L as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
- self.data().into_iter()
+ self.child().into_iter()
}
}
@@ -125,16 +134,20 @@ unsafe impl<L: Sync> Sync for BoxedLockCollection<L> {}
impl<L> Drop for BoxedLockCollection<L> {
#[mutants::skip]
fn drop(&mut self) {
- self.locks.clear();
+ unsafe {
+ // safety: this collection will never be locked again
+ self.locks.clear();
+ // safety: this was allocated using a box, and is now unique
+ let boxed: Box<UnsafeCell<L>> = Box::from_raw(self.data.cast_mut());
- // safety: this was allocated using a box
- unsafe { std::alloc::dealloc(self.data.cast_mut().cast(), Layout::new::<UnsafeCell<L>>()) }
+ drop(boxed)
+ }
}
}
-impl<L> AsRef<L> for BoxedLockCollection<L> {
- fn as_ref(&self) -> &L {
- self.data()
+impl<T, L: AsRef<T>> AsRef<T> for BoxedLockCollection<L> {
+ fn as_ref(&self) -> &T {
+ self.child().as_ref()
}
}
@@ -174,17 +187,24 @@ impl<L> BoxedLockCollection<L> {
/// let lock = LockCollection::try_new(&data).unwrap();
///
/// let key = ThreadKey::get().unwrap();
- /// let guard = lock.into_inner().0.lock(key);
+ /// let guard = lock.into_child().0.lock(key);
/// assert_eq!(*guard, 42);
/// ```
#[must_use]
- pub fn into_inner(self) -> L {
- // safety: this is owned, so no other references exist
- unsafe { self.data.read().into_inner() }
+ pub fn into_child(mut self) -> L {
+ unsafe {
+ // safety: this collection will never be locked again
+ self.locks.clear();
+ // safety: this was allocated using a box, and is now unique
+ let boxed: Box<UnsafeCell<L>> = Box::from_raw(self.data.cast_mut());
+
+ boxed.into_inner()
+ }
}
/// Gets an immutable reference to the underlying data
- fn data(&self) -> &L {
+ #[must_use]
+ pub fn child(&self) -> &L {
unsafe {
self.data
.as_ref()
@@ -338,7 +358,7 @@ impl<L: Lockable> BoxedLockCollection<L> {
LockGuard {
// safety: we've already acquired the lock
- guard: self.data().guard(),
+ guard: self.child().guard(),
key,
_phantom: PhantomData,
}
@@ -361,11 +381,11 @@ impl<L: Lockable> BoxedLockCollection<L> {
/// let lock = LockCollection::new(data);
///
/// match lock.try_lock(key) {
- /// Some(mut guard) => {
+ /// Ok(mut guard) => {
/// *guard.0 += 1;
/// *guard.1 = "1";
/// },
- /// None => unreachable!(),
+ /// Err(_) => unreachable!(),
/// };
///
/// ```
@@ -379,7 +399,7 @@ impl<L: Lockable> BoxedLockCollection<L> {
}
// safety: we've acquired the locks
- self.data().guard()
+ self.child().guard()
};
Ok(LockGuard {
@@ -442,7 +462,7 @@ impl<L: Sharable> BoxedLockCollection<L> {
LockGuard {
// safety: we've already acquired the lock
- guard: self.data().read_guard(),
+ guard: self.child().read_guard(),
key,
_phantom: PhantomData,
}
@@ -485,7 +505,7 @@ impl<L: Sharable> BoxedLockCollection<L> {
}
// safety: we've acquired the locks
- self.data().read_guard()
+ self.child().read_guard()
};
Some(LockGuard {
diff --git a/src/collection/owned.rs b/src/collection/owned.rs
index 714ff01..e4cfe46 100644
--- a/src/collection/owned.rs
+++ b/src/collection/owned.rs
@@ -1,6 +1,8 @@
use std::marker::PhantomData;
-use crate::lockable::{Lockable, LockableIntoInner, OwnedLockable, RawLock, Sharable};
+use crate::lockable::{
+ Lockable, LockableGetMut, LockableIntoInner, OwnedLockable, RawLock, Sharable,
+};
use crate::Keyable;
use super::{utils, LockGuard, OwnedLockCollection};
@@ -67,6 +69,17 @@ unsafe impl<L: Lockable> Lockable for OwnedLockCollection<L> {
}
}
+impl<L: LockableGetMut> LockableGetMut for OwnedLockCollection<L> {
+ type Inner<'a>
+ = L::Inner<'a>
+ where
+ Self: 'a;
+
+ fn get_mut(&mut self) -> Self::Inner<'_> {
+ self.data.get_mut()
+ }
+}
+
impl<L: LockableIntoInner> LockableIntoInner for OwnedLockCollection<L> {
type Inner = L::Inner;
@@ -115,9 +128,15 @@ impl<E: OwnedLockable + Extend<L>, L: OwnedLockable> Extend<L> for OwnedLockColl
}
}
-impl<L: OwnedLockable> AsMut<L> for OwnedLockCollection<L> {
- fn as_mut(&mut self) -> &mut L {
- &mut self.data
+impl<T, L: AsRef<T>> AsRef<T> for OwnedLockCollection<L> {
+ fn as_ref(&self) -> &T {
+ self.data.as_ref()
+ }
+}
+
+impl<T, L: AsMut<T>> AsMut<T> for OwnedLockCollection<L> {
+ fn as_mut(&mut self) -> &mut T {
+ self.data.as_mut()
}
}
@@ -154,27 +173,6 @@ impl<L: OwnedLockable> OwnedLockCollection<L> {
Self { data }
}
- /// Gets the underlying collection, consuming this collection.
- ///
- /// # Examples
- ///
- /// ```
- /// use happylock::{Mutex, ThreadKey};
- /// use happylock::collection::OwnedLockCollection;
- ///
- /// let data = (Mutex::new(42), Mutex::new(""));
- /// let lock = OwnedLockCollection::new(data);
- ///
- /// let key = ThreadKey::get().unwrap();
- /// let inner = lock.into_inner();
- /// let guard = inner.0.lock(key);
- /// assert_eq!(*guard, 42);
- /// ```
- #[must_use]
- pub fn into_inner(self) -> L {
- self.data
- }
-
/// Locks the collection
///
/// This function returns a guard that can be used to access the underlying
@@ -232,11 +230,11 @@ impl<L: OwnedLockable> OwnedLockCollection<L> {
/// let lock = OwnedLockCollection::new(data);
///
/// match lock.try_lock(key) {
- /// Some(mut guard) => {
+ /// Ok(mut guard) => {
/// *guard.0 += 1;
/// *guard.1 = "1";
/// },
- /// None => unreachable!(),
+ /// Err(_) => unreachable!(),
/// };
///
/// ```
@@ -397,6 +395,41 @@ impl<L: Sharable> OwnedLockCollection<L> {
}
}
+impl<L> OwnedLockCollection<L> {
+ /// Gets the underlying collection, consuming this collection.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use happylock::{Mutex, ThreadKey};
+ /// use happylock::collection::OwnedLockCollection;
+ ///
+ /// let data = (Mutex::new(42), Mutex::new(""));
+ /// let lock = OwnedLockCollection::new(data);
+ ///
+ /// let key = ThreadKey::get().unwrap();
+ /// let inner = lock.into_child();
+ /// let guard = inner.0.lock(key);
+ /// assert_eq!(*guard, 42);
+ /// ```
+ #[must_use]
+ pub fn into_child(self) -> L {
+ self.data
+ }
+}
+
+impl<L: LockableGetMut> OwnedLockCollection<L> {
+ pub fn get_mut(&mut self) -> L::Inner<'_> {
+ LockableGetMut::get_mut(self)
+ }
+}
+
+impl<L: LockableIntoInner> OwnedLockCollection<L> {
+ pub fn into_inner(self) -> L::Inner {
+ LockableIntoInner::into_inner(self)
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/src/collection/ref.rs b/src/collection/ref.rs
index a9fc915..4fa5485 100644
--- a/src/collection/ref.rs
+++ b/src/collection/ref.rs
@@ -23,13 +23,8 @@ fn contains_duplicates(l: &[&dyn RawLock]) -> bool {
}
l.windows(2)
- .any(|window| std::ptr::eq(window[0], window[1]))
-}
-
-impl<L> AsRef<L> for RefLockCollection<'_, L> {
- fn as_ref(&self) -> &L {
- self.data
- }
+ // NOTE: addr_eq is necessary because eq would also compare the v-table pointers
+ .any(|window| std::ptr::addr_eq(window[0], window[1]))
}
impl<'a, L> IntoIterator for &'a RefLockCollection<'a, L>
@@ -106,6 +101,12 @@ unsafe impl<L: Sharable> Sharable for RefLockCollection<'_, L> {
}
}
+impl<T, L: AsRef<T>> AsRef<T> for RefLockCollection<'_, L> {
+ fn as_ref(&self) -> &T {
+ self.data.as_ref()
+ }
+}
+
impl<L: Debug> Debug for RefLockCollection<'_, L> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct(stringify!(RefLockCollection))
@@ -149,6 +150,13 @@ impl<'a, L: OwnedLockable> RefLockCollection<'a, L> {
}
}
+impl<L> RefLockCollection<'_, L> {
+ #[must_use]
+ pub const fn child(&self) -> &L {
+ self.data
+ }
+}
+
impl<'a, L: Lockable> RefLockCollection<'a, L> {
/// Creates a new collections of locks.
///
@@ -262,11 +270,11 @@ impl<'a, L: Lockable> RefLockCollection<'a, L> {
/// let lock = RefLockCollection::new(&data);
///
/// match lock.try_lock(key) {
- /// Some(mut guard) => {
+ /// Ok(mut guard) => {
/// *guard.0 += 1;
/// *guard.1 = "1";
/// },
- /// None => unreachable!(),
+ /// Err(_) => unreachable!(),
/// };
///
/// ```
diff --git a/src/collection/retry.rs b/src/collection/retry.rs
index 0c44dea..3f5d471 100644
--- a/src/collection/retry.rs
+++ b/src/collection/retry.rs
@@ -1,7 +1,7 @@
use crate::collection::utils;
use crate::handle_unwind::handle_unwind;
use crate::lockable::{
- Lockable, LockableAsMut, LockableIntoInner, OwnedLockable, RawLock, Sharable,
+ Lockable, LockableGetMut, LockableIntoInner, OwnedLockable, RawLock, Sharable,
};
use crate::Keyable;
@@ -22,7 +22,8 @@ fn get_locks<L: Lockable>(data: &L) -> Vec<&dyn RawLock> {
fn contains_duplicates<L: Lockable>(data: L) -> bool {
let mut locks = Vec::new();
data.get_ptrs(&mut locks);
- let locks = locks.into_iter().map(|l| &raw const *l);
+ // cast to *const () so that the v-table pointers are not used for hashing
+ let locks = locks.into_iter().map(|l| (&raw const *l).cast::<()>());
let mut locks_set = HashSet::with_capacity(locks.len());
for lock in locks {
@@ -228,14 +229,14 @@ unsafe impl<L: Lockable> Lockable for RetryingLockCollection<L> {
}
}
-impl<L: LockableAsMut> LockableAsMut for RetryingLockCollection<L> {
+impl<L: LockableGetMut> LockableGetMut for RetryingLockCollection<L> {
type Inner<'a>
= L::Inner<'a>
where
Self: 'a;
- fn as_mut(&mut self) -> Self::Inner<'_> {
- self.data.as_mut()
+ fn get_mut(&mut self) -> Self::Inner<'_> {
+ self.data.get_mut()
}
}
@@ -311,15 +312,15 @@ impl<E: OwnedLockable + Extend<L>, L: OwnedLockable> Extend<L> for RetryingLockC
}
}
-impl<L> AsRef<L> for RetryingLockCollection<L> {
- fn as_ref(&self) -> &L {
- &self.data
+impl<T, L: AsRef<T>> AsRef<T> for RetryingLockCollection<L> {
+ fn as_ref(&self) -> &T {
+ self.data.as_ref()
}
}
-impl<L> AsMut<L> for RetryingLockCollection<L> {
- fn as_mut(&mut self) -> &mut L {
- &mut self.data
+impl<T, L: AsMut<T>> AsMut<T> for RetryingLockCollection<L> {
+ fn as_mut(&mut self) -> &mut T {
+ self.data.as_mut()
}
}
@@ -378,7 +379,7 @@ impl<'a, L: OwnedLockable> RetryingLockCollection<&'a L> {
}
}
-impl<L: Lockable> RetryingLockCollection<L> {
+impl<L> RetryingLockCollection<L> {
/// Creates a new collections of locks.
///
/// # Safety
@@ -404,6 +405,37 @@ impl<L: Lockable> RetryingLockCollection<L> {
Self { data }
}
+ pub const fn child(&self) -> &L {
+ &self.data
+ }
+
+ pub fn child_mut(&mut self) -> &mut L {
+ &mut self.data
+ }
+
+ /// Gets the underlying collection, consuming this collection.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use happylock::{Mutex, ThreadKey};
+ /// use happylock::collection::RetryingLockCollection;
+ ///
+ /// let data = (Mutex::new(42), Mutex::new(""));
+ /// let lock = RetryingLockCollection::new(data);
+ ///
+ /// let key = ThreadKey::get().unwrap();
+ /// let inner = lock.into_child();
+ /// let guard = inner.0.lock(key);
+ /// assert_eq!(*guard, 42);
+ /// ```
+ #[must_use]
+ pub fn into_child(self) -> L {
+ self.data
+ }
+}
+
+impl<L: Lockable> RetryingLockCollection<L> {
/// Creates a new collection of locks.
///
/// This returns `None` if any locks are found twice in the given
@@ -427,27 +459,6 @@ impl<L: Lockable> RetryingLockCollection<L> {
(!contains_duplicates(&data)).then_some(Self { data })
}
- /// Gets the underlying collection, consuming this collection.
- ///
- /// # Examples
- ///
- /// ```
- /// use happylock::{Mutex, ThreadKey};
- /// use happylock::collection::RetryingLockCollection;
- ///
- /// let data = (Mutex::new(42), Mutex::new(""));
- /// let lock = RetryingLockCollection::new(data);
- ///
- /// let key = ThreadKey::get().unwrap();
- /// let inner = lock.into_inner();
- /// let guard = inner.0.lock(key);
- /// assert_eq!(*guard, 42);
- /// ```
- #[must_use]
- pub fn into_inner(self) -> L {
- self.data
- }
-
/// Locks the collection
///
/// This function returns a guard that can be used to access the underlying
@@ -502,11 +513,11 @@ impl<L: Lockable> RetryingLockCollection<L> {
/// let lock = RetryingLockCollection::new(data);
///
/// match lock.try_lock(key) {
- /// Some(mut guard) => {
+ /// Ok(mut guard) => {
/// *guard.0 += 1;
/// *guard.1 = "1";
/// },
- /// None => unreachable!(),
+ /// Err(_) => unreachable!(),
/// };
///
/// ```
@@ -656,6 +667,18 @@ impl<L: Sharable> RetryingLockCollection<L> {
}
}
+impl<L: LockableGetMut> RetryingLockCollection<L> {
+ pub fn get_mut(&mut self) -> L::Inner<'_> {
+ LockableGetMut::get_mut(self)
+ }
+}
+
+impl<L: LockableIntoInner> RetryingLockCollection<L> {
+ pub fn into_inner(self) -> L::Inner {
+ LockableIntoInner::into_inner(self)
+ }
+}
+
impl<'a, L: 'a> RetryingLockCollection<L>
where
&'a L: IntoIterator,