summaryrefslogtreecommitdiff
path: root/src/rwlock.rs
diff options
context:
space:
mode:
authorBotahamec <botahamec@outlook.com>2025-03-29 17:34:10 -0400
committerBotahamec <botahamec@outlook.com>2025-03-29 17:34:10 -0400
commit17dab88a7b4bc86cf156a1e0ac1bac19e6f9f5c6 (patch)
tree59f7ddaf743899be6b5ddd7ecf1b38882c50087d /src/rwlock.rs
parent3a299432173f98521d0aeb840dafb6710ce27f82 (diff)
Clean up existing documentation
Diffstat (limited to 'src/rwlock.rs')
-rw-r--r--src/rwlock.rs317
1 files changed, 34 insertions, 283 deletions
diff --git a/src/rwlock.rs b/src/rwlock.rs
index f5c0ec5..fca132d 100644
--- a/src/rwlock.rs
+++ b/src/rwlock.rs
@@ -8,9 +8,6 @@ use crate::ThreadKey;
mod rwlock;
-mod read_lock;
-mod write_lock;
-
mod read_guard;
mod write_guard;
@@ -39,7 +36,7 @@ pub type ParkingRwLock<T> = RwLock<T, parking_lot::RawRwLock>;
/// methods) to allow access to the content of the lock.
///
/// Locking the mutex on a thread that already locked it is impossible, due to
-/// the requirement of the [`ThreadKey`]. Therefore, this will never deadlock.
+/// the requirement of the [`ThreadKey`]. This will never deadlock.
///
/// [`ThreadKey`]: `crate::ThreadKey`
/// [`Mutex`]: `crate::mutex::Mutex`
@@ -51,37 +48,37 @@ pub struct RwLock<T: ?Sized, R> {
data: UnsafeCell<T>,
}
-/// Grants read access to an [`RwLock`]
-///
-/// This structure is designed to be used in a [`LockCollection`] to indicate
-/// that only read access is needed to the data.
+/// RAII structure that unlocks the shared read access to a [`RwLock`] when
+/// dropped.
///
-/// [`LockCollection`]: `crate::LockCollection`
-#[repr(transparent)]
-struct ReadLock<'l, T: ?Sized, R>(&'l RwLock<T, R>);
-
-/// Grants write access to an [`RwLock`]
+/// This structure is created when the [`RwLock`] is put in a wrapper type,
+/// such as [`LockCollection`], and a read-only guard is obtained through the
+/// wrapper.
///
-/// This structure is designed to be used in a [`LockCollection`] to indicate
-/// that write access is needed to the data.
+/// This is similar to [`RwLockReadGuard`], except it does not hold a
+/// [`ThreadKey`].
///
+/// [`Deref`]: `std::ops::Deref`
+/// [`DerefMut`]: `std::ops::DerefMut`
/// [`LockCollection`]: `crate::LockCollection`
-#[repr(transparent)]
-struct WriteLock<'l, T: ?Sized, R>(&'l RwLock<T, R>);
-
-/// RAII structure that unlocks the shared read access to a [`RwLock`]
-///
-/// This is similar to [`RwLockReadRef`], except it does not hold a
-/// [`Keyable`].
pub struct RwLockReadRef<'a, T: ?Sized, R: RawRwLock>(
&'a RwLock<T, R>,
PhantomData<R::GuardMarker>,
);
-/// RAII structure that unlocks the exclusive write access to a [`RwLock`]
+/// RAII structure that unlocks the exclusive write access to a [`RwLock`] when
+/// dropped.
+///
+/// This structure is created when the [`RwLock`] is put in a wrapper type,
+/// such as [`LockCollection`], and a mutable guard is obtained through the
+/// wrapper.
///
-/// This is similar to [`RwLockWriteRef`], except it does not hold a
-/// [`Keyable`].
+/// This is similar to [`RwLockWriteGuard`], except it does not hold a
+/// [`ThreadKey`].
+///
+/// [`Deref`]: `std::ops::Deref`
+/// [`DerefMut`]: `std::ops::DerefMut`
+/// [`LockCollection`]: `crate::LockCollection`
pub struct RwLockWriteRef<'a, T: ?Sized, R: RawRwLock>(
&'a RwLock<T, R>,
PhantomData<R::GuardMarker>,
@@ -93,6 +90,12 @@ pub struct RwLockWriteRef<'a, T: ?Sized, R: RawRwLock>(
/// This structure is created by the [`read`] and [`try_read`] methods on
/// [`RwLock`].
///
+/// This guard holds a [`ThreadKey`] for its entire lifetime. Therefore, a new
+/// lock cannot be acquired until this one is dropped. The [`ThreadKey`] can be
+/// reacquired using [`RwLock::unlock_read`].
+///
+/// [`Deref`]: `std::ops::Deref`
+/// [`DerefMut`]: `std::ops::DerefMut`
/// [`read`]: `RwLock::read`
/// [`try_read`]: `RwLock::try_read`
pub struct RwLockReadGuard<'a, T: ?Sized, R: RawRwLock> {
@@ -106,6 +109,12 @@ pub struct RwLockReadGuard<'a, T: ?Sized, R: RawRwLock> {
/// This structure is created by the [`write`] and [`try_write`] methods on
/// [`RwLock`]
///
+/// This guard holds a [`ThreadKey`] for its entire lifetime. Therefor, a new
+/// lock cannot be acquired until this one is dropped. The [`ThreadKey`] can be
+/// reacquired using [`RwLock::unlock_write`].
+///
+/// [`Deref`]: `std::ops::Deref`
+/// [`DerefMut`]: `std::ops::DerefMut`
/// [`try_write`]: `RwLock::try_write`
pub struct RwLockWriteGuard<'a, T: ?Sized, R: RawRwLock> {
rwlock: RwLockWriteRef<'a, T, R>,
@@ -114,14 +123,10 @@ pub struct RwLockWriteGuard<'a, T: ?Sized, R: RawRwLock> {
#[cfg(test)]
mod tests {
- use crate::lockable::Lockable;
- use crate::lockable::RawLock;
use crate::LockCollection;
use crate::RwLock;
use crate::ThreadKey;
- use super::*;
-
#[test]
fn unlocked_when_initialized() {
let key = ThreadKey::get().unwrap();
@@ -132,112 +137,6 @@ mod tests {
}
#[test]
- fn read_lock_unlocked_when_initialized() {
- let key = ThreadKey::get().unwrap();
- let lock: crate::RwLock<_> = RwLock::new("Hello, world!");
- let reader = ReadLock::new(&lock);
-
- assert!(reader.try_lock(key).is_ok());
- }
-
- #[test]
- fn read_lock_from_works() {
- let key = ThreadKey::get().unwrap();
- let lock: crate::RwLock<_> = RwLock::from("Hello, world!");
- let reader = ReadLock::from(&lock);
-
- let guard = reader.lock(key);
- assert_eq!(*guard, "Hello, world!");
- }
-
- #[test]
- fn read_lock_scoped_works() {
- let mut key = ThreadKey::get().unwrap();
- let lock: crate::RwLock<_> = RwLock::new(42);
- let reader = ReadLock::new(&lock);
-
- reader.scoped_lock(&mut key, |num| assert_eq!(*num, 42));
- }
-
- #[test]
- fn read_lock_scoped_try_fails_during_write() {
- let key = ThreadKey::get().unwrap();
- let lock: crate::RwLock<_> = RwLock::new(42);
- let reader = ReadLock::new(&lock);
- let guard = lock.write(key);
-
- std::thread::scope(|s| {
- s.spawn(|| {
- let key = ThreadKey::get().unwrap();
- let r = reader.scoped_try_lock(key, |_| {});
- assert!(r.is_err());
- });
- });
-
- drop(guard);
- }
-
- #[test]
- fn write_lock_unlocked_when_initialized() {
- let key = ThreadKey::get().unwrap();
- let lock: crate::RwLock<_> = RwLock::new("Hello, world!");
- let writer = WriteLock::new(&lock);
-
- assert!(writer.try_lock(key).is_ok());
- }
-
- #[test]
- #[ignore = "We've removed ReadLock"]
- fn read_lock_get_ptrs() {
- let rwlock = RwLock::new(5);
- let readlock = ReadLock::new(&rwlock);
- let mut lock_ptrs = Vec::new();
- readlock.get_ptrs(&mut lock_ptrs);
-
- assert_eq!(lock_ptrs.len(), 1);
- assert!(std::ptr::addr_eq(lock_ptrs[0], &readlock));
- }
-
- #[test]
- #[ignore = "We've removed WriteLock"]
- fn write_lock_get_ptrs() {
- let rwlock = RwLock::new(5);
- let writelock = WriteLock::new(&rwlock);
- let mut lock_ptrs = Vec::new();
- writelock.get_ptrs(&mut lock_ptrs);
-
- assert_eq!(lock_ptrs.len(), 1);
- assert!(std::ptr::addr_eq(lock_ptrs[0], &writelock));
- }
-
- #[test]
- fn write_lock_scoped_works() {
- let mut key = ThreadKey::get().unwrap();
- let lock: crate::RwLock<_> = RwLock::new(42);
- let writer = WriteLock::new(&lock);
-
- writer.scoped_lock(&mut key, |num| assert_eq!(*num, 42));
- }
-
- #[test]
- fn write_lock_scoped_try_fails_during_write() {
- let key = ThreadKey::get().unwrap();
- let lock: crate::RwLock<_> = RwLock::new(42);
- let writer = WriteLock::new(&lock);
- let guard = lock.write(key);
-
- std::thread::scope(|s| {
- s.spawn(|| {
- let key = ThreadKey::get().unwrap();
- let r = writer.scoped_try_lock(key, |_| {});
- assert!(r.is_err());
- });
- });
-
- drop(guard);
- }
-
- #[test]
fn locked_after_read() {
let key = ThreadKey::get().unwrap();
let lock: crate::RwLock<_> = RwLock::new("Hello, world!");
@@ -249,18 +148,6 @@ mod tests {
}
#[test]
- fn locked_after_using_read_lock() {
- let key = ThreadKey::get().unwrap();
- let lock: crate::RwLock<_> = RwLock::new("Hello, world!");
- let reader = ReadLock::new(&lock);
-
- let guard = reader.lock(key);
-
- assert!(lock.is_locked());
- drop(guard)
- }
-
- #[test]
fn locked_after_write() {
let key = ThreadKey::get().unwrap();
let lock: crate::RwLock<_> = RwLock::new("Hello, world!");
@@ -272,18 +159,6 @@ mod tests {
}
#[test]
- fn locked_after_using_write_lock() {
- let key = ThreadKey::get().unwrap();
- let lock: crate::RwLock<_> = RwLock::new("Hello, world!");
- let writer = WriteLock::new(&lock);
-
- let guard = writer.lock(key);
-
- assert!(lock.is_locked());
- drop(guard)
- }
-
- #[test]
fn locked_after_scoped_write() {
let mut key = ThreadKey::get().unwrap();
let lock = crate::RwLock::new("Hello, world!");
@@ -424,112 +299,6 @@ mod tests {
}
#[test]
- fn unlock_read_lock() {
- let key = ThreadKey::get().unwrap();
- let lock = crate::RwLock::new("Hello, world");
- let reader = ReadLock::new(&lock);
-
- let guard = reader.lock(key);
- let key = ReadLock::unlock(guard);
-
- lock.write(key);
- }
-
- #[test]
- fn unlock_write_lock() {
- let key = ThreadKey::get().unwrap();
- let lock = crate::RwLock::new("Hello, world");
- let writer = WriteLock::from(&lock);
-
- let guard = writer.lock(key);
- let key = WriteLock::unlock(guard);
-
- lock.write(key);
- }
-
- #[test]
- #[ignore = "We've removed ReadLock"]
- fn read_lock_in_collection() {
- let mut key = ThreadKey::get().unwrap();
- let lock = crate::RwLock::new("hi");
- let collection = LockCollection::try_new(ReadLock::new(&lock)).unwrap();
-
- collection.scoped_lock(&mut key, |guard| {
- assert_eq!(*guard, "hi");
- });
- collection.scoped_read(&mut key, |guard| {
- assert_eq!(*guard, "hi");
- });
- assert!(collection
- .scoped_try_lock(&mut key, |guard| {
- assert_eq!(*guard, "hi");
- })
- .is_ok());
- assert!(collection
- .scoped_try_read(&mut key, |guard| {
- assert_eq!(*guard, "hi");
- })
- .is_ok());
-
- let guard = collection.lock(key);
- assert_eq!(**guard, "hi");
-
- let key = LockCollection::<ReadLock<_, _>>::unlock(guard);
- let guard = collection.read(key);
- assert_eq!(**guard, "hi");
-
- let key = LockCollection::<ReadLock<_, _>>::unlock(guard);
- let guard = lock.write(key);
-
- std::thread::scope(|s| {
- s.spawn(|| {
- let key = ThreadKey::get().unwrap();
- let guard = collection.try_lock(key);
- assert!(guard.is_err());
- });
- s.spawn(|| {
- let key = ThreadKey::get().unwrap();
- let guard = collection.try_read(key);
- assert!(guard.is_err());
- });
- });
-
- drop(guard);
- }
-
- #[test]
- fn write_lock_in_collection() {
- let mut key = ThreadKey::get().unwrap();
- let lock = crate::RwLock::new("hi");
- let collection = LockCollection::try_new(WriteLock::new(&lock)).unwrap();
-
- collection.scoped_lock(&mut key, |guard| {
- assert_eq!(*guard, "hi");
- });
- assert!(collection
- .scoped_try_lock(&mut key, |guard| {
- assert_eq!(*guard, "hi");
- })
- .is_ok());
-
- let guard = collection.lock(key);
- assert_eq!(**guard, "hi");
-
- let key = LockCollection::<WriteLock<_, _>>::unlock(guard);
- let guard = lock.write(key);
-
- std::thread::scope(|s| {
- s.spawn(|| {
- let key = ThreadKey::get().unwrap();
- let guard = collection.try_lock(key);
- assert!(guard.is_err());
- });
- });
-
- drop(guard);
- }
-
- #[test]
fn read_ref_as_ref() {
let key = ThreadKey::get().unwrap();
let lock = LockCollection::new(crate::RwLock::new("hi"));
@@ -575,22 +344,4 @@ mod tests {
*guard.as_mut() = "foo";
assert_eq!(*guard.as_mut(), "foo");
}
-
- #[test]
- fn poison_read_lock() {
- let lock = crate::RwLock::new("hi");
- let reader = ReadLock::new(&lock);
-
- reader.poison();
- assert!(lock.poison.is_poisoned());
- }
-
- #[test]
- fn poison_write_lock() {
- let lock = crate::RwLock::new("hi");
- let reader = WriteLock::new(&lock);
-
- reader.poison();
- assert!(lock.poison.is_poisoned());
- }
}