jsave 0.2.1

Persist serializable in-memory data in JSON format
Documentation
use parking_lot::{
    MappedReentrantMutexGuard as InnerMappedReentrantMutexGuard,
    ReentrantMutex as InnerReentrantMutex, ReentrantMutexGuard as InnerReentrantMutexGuard,
};
use serde::{Deserialize, Serialize};
use std::{
    fmt::{Debug, Display, Formatter, Result as FmtResult},
    fs::OpenOptions,
    io::Error,
    ops::Deref,
    path::{Path, PathBuf},
    time::{Duration, Instant},
};

pub struct ReentrantMutex<T: ?Sized> {
    file_path: PathBuf,
    data: InnerReentrantMutex<T>,
}

impl<T> ReentrantMutex<T>
where
    T: Serialize + for<'de> Deserialize<'de> + ?Sized,
{
    #[inline]
    pub fn init<P: Into<PathBuf>>(file_path: P) -> Result<Self, Error> {
        let file_path = file_path.into();

        let data = {
            let read = OpenOptions::new().read(true).open(&file_path)?;
            serde_json::from_reader(read)?
        };

        crate::save_data_to_path(&data, &file_path)?;

        Ok(Self {
            data: InnerReentrantMutex::new(data),
            file_path,
        })
    }

    #[inline]
    pub fn init_with<P: Into<PathBuf>>(data: T, file_path: P) -> Result<Self, Error> {
        let file_path = file_path.into();

        crate::save_data_to_path(&data, &file_path)?;

        Ok(Self {
            data: InnerReentrantMutex::new(data),
            file_path,
        })
    }

    #[inline]
    pub fn into_inner(self) -> T {
        self.data.into_inner()
    }

    #[inline]
    pub fn path(&self) -> &Path {
        &self.file_path
    }

    #[inline]
    pub fn get_mut(&mut self) -> &mut T {
        self.data.get_mut()
    }

    #[inline]
    pub fn is_locked(&self) -> bool {
        self.data.is_locked()
    }

    #[inline]
    pub fn is_owned_by_current_thread(&self) -> bool {
        self.data.is_owned_by_current_thread()
    }

    #[inline]
    pub fn data_ptr(&self) -> *mut T {
        self.data.data_ptr()
    }

    #[inline]
    pub fn lock(&self) -> ReentrantMutexGuard<T> {
        ReentrantMutexGuard {
            remutex: self,
            guard: self.data.lock(),
        }
    }

    #[inline]
    pub fn try_lock(&self) -> Option<ReentrantMutexGuard<T>> {
        self.data.try_lock().map(|g| ReentrantMutexGuard {
            remutex: self,
            guard: g,
        })
    }

    #[inline]
    pub fn try_lock_for(&self, timeout: Duration) -> Option<ReentrantMutexGuard<T>> {
        self.data
            .try_lock_for(timeout)
            .map(|g| ReentrantMutexGuard {
                remutex: self,
                guard: g,
            })
    }

    #[inline]
    pub fn try_lock_until(&self, timeout: Instant) -> Option<ReentrantMutexGuard<T>> {
        self.data
            .try_lock_until(timeout)
            .map(|g| ReentrantMutexGuard {
                remutex: self,
                guard: g,
            })
    }

    #[inline]
    pub fn save(&self) -> Result<(), Error> {
        let data = self.data.lock();
        crate::save_data_to_path(data.deref(), &self.file_path)
    }

    #[inline]
    pub fn try_save(&self) -> Option<Result<(), Error>> {
        self.data
            .try_lock()
            .map(|data| crate::save_data_to_path(data.deref(), &self.file_path))
    }

    #[inline]
    pub fn try_save_for(&self, timeout: Duration) -> Option<Result<(), Error>> {
        self.data
            .try_lock_for(timeout)
            .map(|data| crate::save_data_to_path(data.deref(), &self.file_path))
    }

    #[inline]
    pub fn try_save_until(&self, timeout: Instant) -> Option<Result<(), Error>> {
        self.data
            .try_lock_until(timeout)
            .map(|data| crate::save_data_to_path(data.deref(), &self.file_path))
    }

    #[inline]
    #[allow(clippy::missing_safety_doc)]
    pub unsafe fn force_unlock(&self) {
        self.data.force_unlock()
    }

    #[inline]
    #[allow(clippy::missing_safety_doc)]
    pub unsafe fn force_unlock_fair(&self) {
        self.data.force_unlock_fair()
    }
}

impl<T> Debug for ReentrantMutex<T>
where
    T: Debug + Serialize + for<'de> Deserialize<'de> + ?Sized,
{
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
        self.data.fmt(f)
    }
}

pub struct ReentrantMutexGuard<'a, T: ?Sized> {
    remutex: &'a ReentrantMutex<T>,
    guard: InnerReentrantMutexGuard<'a, T>,
}

impl<'a, T: ?Sized> ReentrantMutexGuard<'a, T> {
    #[inline]
    pub fn remutex(s: &Self) -> &'a ReentrantMutex<T> {
        s.remutex
    }

    #[inline]
    pub fn map<U: ?Sized, F>(s: Self, f: F) -> MappedReentrantMutexGuard<'a, U>
    where
        F: FnOnce(&T) -> &U,
    {
        MappedReentrantMutexGuard(InnerReentrantMutexGuard::map(s.guard, f))
    }

    #[inline]
    pub fn try_map<U: ?Sized, F>(s: Self, f: F) -> Result<MappedReentrantMutexGuard<'a, U>, Self>
    where
        F: FnOnce(&mut T) -> Option<&mut U>,
    {
        InnerReentrantMutexGuard::try_map(s.guard, f).map_or_else(
            |g| {
                Err(Self {
                    remutex: s.remutex,
                    guard: g,
                })
            },
            |g| Ok(MappedReentrantMutexGuard(g)),
        )
    }

    #[inline]
    pub fn unlocked<F, U>(s: &mut Self, f: F) -> U
    where
        F: FnOnce() -> U,
    {
        InnerReentrantMutexGuard::unlocked(&mut s.guard, f)
    }

    #[inline]
    pub fn unlocked_fair<F, U>(s: &mut Self, f: F) -> U
    where
        F: FnOnce() -> U,
    {
        InnerReentrantMutexGuard::unlocked_fair(&mut s.guard, f)
    }

    #[inline]
    pub fn unlock_fair(s: Self) {
        InnerReentrantMutexGuard::unlock_fair(s.guard);
    }

    #[inline]
    pub fn bump(s: &mut Self) {
        InnerReentrantMutexGuard::bump(&mut s.guard);
    }
}

impl<T> Debug for ReentrantMutexGuard<'_, T>
where
    T: Debug + ?Sized,
{
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
        self.guard.fmt(f)
    }
}

impl<T> Display for ReentrantMutexGuard<'_, T>
where
    T: Display + ?Sized,
{
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
        self.guard.fmt(f)
    }
}

impl<T: ?Sized + Serialize> Deref for ReentrantMutexGuard<'_, T> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &Self::Target {
        self.guard.deref()
    }
}

pub struct MappedReentrantMutexGuard<'a, T: ?Sized>(InnerMappedReentrantMutexGuard<'a, T>);

impl<'a, T: ?Sized> MappedReentrantMutexGuard<'a, T> {
    #[inline]
    pub fn map<U: ?Sized, F>(s: Self, f: F) -> MappedReentrantMutexGuard<'a, U>
    where
        F: FnOnce(&T) -> &U,
    {
        MappedReentrantMutexGuard(InnerMappedReentrantMutexGuard::map(s.0, f))
    }

    #[inline]
    pub fn try_map<U: ?Sized, F>(s: Self, f: F) -> Result<MappedReentrantMutexGuard<'a, U>, Self>
    where
        F: FnOnce(&T) -> Option<&U>,
    {
        InnerMappedReentrantMutexGuard::try_map(s.0, f)
            .map_or_else(|g| Err(Self(g)), |g| Ok(MappedReentrantMutexGuard(g)))
    }

    #[inline]
    pub fn unlock_fair(s: Self) {
        InnerMappedReentrantMutexGuard::unlock_fair(s.0);
    }
}

impl<T> Debug for MappedReentrantMutexGuard<'_, T>
where
    T: Debug + ?Sized,
{
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
        self.0.fmt(f)
    }
}

impl<T> Display for MappedReentrantMutexGuard<'_, T>
where
    T: Display + ?Sized,
{
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
        self.0.fmt(f)
    }
}

impl<T: ?Sized + Serialize> Deref for MappedReentrantMutexGuard<'_, T> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &Self::Target {
        self.0.deref()
    }
}