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 `Mutex` of TempRef. This module requires std.

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>>;

/// A mutable reference from `Temp<T, F>`.
/// When it is dropped, it calls the reset function.
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),
        }
    }

    /// 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) + 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()
    }
}

/// A value protected by a `Mutex` that ensures its mutable reference is always reset when dropped.
///
/// `Temp<T, F>` holds a value of type `T` inside a `Mutex`, together with a reset
/// function `F: FnMut(&mut T)`. Every time a mutable borrow is created via [`Self::lock`]
/// or [`Self::try_lock`], the returned [`TempRef`] will call the reset function when dropped.
///
/// This guarantees that temporary mutations never leave the value in an
/// inconsistent state, even in multithreaded contexts.
///
/// # Examples
/// ```
/// use tempref::mutex::Temp;
///
/// let data = vec![1;128];
/// let workspace = Temp::new(data, |d| {d.fill(0);});
///
/// assert_eq!(*workspace.lock().unwrap(), vec![1;128]);
/// // Note: The reset function is called here because MutexLock is mutable reference.
/// assert_eq!(*workspace.lock().unwrap(), vec![0;128]);
///
/// {
///     let mut guard = workspace.lock().unwrap();
///     guard.fill(1);
///     assert_eq!(*guard, vec![1;128]);
/// }
/// assert_eq!(*workspace.lock().unwrap(), vec![0;128]);
/// ```
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> {
    /// A constructor of Temp<T, F>.
    pub const fn new(value: T, reset: F) -> Self {
        Temp {
            value: Mutex::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: Mutex::new(value),
            reset: UnsafeCell::new(reset),
        }
    }
    /// Creates `TempRef`.
    /// Automatically resets itself when dropped.
    /// Acquires a mutex, blocking the current thread until it is able to do so.
    pub fn lock<'a>(&'a self) -> PoisonResult<TempRef<'a, T, F>> {
        TempRef::lock(self)
    }
    /// Attempts to acquire this lock.
    /// If the lock could not be acquired at this time, then Err is returned. Otherwise, TempRef is returned.
    pub fn try_lock<'a>(&'a self) -> TryLockResult<TempRef<'a, T, F>> {
        TempRef::try_lock(self)
    }
    /// Consumes the Temp, returning the wrapped value.
    pub fn into_inner(self) -> PoisonResult<T> {
        self.value.into_inner()
    }
    /// Clear the poisoned state from a mutex.
    pub fn clear_poison(&self) {
        self.value.clear_poison();
    }
    /// Determines whether the mutex 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 lock on the internal `Mutex<T>`.
    /// If the lock is poisoned due to a panic in another thread, it returns a `PoisonError`.
    pub fn reset(&self) -> PoisonResult<()> {
        if let Ok(mut guard) = self.value.lock() {
            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 lock on the internal `Mutex<T>`.
    /// If the lock is already held or poisoned, it returns a `TryLockError`.
    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> {
    /// Creates a new `Temp<T, F>` using `T::default()` as the initial value.
    pub fn new_default(reset: F) -> Self {
        Temp {
            value: Mutex::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: 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()
    }
}