From 2376ccee97c99d5c47c09fcf308a97aaf785a29e Mon Sep 17 00:00:00 2001 From: Botahamec Date: Thu, 26 Sep 2024 22:58:13 -0400 Subject: Better into_inner and get_mut implementations --- src/lockable.rs | 44 +++++++++++++++++++++++++++++ src/poisonable.rs | 2 +- src/poisonable/poisonable.rs | 66 +++++++++++++++++++++++++++++++++++++++----- 3 files changed, 104 insertions(+), 8 deletions(-) diff --git a/src/lockable.rs b/src/lockable.rs index 9f44981..6eced32 100644 --- a/src/lockable.rs +++ b/src/lockable.rs @@ -151,6 +151,18 @@ pub unsafe trait Lockable { unsafe fn read_guard(&self) -> Self::ReadGuard<'_>; } +pub trait LockableIntoInner: Lockable { + type Inner; + + fn into_inner(self) -> Self::Inner; +} + +pub trait LockableAsMut: Lockable { + type Inner; + + fn as_mut(&mut self) -> &mut Self::Inner; +} + /// A marker trait to indicate that multiple readers can access the lock at a /// time. /// @@ -258,6 +270,38 @@ unsafe impl Lockable for RwLock { } } +impl LockableIntoInner for Mutex { + type Inner = T; + + fn into_inner(self) -> Self::Inner { + self.into_inner() + } +} + +impl LockableAsMut for Mutex { + type Inner = T; + + fn as_mut(&mut self) -> &mut Self::Inner { + self.get_mut() + } +} + +impl LockableIntoInner for RwLock { + type Inner = T; + + fn into_inner(self) -> Self::Inner { + self.into_inner() + } +} + +impl LockableAsMut for RwLock { + type Inner = T; + + fn as_mut(&mut self) -> &mut Self::Inner { + AsMut::as_mut(self) + } +} + unsafe impl Sharable for RwLock {} unsafe impl OwnedLockable for Mutex {} diff --git a/src/poisonable.rs b/src/poisonable.rs index a492084..6cc234e 100644 --- a/src/poisonable.rs +++ b/src/poisonable.rs @@ -35,7 +35,7 @@ struct PoisonFlag(#[cfg(panic = "unwind")] AtomicBool); /// [`into_inner`]: `PoisonError::into_inner` /// [`clear_poison`]: `Poisonable::clear_poison` #[derive(Debug, Default)] -pub struct Poisonable { +pub struct Poisonable { inner: L, poisoned: PoisonFlag, } diff --git a/src/poisonable/poisonable.rs b/src/poisonable/poisonable.rs index ff43ff8..e1c4caa 100644 --- a/src/poisonable/poisonable.rs +++ b/src/poisonable/poisonable.rs @@ -1,7 +1,7 @@ use std::marker::PhantomData; use std::panic::{RefUnwindSafe, UnwindSafe}; -use crate::lockable::{Lockable, RawLock}; +use crate::lockable::{Lockable, LockableAsMut, LockableIntoInner, RawLock}; use crate::Keyable; use super::{ @@ -282,9 +282,9 @@ impl Poisonable { /// use happylock::{Mutex, Poisonable}; /// /// let mutex = Poisonable::new(Mutex::new(0)); - /// assert_eq!(mutex.into_inner().unwrap().into_inner(), 0); + /// assert_eq!(mutex.inner_lock().unwrap().into_inner(), 0); /// ``` - pub fn into_inner(self) -> PoisonResult { + pub fn inner_lock(self) -> PoisonResult { if self.is_poisoned() { Err(PoisonError::new(self.inner)) } else { @@ -294,6 +294,58 @@ impl Poisonable { /// Returns a mutable reference to the underlying lock. /// + /// # Errors + /// + /// If another user of this lock panicked while holding the lock, then + /// this call will return an error instead. + /// + /// # Examples + /// + /// ``` + /// use happylock::{Mutex, Poisonable, ThreadKey}; + /// + /// let key = ThreadKey::get().unwrap(); + /// let mut mutex = Poisonable::new(Mutex::new(0)); + /// *mutex.lock_mut().unwrap().as_mut() = 10; + /// assert_eq!(*mutex.lock(key).unwrap(), 10); + /// ``` + pub fn lock_mut(&mut self) -> PoisonResult<&mut L> { + if self.is_poisoned() { + Err(PoisonError::new(&mut self.inner)) + } else { + Ok(&mut self.inner) + } + } +} + +impl Poisonable { + /// Consumes this `Poisonable`, returning the underlying data. + /// + /// # Errors + /// + /// If another user of this lock panicked while holding the lock, then this + /// call will return an error instead. + /// + /// # Examples + /// + /// ``` + /// use happylock::{Mutex, Poisonable}; + /// + /// let mutex = Poisonable::new(Mutex::new(0)); + /// assert_eq!(mutex.into_inner().unwrap(), 0); + /// ``` + pub fn into_inner(self) -> PoisonResult { + if self.is_poisoned() { + Err(PoisonError::new(self.inner.into_inner())) + } else { + Ok(self.inner.into_inner()) + } + } +} + +impl Poisonable { + /// Returns a mutable reference to the underlying data. + /// /// Since this call borrows the `Poisonable` mutable, no actual locking /// needs to take place - the mutable borrow statically guarantees no locks /// exist. @@ -310,14 +362,14 @@ impl Poisonable { /// /// let key = ThreadKey::get().unwrap(); /// let mut mutex = Poisonable::new(Mutex::new(0)); - /// *mutex.get_mut().unwrap().as_mut() = 10; + /// *mutex.get_mut().unwrap() = 10; /// assert_eq!(*mutex.lock(key).unwrap(), 10); /// ``` - pub fn get_mut(&mut self) -> PoisonResult<&mut L> { + pub fn get_mut(&mut self) -> PoisonResult<&mut L::Inner> { if self.is_poisoned() { - Err(PoisonError::new(&mut self.inner)) + Err(PoisonError::new(self.inner.as_mut())) } else { - Ok(&mut self.inner) + Ok(self.inner.as_mut()) } } } -- cgit v1.2.3