From bd64ff98530ea5f92ce528009d65203f0f6676fe Mon Sep 17 00:00:00 2001 From: Mica White Date: Wed, 17 Jul 2024 16:37:21 -0400 Subject: Create Poisonable API --- src/poisonable/poisonable.rs | 139 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 src/poisonable/poisonable.rs (limited to 'src/poisonable/poisonable.rs') 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 Lockable for Poisonable { + type Guard<'g> = PoisonResult>> where Self: 'g; + type ReadGuard<'g> = PoisonResult>> 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 From for Poisonable { + fn from(value: L) -> Self { + Self::new(value) + } +} + +impl Poisonable { + 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, 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, 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 { + 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 RefUnwindSafe for Poisonable {} +impl UnwindSafe for Poisonable {} -- cgit v1.2.3