tempref 0.3.0

This crate provides a type whose value remains unchanged even when accessed through a mutable reference.
Documentation
//! Multi thread version which used `RwLock` of TempRef. This module requires std.

extern crate std;

use core::cell::UnsafeCell;
use core::fmt::Debug;
use std::sync::{PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard, TryLockError};

type WriteResult<T> = Result<T, PoisonError<T>>;
type TryLockResult<T> = Result<T, TryLockError<T>>;

/// A mutable reference wrapper from [`Temp<T, F>`].
///
/// When dropped, it automatically calls the reset function on the underlying value.
/// This ensures that temporary mutations never leave the value in an inconsistent state.
pub struct TempRef<'a, T: Send, F: FnMut(&mut T) + Sync> {
    re: RwLockWriteGuard<'a, T>,
    reset: &'a mut F,
}
impl<'a, T: Send, F: FnMut(&mut T) + Sync> TempRef<'a, T, F> {
    fn new(re: RwLockWriteGuard<'a, T>, reset: &'a mut F) -> Self {
        TempRef { re, reset }
    }
    fn write(temp: &'a Temp<T, F>) -> WriteResult<Self> {
        let reset = unsafe { &mut *temp.reset.get() };
        match temp.value.write() {
            Ok(guard) => Ok(TempRef::new(guard, reset)),
            Err(err) => Err(PoisonError::new(TempRef::new(err.into_inner(), reset))),
        }
    }
    fn try_write(temp: &'a Temp<T, F>) -> TryLockResult<Self> {
        let reset = unsafe { &mut *temp.reset.get() };
        match temp.value.try_write() {
            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),
        }
    }

    /// Invokes the reset function on the internal value.
    pub fn reset(&mut self) {
        (self.reset)(&mut self.re);
    }
}
impl<'a, T: Send, F: FnMut(&mut T) + Sync> 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) + Sync> 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) + Sync> Drop for TempRef<'a, T, F> {
    fn drop(&mut self) {
        (self.reset)(&mut self.re);
    }
}
impl<'a, T: Send + Debug, F: FnMut(&mut T) + Sync> 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()
    }
}

/// A value protected by `RwLock` that ensures its mutable reference is always reset when dropped.
///
/// `Temp<T, F>` holds a value of type `T` inside an `RwLock`, together with a reset
/// function `F: Mut(&mut T)`. Every time a mutable borrow is created via [`Self::write`],
/// the returned [`TempRef`] will call the reset function when dropped.
///
/// This guarantees that temporary mutations in a multithreaded context
/// never leave the value in an inconsistent state.
///
/// # Examples
/// ```
/// use tempref::rwlock::Temp;
///
/// let data = vec![0;128];
/// let workspace = Temp::new(data, |d| {d.fill(0);});
///
/// assert_eq!(*workspace.read().unwrap(), vec![0;128]);
///
/// {
///     let mut guard = workspace.write().unwrap();
///     guard.fill(1);
///     assert_eq!(*guard, vec![1;128]);
/// }
/// assert_eq!(*workspace.read().unwrap(), vec![0;128]);
/// ```
pub struct Temp<T: Send, F: FnMut(&mut T) + Sync> {
    value: RwLock<T>,
    reset: UnsafeCell<F>,
}
impl<T: Send, F: FnMut(&mut T) + Sync> Temp<T, F> {
    /// A constructor of Temp<T, F>.
    pub const fn new(value: T, reset: F) -> Self {
        Temp {
            value: RwLock::new(value),
            reset: UnsafeCell::new(reset),
        }
    }
    /// A constructor of Temp<T, F>.
    ///
    /// Unlike [`Self::new`], this constructor immediately applies the given `reset`
    /// function to the initial `value` before storing it.
    pub fn new_with(mut value: T, mut reset: F) -> Self {
        reset(&mut value);
        Temp {
            value: RwLock::new(value),
            reset: UnsafeCell::new(reset),
        }
    }
    /// Locks this Temp with shared read access, blocking the current thread until it can be acquired.
    pub fn read<'a>(
        &'a self,
    ) -> Result<RwLockReadGuard<'a, T>, PoisonError<RwLockReadGuard<'a, T>>> {
        self.value.read()
    }
    /// Acquires an exclusive write lock on this `Temp`, blocking the current thread until the lock is available.
    /// The returned `TempRef` automatically resets itself when dropped.
    pub fn write<'a>(&'a self) -> WriteResult<TempRef<'a, T, F>> {
        TempRef::write(self)
    }
    /// Attempts to acquire this Temp with shared read access.
    /// If the access could not be granted at this time, then Err is returned. Otherwise, an RAII guard is returned which will release the shared access when it is dropped.
    pub fn try_read<'a>(
        &'a self,
    ) -> Result<RwLockReadGuard<'a, T>, TryLockError<RwLockReadGuard<'a, T>>> {
        self.value.try_read()
    }
    /// Attempts to lock this Temp with exclusive write access.
    /// If the lock could not be acquired at this time, then Err is returned. Otherwise, TempRef is returned which will release the lock when it is dropped.
    /// Automatically resets itself when dropped.
    pub fn try_write<'a>(&'a self) -> TryLockResult<TempRef<'a, T, F>> {
        TempRef::try_write(self)
    }
    /// Consumes this Temp, returning the underlying data.
    pub fn into_inner(self) -> WriteResult<T> {
        self.value.into_inner()
    }
    /// Clear the poisoned state from a lock.
    pub fn clear_poison(&self) {
        self.value.clear_poison();
    }
    /// Determines whether the lock is poisoned.
    pub fn is_poisoned(&self) -> bool {
        self.value.is_poisoned()
    }
    /// Invokes the reset function on the internal value.
    ///
    /// This method acquires a blocking write lock on the internal value.
    /// If the lock is poisoned, it returns a `PoisonError`.
    pub fn reset(&self) -> WriteResult<()> {
        if let Ok(mut guard) = self.value.write() {
            self.get_reset()(&mut guard);
            Ok(())
        } else {
            Err(PoisonError::new(()))
        }
    }
    /// Attempts to invoke the reset function on the internal value.
    ///
    /// This method tries to acquire a non-blocking write lock on the internal value.
    /// If the lock cannot be immediately acquired, it returns a `TryLockError`.
    pub fn try_reset(&self) -> TryLockResult<()> {
        match self.value.try_write() {
            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) + Sync> Temp<T, F> {
    /// Creates a new `Temp<T, F>` using `T::default()` as the initial value.
    pub fn new_default(reset: F) -> Self {
        Temp {
            value: RwLock::new(T::default()),
            reset: UnsafeCell::new(reset),
        }
    }
    /// Creates a new `Temp<T, F>` using `T::default()` as the initial value,
    /// and immediately applies the given `reset` function to it.
    ///
    /// This is similar to [`Self::new_default`], but the `reset` function is called once
    /// during initialization.
    pub fn new_default_with(mut reset: F) -> Self {
        let mut default = T::default();
        reset(&mut default);
        Temp {
            value: RwLock::new(default),
            reset: UnsafeCell::new(reset),
        }
    }
}
unsafe impl<T: Send, F: FnMut(&mut T) + Sync> Send for Temp<T, F> {}
unsafe impl<T: Send, F: FnMut(&mut T) + Sync> Sync for Temp<T, F> {}
impl<T: Debug + Send, F: FnMut(&mut T) + Sync> 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()
    }
}