diff options
| author | Mica White <botahamec@outlook.com> | 2026-02-07 13:16:39 -0500 |
|---|---|---|
| committer | Mica White <botahamec@outlook.com> | 2026-02-07 13:16:39 -0500 |
| commit | 055e6fd92326e4796dccd13948b400719f65b546 (patch) | |
| tree | a1b33f31a4820a3826a0ce59249c0f10e699648d | |
| parent | c3a33edff89e96343d6413e597891f9718d0088f (diff) | |
Finish documentation
| -rwxr-xr-x | src/collection/boxed.rs | 12 | ||||
| -rwxr-xr-x | src/collection/owned.rs | 134 | ||||
| -rwxr-xr-x | src/collection/ref.rs | 134 | ||||
| -rwxr-xr-x | src/collection/retry.rs | 134 |
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, |
