summaryrefslogtreecommitdiff
path: root/src/poisonable
diff options
context:
space:
mode:
Diffstat (limited to 'src/poisonable')
-rwxr-xr-x[-rw-r--r--]src/poisonable/error.rs0
-rwxr-xr-x[-rw-r--r--]src/poisonable/flag.rs0
-rwxr-xr-x[-rw-r--r--]src/poisonable/guard.rs0
-rwxr-xr-x[-rw-r--r--]src/poisonable/poisonable.rs149
4 files changed, 145 insertions, 4 deletions
diff --git a/src/poisonable/error.rs b/src/poisonable/error.rs
index eed454b..eed454b 100644..100755
--- a/src/poisonable/error.rs
+++ b/src/poisonable/error.rs
diff --git a/src/poisonable/flag.rs b/src/poisonable/flag.rs
index 9186bbc..9186bbc 100644..100755
--- a/src/poisonable/flag.rs
+++ b/src/poisonable/flag.rs
diff --git a/src/poisonable/guard.rs b/src/poisonable/guard.rs
index b887e2d..b887e2d 100644..100755
--- a/src/poisonable/guard.rs
+++ b/src/poisonable/guard.rs
diff --git a/src/poisonable/poisonable.rs b/src/poisonable/poisonable.rs
index c098041..c8225df 100644..100755
--- a/src/poisonable/poisonable.rs
+++ b/src/poisonable/poisonable.rs
@@ -300,10 +300,40 @@ impl<L: Lockable> Poisonable<L> {
}
impl<L: Lockable + RawLock> Poisonable<L> {
+ /// 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 `Poisonable` is never
+ /// accidentally locked forever by leaking the guard. Even if the function
+ /// panics, this function will gracefully notice the panic, poison the lock,
+ /// and unlock.
+ ///
+ /// If the lock is poisoned, then an error will be passed into the provided
+ /// function.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if the provided function also panics. However,
+ /// `Poisonable` will be safely poisoned and any subsequent calls will pass
+ /// `Err` into the given function.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use happylock::{Poisonable, ThreadKey, RwLock};
+ ///
+ /// let mut key = ThreadKey::get().unwrap();
+ /// let lock = Poisonable::new(RwLock::new(42));
+ ///
+ /// let x = lock.scoped_lock(&mut key, |number| {
+ /// *number.unwrap()
+ /// });
+ /// assert_eq!(x, 42);
+ /// ```
pub fn scoped_lock<'a, R>(
&'a self,
key: impl Keyable,
- f: impl Fn(<Self as Lockable>::DataMut<'a>) -> R,
+ f: impl FnOnce(<Self as Lockable>::DataMut<'a>) -> R,
) -> R {
unsafe {
// safety: we have the thread key
@@ -327,10 +357,50 @@ impl<L: Lockable + RawLock> Poisonable<L> {
}
}
+ /// Attempts to acquire an exclusive lock to the `Poisonable` without
+ /// blocking, and then unlocks it once the provided function returns.
+ ///
+ /// This function implements a non-blocking variant of [`scoped_lock`].
+ /// Unlike `scoped_lock`, if the `Poisonable` 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.
+ ///
+ /// If the lock is poisoned, then an error will be passed into the provided
+ /// function.
+ ///
+ /// # Errors
+ ///
+ /// If the `Poisonable` 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 `Poisonable` will also be gracefully unlocked, allowing the
+ /// `Poisonable` to be locked again.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use happylock::{Poisonable, RwLock, ThreadKey};
+ ///
+ /// let mut key = ThreadKey::get().unwrap();
+ /// let lock = Poisonable::new(RwLock::new(42));
+ ///
+ /// let result = lock.scoped_try_lock(&mut key, |num| {
+ /// *num.unwrap()
+ /// });
+ ///
+ /// match result {
+ /// Ok(val) => println!("The number is {val}"),
+ /// Err(_) => unreachable!(),
+ /// }
+ /// ```
pub fn scoped_try_lock<'a, Key: Keyable, R>(
&'a self,
key: Key,
- f: impl Fn(<Self as Lockable>::DataMut<'a>) -> R,
+ f: impl FnOnce(<Self as Lockable>::DataMut<'a>) -> R,
) -> Result<R, Key> {
unsafe {
// safety: we have the thread key
@@ -487,10 +557,41 @@ impl<L: Sharable + RawLock> Poisonable<L> {
Ok(guard)
}
+ /// 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 `Poisonable` 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.
+ ///
+ /// If the lock is poisoned, then an error will be passed into the provided
+ /// into the provided function.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if the provided function also panics. However,
+ /// `Poisonable` will be safely unlocked in this case, allowing the
+ /// `Poisonable` to be locked again later.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use happylock::{Poisonable, ThreadKey, RwLock};
+ ///
+ /// let mut key = ThreadKey::get().unwrap();
+ /// let lock = Poisonable::new(RwLock::new(42));
+ ///
+ /// let x = lock.scoped_read(&mut key, |number| {
+ /// *number.unwrap()
+ /// });
+ /// assert_eq!(x, 42);
+ /// ```
pub fn scoped_read<'a, R>(
&'a self,
key: impl Keyable,
- f: impl Fn(<Self as Sharable>::DataRef<'a>) -> R,
+ f: impl FnOnce(<Self as Sharable>::DataRef<'a>) -> R,
) -> R {
unsafe {
// safety: we have the thread key
@@ -514,10 +615,50 @@ impl<L: Sharable + RawLock> Poisonable<L> {
}
}
+ /// Attempts to acquire a shared lock to the `Poisonable` 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 `Poisonable` 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.
+ ///
+ /// If the lock is poisoned, then an error will be passed into the provided
+ /// function.
+ ///
+ /// # Errors
+ ///
+ /// If the `Poisonable` 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 `Poisonable` will also be gracefully unlocked, allowing the
+ /// `Poisonable` to be locked again.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use happylock::{Poisonable, RwLock, ThreadKey};
+ ///
+ /// let mut key = ThreadKey::get().unwrap();
+ /// let lock = Poisonable::new(RwLock::new(42));
+ ///
+ /// let result = lock.scoped_try_read(&mut key, |num| {
+ /// *num.unwrap()
+ /// });
+ ///
+ /// match result {
+ /// Ok(val) => println!("The number is {val}"),
+ /// Err(_) => unreachable!(),
+ /// }
+ /// ```
pub fn scoped_try_read<'a, Key: Keyable, R>(
&'a self,
key: Key,
- f: impl Fn(<Self as Sharable>::DataRef<'a>) -> R,
+ f: impl FnOnce(<Self as Sharable>::DataRef<'a>) -> R,
) -> Result<R, Key> {
unsafe {
// safety: we have the thread key