summaryrefslogtreecommitdiff
path: root/src/poisonable/poisonable.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/poisonable/poisonable.rs')
-rw-r--r--src/poisonable/poisonable.rs139
1 files changed, 139 insertions, 0 deletions
diff --git a/src/poisonable/poisonable.rs b/src/poisonable/poisonable.rs
new file mode 100644
index 0000000..6c78346
--- /dev/null
+++ b/src/poisonable/poisonable.rs
@@ -0,0 +1,139 @@
+use std::marker::PhantomData;
+use std::panic::{RefUnwindSafe, UnwindSafe};
+
+use crate::lockable::{Lockable, RawLock};
+use crate::Keyable;
+
+use super::{
+ PoisonError, PoisonFlag, PoisonGuard, PoisonRef, PoisonResult, Poisonable,
+ TryLockPoisonableError, TryLockPoisonableResult,
+};
+
+unsafe impl<L: Lockable + RawLock> Lockable for Poisonable<L> {
+ type Guard<'g> = PoisonResult<PoisonRef<'g, L::Guard<'g>>> where Self: 'g;
+ type ReadGuard<'g> = PoisonResult<PoisonRef<'g, L::ReadGuard<'g>>> where Self: 'g;
+
+ fn get_ptrs<'a>(&'a self, ptrs: &mut Vec<&'a dyn RawLock>) {
+ self.inner.get_ptrs(ptrs)
+ }
+
+ unsafe fn guard(&self) -> Self::Guard<'_> {
+ let ref_guard = PoisonRef {
+ guard: self.inner.guard(),
+ flag: &self.poisoned,
+ };
+
+ if self.is_poisoned() {
+ Ok(ref_guard)
+ } else {
+ Err(PoisonError { guard: ref_guard })
+ }
+ }
+
+ unsafe fn read_guard(&self) -> Self::ReadGuard<'_> {
+ let ref_guard = PoisonRef {
+ guard: self.inner.read_guard(),
+ flag: &self.poisoned,
+ };
+
+ if self.is_poisoned() {
+ Ok(ref_guard)
+ } else {
+ Err(PoisonError { guard: ref_guard })
+ }
+ }
+}
+
+impl<L: Lockable + RawLock> From<L> for Poisonable<L> {
+ fn from(value: L) -> Self {
+ Self::new(value)
+ }
+}
+
+impl<L: Lockable + RawLock> Poisonable<L> {
+ pub const fn new(value: L) -> Self {
+ Self {
+ inner: value,
+ poisoned: PoisonFlag::new(),
+ }
+ }
+
+ unsafe fn guard<'flag, 'key, Key: Keyable + 'key>(
+ &'flag self,
+ key: Key,
+ ) -> PoisonResult<PoisonGuard<'flag, 'key, L::Guard<'flag>, Key>> {
+ let guard = PoisonGuard {
+ guard: PoisonRef {
+ guard: self.inner.guard(),
+ flag: &self.poisoned,
+ },
+ key,
+ _phantom: PhantomData,
+ };
+
+ if self.is_poisoned() {
+ Ok(guard)
+ } else {
+ Err(PoisonError { guard })
+ }
+ }
+
+ pub fn lock<'flag, 'key, Key: Keyable + 'key>(
+ &'flag self,
+ key: Key,
+ ) -> PoisonResult<PoisonGuard<'flag, 'key, L::Guard<'flag>, Key>> {
+ unsafe {
+ self.inner.lock();
+ self.guard(key)
+ }
+ }
+
+ pub fn try_lock<'flag, 'key, Key: Keyable + 'key>(
+ &'flag self,
+ key: Key,
+ ) -> TryLockPoisonableResult<'flag, 'key, L::Guard<'flag>, Key> {
+ unsafe {
+ if self.inner.try_lock() {
+ Ok(self.guard(key)?)
+ } else {
+ Err(TryLockPoisonableError::WouldBlock(key))
+ }
+ }
+ }
+
+ pub fn unlock<'flag, 'key, Key: Keyable + 'key>(
+ guard: PoisonGuard<'flag, 'key, L::Guard<'flag>, Key>,
+ ) -> Key {
+ drop(guard.guard);
+ guard.key
+ }
+
+ pub fn is_poisoned(&self) -> bool {
+ self.poisoned.is_poisoned()
+ }
+
+ pub fn clear_poison(&self) {
+ self.poisoned.clear_poison()
+ }
+
+ pub fn into_inner(self) -> PoisonResult<L> {
+ if self.is_poisoned() {
+ Err(PoisonError { guard: self.inner })
+ } else {
+ Ok(self.inner)
+ }
+ }
+
+ pub fn get_mut(&mut self) -> PoisonResult<&mut L> {
+ if self.is_poisoned() {
+ Err(PoisonError {
+ guard: &mut self.inner,
+ })
+ } else {
+ Ok(&mut self.inner)
+ }
+ }
+}
+
+impl<L: Lockable + RawLock> RefUnwindSafe for Poisonable<L> {}
+impl<L: Lockable + RawLock> UnwindSafe for Poisonable<L> {}