summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lockable.rs44
-rw-r--r--src/poisonable.rs2
-rw-r--r--src/poisonable/poisonable.rs66
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<T: Send, R: RawRwLock + Send + Sync> Lockable for RwLock<T, R> {
}
}
+impl<T: Send, R: RawMutex + Send + Sync> LockableIntoInner for Mutex<T, R> {
+ type Inner = T;
+
+ fn into_inner(self) -> Self::Inner {
+ self.into_inner()
+ }
+}
+
+impl<T: Send, R: RawMutex + Send + Sync> LockableAsMut for Mutex<T, R> {
+ type Inner = T;
+
+ fn as_mut(&mut self) -> &mut Self::Inner {
+ self.get_mut()
+ }
+}
+
+impl<T: Send, R: RawRwLock + Send + Sync> LockableIntoInner for RwLock<T, R> {
+ type Inner = T;
+
+ fn into_inner(self) -> Self::Inner {
+ self.into_inner()
+ }
+}
+
+impl<T: Send, R: RawRwLock + Send + Sync> LockableAsMut for RwLock<T, R> {
+ type Inner = T;
+
+ fn as_mut(&mut self) -> &mut Self::Inner {
+ AsMut::as_mut(self)
+ }
+}
+
unsafe impl<T: Send, R: RawRwLock + Send + Sync> Sharable for RwLock<T, R> {}
unsafe impl<T: Send, R: RawMutex + Send + Sync> OwnedLockable for Mutex<T, R> {}
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<L: Lockable + RawLock> {
+pub struct Poisonable<L> {
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<L: Lockable + RawLock> Poisonable<L> {
/// 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<L> {
+ pub fn inner_lock(self) -> PoisonResult<L> {
if self.is_poisoned() {
Err(PoisonError::new(self.inner))
} else {
@@ -294,6 +294,58 @@ impl<L: Lockable + RawLock> Poisonable<L> {
/// 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<L: LockableIntoInner + RawLock> Poisonable<L> {
+ /// 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<L::Inner> {
+ if self.is_poisoned() {
+ Err(PoisonError::new(self.inner.into_inner()))
+ } else {
+ Ok(self.inner.into_inner())
+ }
+ }
+}
+
+impl<L: LockableAsMut + RawLock> Poisonable<L> {
+ /// 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<L: Lockable + RawLock> Poisonable<L> {
///
/// 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())
}
}
}