diff options
| author | Mica White <botahamec@gmail.com> | 2024-12-26 12:06:47 -0500 |
|---|---|---|
| committer | Mica White <botahamec@gmail.com> | 2024-12-26 13:23:40 -0500 |
| commit | 9eec9ab94bbe5c9fbd52d5bbf393fe1ddcc6fc26 (patch) | |
| tree | a55cb81db2167cd3caf3330d503c2e9cacd24fd4 /src | |
| parent | dc16634f4abdb1e830d2749e64b419740702b302 (diff) | |
Documentation
Diffstat (limited to 'src')
| -rw-r--r-- | src/collection/boxed.rs | 66 | ||||
| -rw-r--r-- | src/collection/owned.rs | 66 | ||||
| -rw-r--r-- | src/collection/ref.rs | 41 | ||||
| -rw-r--r-- | src/collection/retry.rs | 83 | ||||
| -rw-r--r-- | src/handle_unwind.rs | 5 | ||||
| -rw-r--r-- | src/mutex/mutex.rs | 7 | ||||
| -rw-r--r-- | src/poisonable.rs | 2 | ||||
| -rw-r--r-- | src/poisonable/poisonable.rs | 2 | ||||
| -rw-r--r-- | src/rwlock/read_lock.rs | 76 | ||||
| -rw-r--r-- | src/rwlock/rwlock.rs | 22 | ||||
| -rw-r--r-- | src/rwlock/write_lock.rs | 75 |
11 files changed, 407 insertions, 38 deletions
diff --git a/src/collection/boxed.rs b/src/collection/boxed.rs index c0cc294..7a84b2a 100644 --- a/src/collection/boxed.rs +++ b/src/collection/boxed.rs @@ -211,6 +211,23 @@ impl<L> BoxedLockCollection<L> { // references happening at the same time /// Gets an immutable reference to the underlying data + /// + /// # Examples + /// + /// ``` + /// use happylock::{Mutex, ThreadKey, LockCollection}; + /// + /// let data1 = Mutex::new(42); + /// let data2 = Mutex::new(""); + /// + /// // data1 and data2 refer to distinct mutexes, so this won't panic + /// let data = (&data1, &data2); + /// let lock = LockCollection::try_new(&data).unwrap(); + /// + /// let key = ThreadKey::get().unwrap(); + /// let guard = lock.child().0.lock(key); + /// assert_eq!(*guard, 42); + /// ``` #[must_use] pub fn child(&self) -> &L { unsafe { @@ -375,9 +392,14 @@ impl<L: Lockable> BoxedLockCollection<L> { /// Attempts to lock the without blocking. /// - /// If successful, this method returns a guard that can be used to access - /// the data, and unlocks the data when it is dropped. Otherwise, `None` is - /// returned. + /// If the access could not be granted at this time, then `Err` is + /// returned. Otherwise, an RAII guard is returned which will release the + /// locks when it is dropped. + /// + /// # Errors + /// + /// If any locks in the collection are already locked, then an error + /// containing the given key is returned. /// /// # Examples /// @@ -480,9 +502,14 @@ impl<L: Sharable> BoxedLockCollection<L> { /// Attempts to lock the without blocking, in such a way that other threads /// can still read from the collection. /// - /// If successful, this method returns a guard that can be used to access - /// the data immutably, and unlocks the data when it is dropped. Otherwise, - /// `None` is returned. + /// If the access could not be granted at this time, then `Err` is + /// returned. Otherwise, an RAII guard is returned which will release the + /// shared access when it is dropped. + /// + /// # Errors + /// + /// If any of the locks in the collection are already locked, then an error + /// is returned containing the given key. /// /// # Examples /// @@ -494,29 +521,29 @@ impl<L: Sharable> BoxedLockCollection<L> { /// let lock = LockCollection::new(data); /// /// match lock.try_read(key) { - /// Some(mut guard) => { + /// Ok(mut guard) => { /// assert_eq!(*guard.0, 5); /// assert_eq!(*guard.1, "6"); /// }, - /// None => unreachable!(), + /// Err(_) => unreachable!(), /// }; /// /// ``` pub fn try_read<'g, 'key: 'g, Key: Keyable + 'key>( &'g self, key: Key, - ) -> Option<LockGuard<'key, L::ReadGuard<'g>, Key>> { + ) -> Result<LockGuard<'key, L::ReadGuard<'g>, Key>, Key> { let guard = unsafe { // safety: we have the thread key if !self.raw_try_read() { - return None; + return Err(key); } // safety: we've acquired the locks self.child().read_guard() }; - Some(LockGuard { + Ok(LockGuard { guard, key, _phantom: PhantomData, @@ -546,6 +573,23 @@ impl<L: Sharable> BoxedLockCollection<L> { } } +impl<L: LockableIntoInner> BoxedLockCollection<L> { + /// Consumes this `BoxedLockCollection`, returning the underlying data. + /// + /// # Examples + /// + /// ``` + /// use happylock::{Mutex, LockCollection}; + /// + /// let mutex = LockCollection::new([Mutex::new(0), Mutex::new(0)]); + /// assert_eq!(mutex.into_inner(), [0, 0]); + /// ``` + #[must_use] + pub fn into_inner(self) -> <Self as LockableIntoInner>::Inner { + LockableIntoInner::into_inner(self) + } +} + impl<'a, L: 'a> BoxedLockCollection<L> where &'a L: IntoIterator, diff --git a/src/collection/owned.rs b/src/collection/owned.rs index 3d6fa93..7436a6e 100644 --- a/src/collection/owned.rs +++ b/src/collection/owned.rs @@ -213,9 +213,14 @@ impl<L: OwnedLockable> OwnedLockCollection<L> { /// Attempts to lock the without blocking. /// - /// If successful, this method returns a guard that can be used to access - /// the data, and unlocks the data when it is dropped. Otherwise, `None` is - /// returned. + /// If the access could not be granted at this time, then `Err` is + /// returned. Otherwise, an RAII guard is returned which will release the + /// locks when it is dropped. + /// + /// # Errors + /// + /// If any of the locks in this collection are already locked, this returns + /// an error containing the given key. /// /// # Examples /// @@ -324,9 +329,14 @@ impl<L: Sharable> OwnedLockCollection<L> { /// Attempts to lock the without blocking, in such a way that other threads /// can still read from the collection. /// - /// If successful, this method returns a guard that can be used to access - /// the data immutably, and unlocks the data when it is dropped. Otherwise, - /// `None` is returned. + /// If the access could not be granted at this time, then `Err` is + /// returned. Otherwise, an RAII guard is returned which will release the + /// shared access when it is dropped. + /// + /// # Errors + /// + /// If any of the locks in this collection can't be acquired, then an error + /// is returned containing the given key. /// /// # Examples /// @@ -415,18 +425,62 @@ impl<L> OwnedLockCollection<L> { self.data } + /// Gets a mutable reference to the underlying collection. + /// + /// # Examples + /// + /// ``` + /// use happylock::{Mutex, ThreadKey}; + /// use happylock::collection::OwnedLockCollection; + /// + /// let data = (Mutex::new(42), Mutex::new("")); + /// let mut lock = OwnedLockCollection::new(data); + /// + /// let key = ThreadKey::get().unwrap(); + /// let mut inner = lock.child_mut(); + /// let guard = inner.0.get_mut(); + /// assert_eq!(*guard, 42); + /// ``` + #[must_use] pub fn child_mut(&mut self) -> &mut L { &mut self.data } } impl<L: LockableGetMut> OwnedLockCollection<L> { + /// Gets a mutable reference to the data behind this `OwnedLockCollection`. + /// + /// Since this call borrows the `OwnedLockCollection` mutably, no actual + /// locking needs to take place - the mutable borrow statically guarantees + /// no locks exist. + /// + /// # Examples + /// + /// ``` + /// use happylock::{Mutex, LockCollection}; + /// use happylock::collection::OwnedLockCollection; + /// + /// let mut mutex = OwnedLockCollection::new([Mutex::new(0), Mutex::new(0)]); + /// assert_eq!(mutex.get_mut(), [&mut 0, &mut 0]); + /// ``` pub fn get_mut(&mut self) -> L::Inner<'_> { LockableGetMut::get_mut(self) } } impl<L: LockableIntoInner> OwnedLockCollection<L> { + /// Consumes this `OwnedLockCollection`, returning the underlying data. + /// + /// # Examples + /// + /// ``` + /// use happylock::{Mutex, LockCollection}; + /// use happylock::collection::OwnedLockCollection; + /// + /// let mutex = OwnedLockCollection::new([Mutex::new(0), Mutex::new(0)]); + /// assert_eq!(mutex.into_inner(), [0, 0]); + /// ``` + #[must_use] pub fn into_inner(self) -> L::Inner { LockableIntoInner::into_inner(self) } diff --git a/src/collection/ref.rs b/src/collection/ref.rs index a9c3579..1e17412 100644 --- a/src/collection/ref.rs +++ b/src/collection/ref.rs @@ -151,6 +151,25 @@ impl<'a, L: OwnedLockable> RefLockCollection<'a, L> { } impl<L> RefLockCollection<'_, L> { + /// Gets an immutable reference to the underlying data + /// + /// # Examples + /// + /// ``` + /// use happylock::{Mutex, ThreadKey}; + /// use happylock::collection::RefLockCollection; + /// + /// let data1 = Mutex::new(42); + /// let data2 = Mutex::new(""); + /// + /// // data1 and data2 refer to distinct mutexes, so this won't panic + /// let data = (&data1, &data2); + /// let lock = RefLockCollection::try_new(&data).unwrap(); + /// + /// let key = ThreadKey::get().unwrap(); + /// let guard = lock.child().0.lock(key); + /// assert_eq!(*guard, 42); + /// ``` #[must_use] pub const fn child(&self) -> &L { self.data @@ -255,9 +274,14 @@ impl<'a, L: Lockable> RefLockCollection<'a, L> { /// Attempts to lock the without blocking. /// - /// If successful, this method returns a guard that can be used to access - /// the data, and unlocks the data when it is dropped. Otherwise, `None` is - /// returned. + /// If the access could not be granted at this time, then `Err` is + /// returned. Otherwise, an RAII guard is returned which will release the + /// locks when it is dropped. + /// + /// # Errors + /// + /// If any of the locks in the collection are already locked, then an error + /// is returned containing the given key. /// /// # Examples /// @@ -364,9 +388,14 @@ impl<'a, L: Sharable> RefLockCollection<'a, L> { /// Attempts to lock the without blocking, in such a way that other threads /// can still read from the collection. /// - /// If successful, this method returns a guard that can be used to access - /// the data immutably, and unlocks the data when it is dropped. Otherwise, - /// `None` is returned. + /// If the access could not be granted at this time, then `Err` is + /// returned. Otherwise, an RAII guard is returned which will release the + /// shared access when it is dropped. + /// + /// # Errors + /// + /// If any of the locks in the collection are already locked, then an error + /// is returned containing the given key. /// /// # Examples /// diff --git a/src/collection/retry.rs b/src/collection/retry.rs index 83842f8..db09ebf 100644 --- a/src/collection/retry.rs +++ b/src/collection/retry.rs @@ -422,10 +422,44 @@ impl<L> RetryingLockCollection<L> { Self { data } } + /// Gets an immutable reference to the underlying collection. + /// + /// # Examples + /// + /// ``` + /// use happylock::{Mutex, ThreadKey}; + /// use happylock::collection::RetryingLockCollection; + /// + /// let data = (Mutex::new(42), Mutex::new("")); + /// let lock = RetryingLockCollection::new(data); + /// + /// let key = ThreadKey::get().unwrap(); + /// let inner = lock.child(); + /// let guard = inner.0.lock(key); + /// assert_eq!(*guard, 42); + /// ``` + #[must_use] pub const fn child(&self) -> &L { &self.data } + /// Gets a mutable reference to the underlying collection. + /// + /// # Examples + /// + /// ``` + /// use happylock::{Mutex, ThreadKey}; + /// use happylock::collection::RetryingLockCollection; + /// + /// let data = (Mutex::new(42), Mutex::new("")); + /// let mut lock = RetryingLockCollection::new(data); + /// + /// let key = ThreadKey::get().unwrap(); + /// let mut inner = lock.child_mut(); + /// let guard = inner.0.get_mut(); + /// assert_eq!(*guard, 42); + /// ``` + #[must_use] pub fn child_mut(&mut self) -> &mut L { &mut self.data } @@ -515,9 +549,14 @@ impl<L: Lockable> RetryingLockCollection<L> { /// Attempts to lock the without blocking. /// - /// If successful, this method returns a guard that can be used to access - /// the data, and unlocks the data when it is dropped. Otherwise, `None` is - /// returned. + /// If the access could not be granted at this time, then `Err` is + /// returned. Otherwise, an RAII guard is returned which will release the + /// locks when it is dropped. + /// + /// # Errors + /// + /// If any of the locks in the collection are already locked, then an error + /// is returned containing the given key. /// /// # Examples /// @@ -622,9 +661,14 @@ impl<L: Sharable> RetryingLockCollection<L> { /// Attempts to lock the without blocking, in such a way that other threads /// can still read from the collection. /// - /// If successful, this method returns a guard that can be used to access - /// the data immutably, and unlocks the data when it is dropped. Otherwise, - /// `None` is returned. + /// If the access could not be granted at this time, then `Err` is + /// returned. Otherwise, an RAII guard is returned which will release the + /// shared access when it is dropped. + /// + /// # Errors + /// + /// If shared access cannot be acquired at this time, then an error is + /// returned containing the given key. /// /// # Examples /// @@ -685,12 +729,39 @@ impl<L: Sharable> RetryingLockCollection<L> { } impl<L: LockableGetMut> RetryingLockCollection<L> { + /// Gets a mutable reference to the data behind this + /// `RetryingLockCollection`. + /// + /// Since this call borrows the `RetryingLockCollection` mutably, no actual + /// locking needs to take place - the mutable borrow statically guarantees + /// no locks exist. + /// + /// # Examples + /// + /// ``` + /// use happylock::{Mutex, LockCollection}; + /// use happylock::collection::RetryingLockCollection; + /// + /// let mut mutex = RetryingLockCollection::new([Mutex::new(0), Mutex::new(0)]); + /// assert_eq!(mutex.get_mut(), [&mut 0, &mut 0]); + /// ``` pub fn get_mut(&mut self) -> L::Inner<'_> { LockableGetMut::get_mut(self) } } impl<L: LockableIntoInner> RetryingLockCollection<L> { + /// Consumes this `RetryingLockCollection`, returning the underlying data. + /// + /// # Examples + /// + /// ``` + /// use happylock::{Mutex, LockCollection}; + /// use happylock::collection::RetryingLockCollection; + /// + /// let mutex = RetryingLockCollection::new([Mutex::new(0), Mutex::new(0)]); + /// assert_eq!(mutex.into_inner(), [0, 0]); + /// ``` pub fn into_inner(self) -> L::Inner { LockableIntoInner::into_inner(self) } diff --git a/src/handle_unwind.rs b/src/handle_unwind.rs index 220d379..42b6fc5 100644 --- a/src/handle_unwind.rs +++ b/src/handle_unwind.rs @@ -1,6 +1,9 @@ use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe}; -/// Runs `try_fn`. If it unwinds, it will run `catch` and then continue unwinding +/// Runs `try_fn`. If it unwinds, it will run `catch` and then continue +/// unwinding. This is used instead of `scopeguard` to ensure the `catch` +/// function doesn't run if the thread is already panicking. The unwind +/// must specifically be caused by the `try_fn` pub fn handle_unwind<R, F: FnOnce() -> R, G: FnOnce()>(try_fn: F, catch: G) -> R { let try_fn = AssertUnwindSafe(try_fn); catch_unwind(try_fn).unwrap_or_else(|e| { diff --git a/src/mutex/mutex.rs b/src/mutex/mutex.rs index 505ff83..9b71ea4 100644 --- a/src/mutex/mutex.rs +++ b/src/mutex/mutex.rs @@ -247,9 +247,14 @@ impl<T: ?Sized, R: RawMutex> Mutex<T, R> { /// Attempts to lock the `Mutex` without blocking. /// + /// If the access could not be granted at this time, then `Err` is + /// returned. Otherwise, an RAII guard is returned which will release the + /// lock when it is dropped. + /// /// # Errors /// - /// Returns [`Err`] if the `Mutex` cannot be locked without blocking. + /// If the mutex could not be acquired because it is already locked, then + /// this call will return an error containing the given key. /// /// # Examples /// diff --git a/src/poisonable.rs b/src/poisonable.rs index 6af9f9a..f9152d1 100644 --- a/src/poisonable.rs +++ b/src/poisonable.rs @@ -1,8 +1,6 @@ use std::marker::PhantomData; use std::sync::atomic::AtomicBool; -use crate::Keyable; - mod error; mod flag; mod guard; diff --git a/src/poisonable/poisonable.rs b/src/poisonable/poisonable.rs index ea51dd5..b49aa94 100644 --- a/src/poisonable/poisonable.rs +++ b/src/poisonable/poisonable.rs @@ -560,7 +560,7 @@ impl<L: LockableIntoInner> Poisonable<L> { impl<L: LockableGetMut + RawLock> Poisonable<L> { /// Returns a mutable reference to the underlying data. /// - /// Since this call borrows the `Poisonable` mutable, no actual locking + /// Since this call borrows the `Poisonable` mutably, no actual locking /// needs to take place - the mutable borrow statically guarantees no locks /// exist. /// diff --git a/src/rwlock/read_lock.rs b/src/rwlock/read_lock.rs index d719a50..ae593e2 100644 --- a/src/rwlock/read_lock.rs +++ b/src/rwlock/read_lock.rs @@ -87,6 +87,34 @@ impl<'l, T, R> ReadLock<'l, T, R> { impl<T: ?Sized, R: RawRwLock> ReadLock<'_, T, R> { /// Locks the underlying [`RwLock`] with shared read access, blocking the /// current thread until it can be acquired. + /// + /// The calling thread will be blocked until there are no more writers + /// which hold the lock. There may be other readers currently inside the + /// lock when this method returns. + /// + /// Returns an RAII guard which will release this thread's shared access + /// once it is dropped. + /// + /// Because this method takes a [`ThreadKey`], it's not possible for this + /// method to cause a deadlock. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// use std::thread; + /// use happylock::{RwLock, ThreadKey}; + /// use happylock::rwlock::ReadLock; + /// + /// let key = ThreadKey::get().unwrap(); + /// let lock: &'static mut RwLock<_> = Box::leak(Box::new(RwLock::new(1))); + /// let reader = ReadLock::new(&lock); + /// + /// let n = reader.lock(key); + /// assert_eq!(*n, 1); + /// ``` + /// + /// [`ThreadKey`]: `crate::ThreadKey` pub fn lock<'s, 'key: 's, Key: Keyable + 'key>( &'s self, key: Key, @@ -96,6 +124,35 @@ impl<T: ?Sized, R: RawRwLock> ReadLock<'_, T, R> { /// Attempts to acquire the underlying [`RwLock`] with shared read access /// without blocking. + /// + /// If the access could not be granted at this time, then `Err` is + /// returned. Otherwise, an RAII guard is returned which will release the + /// shared access when it is dropped. + /// + /// This function 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` could not be acquired because it was already locked + /// exclusively, then an error will be returned containing the given key. + /// + /// # Examples + /// + /// ``` + /// use happylock::{RwLock, ThreadKey}; + /// use happylock::rwlock::ReadLock; + /// + /// let key = ThreadKey::get().unwrap(); + /// let lock = RwLock::new(1); + /// let reader = ReadLock::new(&lock); + /// + /// match reader.try_lock(key) { + /// Ok(n) => assert_eq!(*n, 1), + /// Err(_) => unreachable!(), + /// }; + /// ``` pub fn try_lock<'s, 'key: 's, Key: Keyable + 'key>( &'s self, key: Key, @@ -111,6 +168,25 @@ impl<T: ?Sized, R: RawRwLock> ReadLock<'_, T, R> { /// Immediately drops the guard, and consequently releases the shared lock /// on the underlying [`RwLock`]. + /// + /// This function is equivalent to calling [`drop`] on the guard, except + /// that it returns the key that was used to create it. Alternately, the + /// guard will be automatically dropped when it goes out of scope. + /// + /// # Examples + /// + /// ``` + /// use happylock::{RwLock, ThreadKey}; + /// use happylock::rwlock::ReadLock; + /// + /// let key = ThreadKey::get().unwrap(); + /// let lock = RwLock::new(0); + /// let reader = ReadLock::new(&lock); + /// + /// let mut guard = reader.lock(key); + /// assert_eq!(*guard, 0); + /// let key = ReadLock::unlock(guard); + /// ``` pub fn unlock<'key, Key: Keyable + 'key>(guard: RwLockReadGuard<'_, 'key, T, Key, R>) -> Key { RwLock::unlock_read(guard) } diff --git a/src/rwlock/rwlock.rs b/src/rwlock/rwlock.rs index 6432128..a249675 100644 --- a/src/rwlock/rwlock.rs +++ b/src/rwlock/rwlock.rs @@ -277,10 +277,19 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> { /// Attempts to acquire this `RwLock` with shared read access without /// blocking. /// - /// If the access could not be granted at this time, then `None` is + /// If the access could not be granted at this time, then `Err` is /// returned. Otherwise, an RAII guard is returned which will release the /// shared access when it is dropped. /// + /// This function 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` could not be acquired because it was already locked + /// exclusively, then an error will be returned containing the given key. + /// /// # Examples /// /// ``` @@ -351,8 +360,10 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> { /// let key = ThreadKey::get().unwrap(); /// let lock = RwLock::new(1); /// - /// let mut n = lock.write(key); - /// *n += 2; + /// match lock.try_write(key) { + /// Ok(n) => assert_eq!(*n, 1), + /// Err(_) => unreachable!(), + /// }; /// ``` /// /// [`ThreadKey`]: `crate::ThreadKey` @@ -378,6 +389,11 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> { /// ordering of whether contentious readers or writers will acquire the /// lock first. /// + /// # Errors + /// + /// If the `RwLock` could not be acquired because it was already locked, + /// then an error will be returned containing the given key. + /// /// # Examples /// /// ``` diff --git a/src/rwlock/write_lock.rs b/src/rwlock/write_lock.rs index e9be750..ff00c06 100644 --- a/src/rwlock/write_lock.rs +++ b/src/rwlock/write_lock.rs @@ -81,6 +81,31 @@ impl<'l, T, R> WriteLock<'l, T, R> { impl<T: ?Sized, R: RawRwLock> WriteLock<'_, T, R> { /// Locks the underlying [`RwLock`] with exclusive write access, blocking /// the current until it can be acquired. + /// + /// This function will not return while other writers or readers currently + /// have access to the lock. + /// + /// Returns an RAII guard which will drop the write access of this `RwLock` + /// when dropped. + /// + /// Because this method takes a [`ThreadKey`], it's not possible for this + /// method to cause a deadlock. + /// + /// # Examples + /// + /// ``` + /// use happylock::{ThreadKey, RwLock}; + /// use happylock::rwlock::WriteLock; + /// + /// let key = ThreadKey::get().unwrap(); + /// let lock = RwLock::new(1); + /// let writer = WriteLock::new(&lock); + /// + /// let mut n = writer.lock(key); + /// *n += 2; + /// ``` + /// + /// [`ThreadKey`]: `crate::ThreadKey` pub fn lock<'s, 'key: 's, Key: Keyable + 'key>( &'s self, key: Key, @@ -89,6 +114,35 @@ impl<T: ?Sized, R: RawRwLock> WriteLock<'_, T, R> { } /// Attempts to lock the underlying [`RwLock`] with exclusive write access. + /// + /// This function does not block. If the lock could not be acquired at this + /// time, then `None` is returned. Otherwise, an RAII guard is returned + /// which will release the lock when it is dropped. + /// + /// This function 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`] could not be acquired because it was already locked, + /// then an error will be returned containing the given key. + /// + /// # Examples + /// + /// ``` + /// use happylock::{RwLock, ThreadKey}; + /// use happylock::rwlock::WriteLock; + /// + /// let key = ThreadKey::get().unwrap(); + /// let lock = RwLock::new(1); + /// let writer = WriteLock::new(&lock); + /// + /// match writer.try_lock(key) { + /// Ok(n) => assert_eq!(*n, 1), + /// Err(_) => unreachable!(), + /// }; + /// ``` pub fn try_lock<'s, 'key: 's, Key: Keyable + 'key>( &'s self, key: Key, @@ -100,7 +154,26 @@ impl<T: ?Sized, R: RawRwLock> WriteLock<'_, T, R> { // the referenced `RwLock`. /// Immediately drops the guard, and consequently releases the exclusive - /// lock. + /// lock on the underlying [`RwLock`]. + /// + /// This function is equivalent to calling [`drop`] on the guard, except + /// that it returns the key that was used to create it. Alternately, the + /// guard will be automatically dropped when it goes out of scope. + /// + /// # Examples + /// + /// ``` + /// use happylock::{RwLock, ThreadKey}; + /// use happylock::rwlock::WriteLock; + /// + /// let key = ThreadKey::get().unwrap(); + /// let lock = RwLock::new(0); + /// let writer = WriteLock::new(&lock); + /// + /// let mut guard = writer.lock(key); + /// *guard += 20; + /// let key = WriteLock::unlock(guard); + /// ``` pub fn unlock<'key, Key: Keyable + 'key>(guard: RwLockWriteGuard<'_, 'key, T, Key, R>) -> Key { RwLock::unlock_write(guard) } |
