summaryrefslogtreecommitdiff
path: root/src/collection/ref.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/collection/ref.rs')
-rwxr-xr-xsrc/collection/ref.rs134
1 files changed, 134 insertions, 0 deletions
diff --git a/src/collection/ref.rs b/src/collection/ref.rs
index 14ad861..a995097 100755
--- a/src/collection/ref.rs
+++ b/src/collection/ref.rs
@@ -240,6 +240,36 @@ impl<'a, L: Lockable> RefLockCollection<'a, L> {
Some(Self { child: data, locks })
}
+ /// 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 the data is never accidentally
+ /// locked forever by leaking the guard. 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,
+ /// the collection will be safely unlocked in this case, allowing the
+ /// collection to be locked again later.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use happylock::{ThreadKey, Mutex};
+ /// use happylock::collection::RefLockCollection;
+ ///
+ /// let mut key = ThreadKey::get().unwrap();
+ /// let data = (Mutex::new(0), Mutex::new(""));
+ /// let lock = RefLockCollection::new(&data);
+ ///
+ /// lock.scoped_lock(&mut key, |(number, string)| {
+ /// *number += 1;
+ /// *string = "1";
+ /// });
+ /// ```
pub fn scoped_lock<'s, R>(
&'s self,
key: impl Keyable,
@@ -248,6 +278,43 @@ impl<'a, L: Lockable> RefLockCollection<'a, L> {
scoped_write(self, key, f)
}
+ /// Attempts to acquire an exclusive lock to the underlying data without
+ /// blocking, and then unlocks once the provided function returns.
+ ///
+ /// This function implements a non-blocking variant of [`scoped_lock`].
+ /// Unlike `scoped_lock`, if the lock collection 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 any of the locks in the collection are already locked, then the
+ /// provided function will not run. `Err` is returned with the given key.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if the provided function also panics. However,
+ /// the collection will be safely unlocked in this case, allowing the
+ /// collection to be locked again later.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use happylock::{ThreadKey, Mutex};
+ /// use happylock::collection::RefLockCollection;
+ ///
+ /// let mut key = ThreadKey::get().unwrap();
+ /// let data = (Mutex::new(0), Mutex::new(""));
+ /// let lock = RefLockCollection::new(&data);
+ ///
+ /// lock.scoped_try_lock(&mut key, |(number, string)| {
+ /// *number += 1;
+ /// *string = "1";
+ /// }).expect("This lock has not yet been locked");
+ /// ```
+ ///
+ /// [`scoped_lock`]: RefLockCollection::scoped_lock
pub fn scoped_try_lock<'s, Key: Keyable, R>(
&'s self,
key: Key,
@@ -359,6 +426,36 @@ impl<'a, L: Lockable> RefLockCollection<'a, L> {
}
impl<L: Sharable> RefLockCollection<'_, L> {
+ /// 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 the data is never accidentally
+ /// locked forever by leaking the guard. 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,
+ /// the collection will be safely unlocked in this case, allowing the
+ /// collection to be locked again later.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use happylock::{ThreadKey, RwLock};
+ /// use happylock::collection::RefLockCollection;
+ ///
+ /// let mut key = ThreadKey::get().unwrap();
+ /// let data = (RwLock::new(0), RwLock::new(""));
+ /// let lock = RefLockCollection::new(&data);
+ ///
+ /// lock.scoped_read(&mut key, |(number, string)| {
+ /// assert_eq!(*number, 0);
+ /// assert_eq!(*string, "");
+ /// });
+ /// ```
pub fn scoped_read<'a, R>(
&'a self,
key: impl Keyable,
@@ -367,6 +464,43 @@ impl<L: Sharable> RefLockCollection<'_, L> {
scoped_read(self, key, f)
}
+ /// Attempts to acquire an exclusive lock to the underlying data without
+ /// blocking, and then unlocks once the provided function returns.
+ ///
+ /// This function implements a non-blocking variant of [`scoped_read`].
+ /// Unlike `scoped_read`, if the lock collection is exclusively locked, 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 any of the locks in the collection are already exclusively locked, then
+ /// the provided function will not run. `Err` is returned with the given key.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if the provided function also panics. However,
+ /// the collection will be safely unlocked in this case, allowing the
+ /// collection to be locked again later.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use happylock::{ThreadKey, RwLock};
+ /// use happylock::collection::RefLockCollection;
+ ///
+ /// let mut key = ThreadKey::get().unwrap();
+ /// let data = (RwLock::new(0), RwLock::new(""));
+ /// let lock = RefLockCollection::new(&data);
+ ///
+ /// lock.scoped_try_read(&mut key, |(number, string)| {
+ /// assert_eq!(*number, 0);
+ /// assert_eq!(*string, "");
+ /// }).expect("This lock has not yet been locked");
+ /// ```
+ ///
+ /// [`scoped_read`]: RefLockCollection::scoped_read
pub fn scoped_try_read<'a, Key: Keyable, R>(
&'a self,
key: Key,