summaryrefslogtreecommitdiff
path: root/src/rwlock
diff options
context:
space:
mode:
authorMica White <botahamec@outlook.com>2025-12-08 20:03:40 -0500
committerMica White <botahamec@outlook.com>2025-12-08 20:03:40 -0500
commit8be852662a432d96553fcf7a9fc57c4f3c92baae (patch)
tree90c93f4d9d24538c64c7552a83ef8ae29172e78a /src/rwlock
parent17dab88a7b4bc86cf156a1e0ac1bac19e6f9f5c6 (diff)
Stuff
Diffstat (limited to 'src/rwlock')
-rwxr-xr-x[-rw-r--r--]src/rwlock/read_guard.rs0
-rwxr-xr-x[-rw-r--r--]src/rwlock/rwlock.rs145
-rwxr-xr-x[-rw-r--r--]src/rwlock/write_guard.rs0
3 files changed, 140 insertions, 5 deletions
diff --git a/src/rwlock/read_guard.rs b/src/rwlock/read_guard.rs
index 5b26c06..5b26c06 100644..100755
--- a/src/rwlock/read_guard.rs
+++ b/src/rwlock/read_guard.rs
diff --git a/src/rwlock/rwlock.rs b/src/rwlock/rwlock.rs
index 0dce710..98ac466 100644..100755
--- a/src/rwlock/rwlock.rs
+++ b/src/rwlock/rwlock.rs
@@ -250,7 +250,35 @@ impl<T: ?Sized, R> RwLock<T, R> {
}
impl<T: ?Sized, R: RawRwLock> RwLock<T, R> {
- pub fn scoped_read<'a, Ret>(&'a self, key: impl Keyable, f: impl Fn(&'a T) -> Ret) -> Ret {
+ /// Acquires a shared lock, blocking until it is safe to do so, and then
+ /// unlocks after the provided function returns.
+ ///
+ /// This function is useful to ensure that a `RwLock` is never accidentally
+ /// locked forever by leaking the `ReadGuard`. Even if the function panics,
+ /// this function will gracefully notice the panic, and unlock. This function
+ /// provides no guarantees with respect to the ordering of whether contentious
+ /// readers or writers will acquire the lock first.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if the provided function also panics. However,
+ /// `RwLock` will be safely unlocked in this case, allowing the `RwLock` to be
+ /// locked again later.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use happylock::{ThreadKey, RwLock};
+ ///
+ /// let mut key = ThreadKey::get().unwrap();
+ /// let lock = RwLock::new(42);
+ ///
+ /// let x = lock.scoped_read(&mut key, |number| {
+ /// *number
+ /// });
+ /// assert_eq!(x, 42);
+ /// ```
+ pub fn scoped_read<'a, Ret>(&'a self, key: impl Keyable, f: impl FnOnce(&'a T) -> Ret) -> Ret {
unsafe {
// safety: we have the key
self.raw_read();
@@ -271,10 +299,47 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> {
}
}
+ /// Attempts to acquire a shared lock to the `RwLock` without blocking,
+ /// and then unlocks it once the provided function returns.
+ ///
+ /// This function implements a non-blocking variant of [`scoped_read`].
+ /// Unlike `scoped_read`, if the `RwLock` is exclusively locked, then the
+ /// provided function will not run, and the given [`Keyable`] is returned.
+ /// This method provides no guarantees with respect to the ordering of whether
+ /// contentious readers of writers will acquire the lock first.
+ ///
+ /// # Errors
+ ///
+ /// If the `RwLock` is already exclusively locked, then the provided function
+ /// will not run. `Err` is returned with the given key.
+ ///
+ /// # Panics
+ ///
+ /// If the provided function panics, then the panic will be bubbled up and
+ /// rethrown. The `RwLock` will also be gracefully unlocked, allowing the
+ /// `RwLock` to be locked again.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use happylock::{RwLock, ThreadKey};
+ ///
+ /// let mut key = ThreadKey::get().unwrap();
+ /// let lock = RwLock::new(42);
+ ///
+ /// let result = lock.scoped_try_read(&mut key, |num| {
+ /// *num
+ /// });
+ ///
+ /// match result {
+ /// Ok(val) => println!("The number is {val}"),
+ /// Err(_) => unreachable!(),
+ /// }
+ /// ```
pub fn scoped_try_read<'a, Key: Keyable, Ret>(
&'a self,
key: Key,
- f: impl Fn(&'a T) -> Ret,
+ f: impl FnOnce(&'a T) -> Ret,
) -> Result<Ret, Key> {
unsafe {
// safety: we have the key
@@ -298,7 +363,40 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> {
}
}
- pub fn scoped_write<'a, Ret>(&'a self, key: impl Keyable, f: impl Fn(&'a mut T) -> Ret) -> Ret {
+ /// Acquires an exclusive lock, blocking until it is safe to do so, and then
+ /// unlocks after the provided function returns.
+ ///
+ /// This function is useful to ensure that a `RwLock` is never accidentally
+ /// locked forever by leaking the `WriteGuard`. Even if the function panics,
+ /// this function will gracefully notice the panic, and unlock. This method
+ /// does not provide any guarantees with respect to the ordering of whether
+ /// contentious readers or writers will acquire the lock first.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if the provided function also panics. However,
+ /// `RwLock` will be safely unlocked in this case, allowing the `RwLock` to be
+ /// locked again later.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use happylock::{ThreadKey, RwLock};
+ ///
+ /// let mut key = ThreadKey::get().unwrap();
+ /// let lock = RwLock::new(42);
+ ///
+ /// let x = lock.scoped_write(&mut key, |number| {
+ /// *number += 5;
+ /// *number
+ /// });
+ /// assert_eq!(x, 47);
+ /// ```
+ pub fn scoped_write<'a, Ret>(
+ &'a self,
+ key: impl Keyable,
+ f: impl FnOnce(&'a mut T) -> Ret,
+ ) -> Ret {
unsafe {
// safety: we have the key
self.raw_write();
@@ -319,10 +417,47 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> {
}
}
+ /// Attempts to acquire an exclusive lock to the `RwLock` without blocking,
+ /// and then unlocks it once the provided function returns.
+ ///
+ /// This function implements a non-blocking variant of [`scoped_write`].
+ /// Unlike `scoped_write`, if the `RwLock` is not already unlocked, then the
+ /// provided function will not run, and the given [`Keyable`] is returned.
+ /// This method does not provide any guarantees with respect to the ordering
+ /// of whether contentious readers or writers will acquire the lock first.
+ ///
+ /// # Errors
+ ///
+ /// If the `RwLock` is already locked, then the provided function will not
+ /// run. `Err` is returned with the given key.
+ ///
+ /// # Panics
+ ///
+ /// If the provided function panics, then the panic will be bubbled up and
+ /// rethrown. The `RwLock` will also be gracefully unlocked, allowing the
+ /// `RwLock` to be locked again.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use happylock::{RwLock, ThreadKey};
+ ///
+ /// let mut key = ThreadKey::get().unwrap();
+ /// let lock = RwLock::new(42);
+ ///
+ /// let result = lock.scoped_try_write(&mut key, |num| {
+ /// *num
+ /// });
+ ///
+ /// match result {
+ /// Ok(val) => println!("The number is {val}"),
+ /// Err(_) => unreachable!(),
+ /// }
+ /// ```
pub fn scoped_try_write<'a, Key: Keyable, Ret>(
&'a self,
key: Key,
- f: impl Fn(&'a mut T) -> Ret,
+ f: impl FnOnce(&'a mut T) -> Ret,
) -> Result<Ret, Key> {
unsafe {
// safety: we have the key
@@ -518,7 +653,7 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> {
/// let key = match lock.try_write(key) {
/// Ok(mut n) => {
/// assert_eq!(*n, 1);
- /// *n = 2;
+ /// *n = 2;
/// RwLock::unlock_write(n)
/// }
/// Err(_) => unreachable!(),
diff --git a/src/rwlock/write_guard.rs b/src/rwlock/write_guard.rs
index c7676b5..c7676b5 100644..100755
--- a/src/rwlock/write_guard.rs
+++ b/src/rwlock/write_guard.rs