diff options
| author | Mica White <botahamec@outlook.com> | 2025-12-08 20:03:40 -0500 |
|---|---|---|
| committer | Mica White <botahamec@outlook.com> | 2025-12-08 20:03:40 -0500 |
| commit | 8be852662a432d96553fcf7a9fc57c4f3c92baae (patch) | |
| tree | 90c93f4d9d24538c64c7552a83ef8ae29172e78a /src/rwlock | |
| parent | 17dab88a7b4bc86cf156a1e0ac1bac19e6f9f5c6 (diff) | |
Stuff
Diffstat (limited to 'src/rwlock')
| -rwxr-xr-x[-rw-r--r--] | src/rwlock/read_guard.rs | 0 | ||||
| -rwxr-xr-x[-rw-r--r--] | src/rwlock/rwlock.rs | 145 | ||||
| -rwxr-xr-x[-rw-r--r--] | src/rwlock/write_guard.rs | 0 |
3 files changed, 140 insertions, 5 deletions
diff --git a/src/rwlock/read_guard.rs b/src/rwlock/read_guard.rs index 5b26c06..5b26c06 100644..100755 --- a/src/rwlock/read_guard.rs +++ b/src/rwlock/read_guard.rs diff --git a/src/rwlock/rwlock.rs b/src/rwlock/rwlock.rs index 0dce710..98ac466 100644..100755 --- a/src/rwlock/rwlock.rs +++ b/src/rwlock/rwlock.rs @@ -250,7 +250,35 @@ impl<T: ?Sized, R> RwLock<T, R> { } impl<T: ?Sized, R: RawRwLock> RwLock<T, R> { - pub fn scoped_read<'a, Ret>(&'a self, key: impl Keyable, f: impl Fn(&'a T) -> Ret) -> Ret { + /// 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 `RwLock` 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. + /// + /// # Panics + /// + /// This function will panic if the provided function also panics. However, + /// `RwLock` will be safely unlocked in this case, allowing the `RwLock` to be + /// locked again later. + /// + /// # Example + /// + /// ``` + /// use happylock::{ThreadKey, RwLock}; + /// + /// let mut key = ThreadKey::get().unwrap(); + /// let lock = RwLock::new(42); + /// + /// let x = lock.scoped_read(&mut key, |number| { + /// *number + /// }); + /// assert_eq!(x, 42); + /// ``` + pub fn scoped_read<'a, Ret>(&'a self, key: impl Keyable, f: impl FnOnce(&'a T) -> Ret) -> Ret { unsafe { // safety: we have the key self.raw_read(); @@ -271,10 +299,47 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> { } } + /// Attempts to acquire a shared lock to the `RwLock` 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 `RwLock` 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. + /// + /// # Errors + /// + /// If the `RwLock` 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 `RwLock` will also be gracefully unlocked, allowing the + /// `RwLock` to be locked again. + /// + /// # Examples + /// + /// ``` + /// use happylock::{RwLock, ThreadKey}; + /// + /// let mut key = ThreadKey::get().unwrap(); + /// let lock = RwLock::new(42); + /// + /// let result = lock.scoped_try_read(&mut key, |num| { + /// *num + /// }); + /// + /// match result { + /// Ok(val) => println!("The number is {val}"), + /// Err(_) => unreachable!(), + /// } + /// ``` pub fn scoped_try_read<'a, Key: Keyable, Ret>( &'a self, key: Key, - f: impl Fn(&'a T) -> Ret, + f: impl FnOnce(&'a T) -> Ret, ) -> Result<Ret, Key> { unsafe { // safety: we have the key @@ -298,7 +363,40 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> { } } - pub fn scoped_write<'a, Ret>(&'a self, key: impl Keyable, f: impl Fn(&'a mut T) -> Ret) -> Ret { + /// 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 `RwLock` is never accidentally + /// locked forever by leaking the `WriteGuard`. Even if the function panics, + /// this function will gracefully notice the panic, and unlock. This method + /// does not provide any 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, + /// `RwLock` will be safely unlocked in this case, allowing the `RwLock` to be + /// locked again later. + /// + /// # Example + /// + /// ``` + /// use happylock::{ThreadKey, RwLock}; + /// + /// let mut key = ThreadKey::get().unwrap(); + /// let lock = RwLock::new(42); + /// + /// let x = lock.scoped_write(&mut key, |number| { + /// *number += 5; + /// *number + /// }); + /// assert_eq!(x, 47); + /// ``` + pub fn scoped_write<'a, Ret>( + &'a self, + key: impl Keyable, + f: impl FnOnce(&'a mut T) -> Ret, + ) -> Ret { unsafe { // safety: we have the key self.raw_write(); @@ -319,10 +417,47 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> { } } + /// Attempts to acquire an exclusive lock to the `RwLock` without blocking, + /// and then unlocks it once the provided function returns. + /// + /// This function implements a non-blocking variant of [`scoped_write`]. + /// Unlike `scoped_write`, if the `RwLock` 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 the `RwLock` 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 `RwLock` will also be gracefully unlocked, allowing the + /// `RwLock` to be locked again. + /// + /// # Examples + /// + /// ``` + /// use happylock::{RwLock, ThreadKey}; + /// + /// let mut key = ThreadKey::get().unwrap(); + /// let lock = RwLock::new(42); + /// + /// let result = lock.scoped_try_write(&mut key, |num| { + /// *num + /// }); + /// + /// match result { + /// Ok(val) => println!("The number is {val}"), + /// Err(_) => unreachable!(), + /// } + /// ``` pub fn scoped_try_write<'a, Key: Keyable, Ret>( &'a self, key: Key, - f: impl Fn(&'a mut T) -> Ret, + f: impl FnOnce(&'a mut T) -> Ret, ) -> Result<Ret, Key> { unsafe { // safety: we have the key @@ -518,7 +653,7 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> { /// let key = match lock.try_write(key) { /// Ok(mut n) => { /// assert_eq!(*n, 1); - /// *n = 2; + /// *n = 2; /// RwLock::unlock_write(n) /// } /// Err(_) => unreachable!(), diff --git a/src/rwlock/write_guard.rs b/src/rwlock/write_guard.rs index c7676b5..c7676b5 100644..100755 --- a/src/rwlock/write_guard.rs +++ b/src/rwlock/write_guard.rs |
