extern crate std;
use core::cell::UnsafeCell;
use core::fmt::Debug;
use std::sync::{Mutex, MutexGuard, PoisonError, TryLockError};
type PoisonResult<T> = Result<T, PoisonError<T>>;
type TryLockResult<T> = Result<T, TryLockError<T>>;
pub struct TempRef<'a, T: Send, F: FnMut(&mut T) + Send> {
re: MutexGuard<'a, T>,
reset: &'a mut F,
}
impl<'a, T: Send, F: FnMut(&mut T) + Send> TempRef<'a, T, F> {
fn new(re: MutexGuard<'a, T>, reset: &'a mut F) -> Self {
TempRef { re, reset }
}
fn lock(temp: &'a Temp<T, F>) -> PoisonResult<Self> {
let reset = unsafe { &mut *temp.reset.get() };
match temp.value.lock() {
Ok(guard) => Ok(TempRef::new(guard, reset)),
Err(err) => Err(PoisonError::new(TempRef::new(err.into_inner(), reset))),
}
}
fn try_lock(temp: &'a Temp<T, F>) -> TryLockResult<Self> {
let reset = unsafe { &mut *temp.reset.get() };
match temp.value.try_lock() {
Ok(guard) => Ok(TempRef::new(guard, reset)),
Err(TryLockError::Poisoned(err)) => Err(TryLockError::Poisoned(PoisonError::new(
TempRef::new(err.into_inner(), reset),
))),
Err(TryLockError::WouldBlock) => Err(TryLockError::WouldBlock),
}
}
pub fn reset(&mut self) {
(self.reset)(&mut self.re)
}
}
impl<'a, T: Send, F: FnMut(&mut T) + Send> core::ops::Deref for TempRef<'a, T, F> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.re
}
}
impl<'a, T: Send, F: FnMut(&mut T) + Send> core::ops::DerefMut for TempRef<'a, T, F> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.re
}
}
impl<'a, T: Send, F: FnMut(&mut T) + Send> Drop for TempRef<'a, T, F> {
fn drop(&mut self) {
(self.reset)(&mut self.re);
}
}
impl<'a, T: Debug + Send, F: FnMut(&mut T) + Send> Debug for TempRef<'a, T, F> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("TempRef").field("value", &self.re).finish()
}
}
pub struct Temp<T: Send, F: FnMut(&mut T) + Send> {
value: Mutex<T>,
reset: UnsafeCell<F>,
}
impl<T: Send, F: FnMut(&mut T) + Send> Temp<T, F> {
pub const fn new(value: T, reset: F) -> Self {
Temp {
value: Mutex::new(value),
reset: UnsafeCell::new(reset),
}
}
pub fn new_with(mut value: T, mut reset: F) -> Self {
reset(&mut value);
Temp {
value: Mutex::new(value),
reset: UnsafeCell::new(reset),
}
}
pub fn lock<'a>(&'a self) -> PoisonResult<TempRef<'a, T, F>> {
TempRef::lock(self)
}
pub fn try_lock<'a>(&'a self) -> TryLockResult<TempRef<'a, T, F>> {
TempRef::try_lock(self)
}
pub fn into_inner(self) -> PoisonResult<T> {
self.value.into_inner()
}
pub fn clear_poison(&self) {
self.value.clear_poison();
}
pub fn is_poisoned(&self) -> bool {
self.value.is_poisoned()
}
pub fn reset(&self) -> PoisonResult<()> {
if let Ok(mut guard) = self.value.lock() {
self.get_reset()(&mut guard);
Ok(())
} else {
Err(PoisonError::new(()))
}
}
pub fn try_reset(&self) -> TryLockResult<()> {
match self.value.try_lock() {
Ok(mut guard) => {
self.get_reset()(&mut guard);
Ok(())
},
Err(TryLockError::Poisoned(_)) => Err(TryLockError::Poisoned(PoisonError::new(()))),
Err(TryLockError::WouldBlock) => Err(TryLockError::WouldBlock),
}
}
#[allow(clippy::mut_from_ref)]
fn get_reset(&self) -> &mut F {
unsafe { &mut *self.reset.get() }
}
}
impl<T: Default + Send, F: FnMut(&mut T) + Send> Temp<T, F> {
pub fn new_default(reset: F) -> Self {
Temp {
value: Mutex::new(T::default()),
reset: UnsafeCell::new(reset),
}
}
pub fn new_default_with(mut reset: F) -> Self {
let mut default = T::default();
reset(&mut default);
Temp {
value: Mutex::new(default),
reset: UnsafeCell::new(reset),
}
}
}
unsafe impl<T: Send, F: FnMut(&mut T) + Send> Send for Temp<T, F> {}
unsafe impl<T: Send, F: FnMut(&mut T) + Send> Sync for Temp<T, F> {}
impl<T: Debug + Send, F: FnMut(&mut T) + Send> Debug for Temp<T, F> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Temp").field("value", &self.value).finish()
}
}