summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMica White <botahamec@outlook.com>2026-02-07 13:16:39 -0500
committerMica White <botahamec@outlook.com>2026-02-07 13:16:39 -0500
commit055e6fd92326e4796dccd13948b400719f65b546 (patch)
treea1b33f31a4820a3826a0ce59249c0f10e699648d /src
parentc3a33edff89e96343d6413e597891f9718d0088f (diff)
Finish documentation
Diffstat (limited to 'src')
-rwxr-xr-xsrc/collection/boxed.rs12
-rwxr-xr-xsrc/collection/owned.rs134
-rwxr-xr-xsrc/collection/ref.rs134
-rwxr-xr-xsrc/collection/retry.rs134
4 files changed, 408 insertions, 6 deletions
diff --git a/src/collection/boxed.rs b/src/collection/boxed.rs
index 234fa07..83675b5 100755
--- a/src/collection/boxed.rs
+++ b/src/collection/boxed.rs
@@ -560,10 +560,10 @@ impl<L: Sharable> BoxedLockCollection<L> {
/// # Example
///
/// ```
- /// use happylock::{LockCollection, ThreadKey, Mutex};
+ /// use happylock::{LockCollection, ThreadKey, RwLock};
///
/// let mut key = ThreadKey::get().unwrap();
- /// let data = (Mutex::new(0), Mutex::new(""));
+ /// let data = (RwLock::new(0), RwLock::new(""));
/// let lock = LockCollection::new(data);
///
/// lock.scoped_read(&mut key, |(number, string)| {
@@ -602,15 +602,15 @@ impl<L: Sharable> BoxedLockCollection<L> {
/// # Example
///
/// ```
- /// use happylock::{LockCollection, ThreadKey, Mutex};
+ /// use happylock::{LockCollection, ThreadKey, RwLock};
///
/// let mut key = ThreadKey::get().unwrap();
- /// let data = (Mutex::new(0), Mutex::new(""));
+ /// let data = (RwLock::new(0), RwLock::new(""));
/// let lock = LockCollection::new(data);
///
/// lock.scoped_try_read(&mut key, |(number, string)| {
- /// *number += 1;
- /// *string = "1";
+ /// assert_eq!(*number, 0);
+ /// assert_eq!(*string, "");
/// }).expect("This lock has not yet been locked");
/// ```
///
diff --git a/src/collection/owned.rs b/src/collection/owned.rs
index 02d434c..456742b 100755
--- a/src/collection/owned.rs
+++ b/src/collection/owned.rs
@@ -189,6 +189,36 @@ impl<L: OwnedLockable> OwnedLockCollection<L> {
Self { child: data }
}
+ /// 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::OwnedLockCollection;
+ ///
+ /// let mut key = ThreadKey::get().unwrap();
+ /// let data = (Mutex::new(0), Mutex::new(""));
+ /// let lock = OwnedLockCollection::new(data);
+ ///
+ /// lock.scoped_lock(&mut key, |(number, string)| {
+ /// *number += 1;
+ /// *string = "1";
+ /// });
+ /// ```
pub fn scoped_lock<'a, R>(
&'a self,
key: impl Keyable,
@@ -197,6 +227,43 @@ impl<L: OwnedLockable> OwnedLockCollection<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::OwnedLockCollection;
+ ///
+ /// let mut key = ThreadKey::get().unwrap();
+ /// let data = (Mutex::new(0), Mutex::new(""));
+ /// let lock = OwnedLockCollection::new(data);
+ ///
+ /// lock.scoped_try_lock(&mut key, |(number, string)| {
+ /// *number += 1;
+ /// *string = "1";
+ /// }).expect("This lock has not yet been locked");
+ /// ```
+ ///
+ /// [`scoped_lock`]: OwnedLockCollection::scoped_lock
pub fn scoped_try_lock<'a, Key: Keyable, R>(
&'a self,
key: Key,
@@ -308,6 +375,36 @@ impl<L: OwnedLockable> OwnedLockCollection<L> {
}
impl<L: Sharable> OwnedLockCollection<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::OwnedLockCollection;
+ ///
+ /// let mut key = ThreadKey::get().unwrap();
+ /// let data = (RwLock::new(0), RwLock::new(""));
+ /// let lock = OwnedLockCollection::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,
@@ -316,6 +413,43 @@ impl<L: Sharable> OwnedLockCollection<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::OwnedLockCollection;
+ ///
+ /// let mut key = ThreadKey::get().unwrap();
+ /// let data = (RwLock::new(0), RwLock::new(""));
+ /// let lock = OwnedLockCollection::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`]: OwnedLockCollection::scoped_read
pub fn scoped_try_read<'a, Key: Keyable, R>(
&'a self,
key: Key,
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,
diff --git a/src/collection/retry.rs b/src/collection/retry.rs
index c887405..4a5df6e 100755
--- a/src/collection/retry.rs
+++ b/src/collection/retry.rs
@@ -534,6 +534,36 @@ impl<L: Lockable> RetryingLockCollection<L> {
(!contains_duplicates(&data)).then_some(unsafe { Self::new_unchecked(data) })
}
+ /// 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::RetryingLockCollection;
+ ///
+ /// let mut key = ThreadKey::get().unwrap();
+ /// let data = (Mutex::new(0), Mutex::new(""));
+ /// let lock = RetryingLockCollection::new(data);
+ ///
+ /// lock.scoped_lock(&mut key, |(number, string)| {
+ /// *number += 1;
+ /// *string = "1";
+ /// });
+ /// ```
pub fn scoped_lock<'a, R>(
&'a self,
key: impl Keyable,
@@ -542,6 +572,43 @@ impl<L: Lockable> RetryingLockCollection<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::RetryingLockCollection;
+ ///
+ /// let mut key = ThreadKey::get().unwrap();
+ /// let data = (Mutex::new(0), Mutex::new(""));
+ /// let lock = RetryingLockCollection::new(data);
+ ///
+ /// lock.scoped_try_lock(&mut key, |(number, string)| {
+ /// *number += 1;
+ /// *string = "1";
+ /// }).expect("This lock has not yet been locked");
+ /// ```
+ ///
+ /// [`scoped_lock`]: RetryingLockCollection::scoped_lock
pub fn scoped_try_lock<'a, Key: Keyable, R>(
&'a self,
key: Key,
@@ -653,6 +720,36 @@ impl<L: Lockable> RetryingLockCollection<L> {
}
impl<L: Sharable> RetryingLockCollection<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::RetryingLockCollection;
+ ///
+ /// let mut key = ThreadKey::get().unwrap();
+ /// let data = (RwLock::new(0), RwLock::new(""));
+ /// let lock = RetryingLockCollection::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,
@@ -661,6 +758,43 @@ impl<L: Sharable> RetryingLockCollection<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::RetryingLockCollection;
+ ///
+ /// let mut key = ThreadKey::get().unwrap();
+ /// let data = (RwLock::new(0), RwLock::new(""));
+ /// let lock = RetryingLockCollection::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`]: RetryingLockCollection::scoped_read
pub fn scoped_try_read<'a, Key: Keyable, R>(
&'a self,
key: Key,