From 8be852662a432d96553fcf7a9fc57c4f3c92baae Mon Sep 17 00:00:00 2001 From: Mica White Date: Mon, 8 Dec 2025 20:03:40 -0500 Subject: Stuff --- src/rwlock/rwlock.rs | 145 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 140 insertions(+), 5 deletions(-) mode change 100644 => 100755 src/rwlock/rwlock.rs (limited to 'src/rwlock/rwlock.rs') diff --git a/src/rwlock/rwlock.rs b/src/rwlock/rwlock.rs old mode 100644 new mode 100755 index 0dce710..98ac466 --- a/src/rwlock/rwlock.rs +++ b/src/rwlock/rwlock.rs @@ -250,7 +250,35 @@ impl RwLock { } impl RwLock { - 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 RwLock { } } + /// 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 { unsafe { // safety: we have the key @@ -298,7 +363,40 @@ impl RwLock { } } - 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 RwLock { } } + /// 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 { unsafe { // safety: we have the key @@ -518,7 +653,7 @@ impl RwLock { /// let key = match lock.try_write(key) { /// Ok(mut n) => { /// assert_eq!(*n, 1); - /// *n = 2; + /// *n = 2; /// RwLock::unlock_write(n) /// } /// Err(_) => unreachable!(), -- cgit v1.2.3