Documentation
extern crate std;

use core::fmt;
use std::{io, sync::Mutex};

use crate::UnsafeSeqLock;

pub struct MutexSeqLock<T> {
    seq: UnsafeSeqLock<T>,
    mutex: Mutex<()>,
}

impl<T> MutexSeqLock<T> {
    pub const fn new(value: T) -> Self {
        Self {
            seq: UnsafeSeqLock::new(value),
            mutex: Mutex::new(()),
        }
    }
}

impl<T: Copy> MutexSeqLock<T> {
    pub fn read(&self) -> T {
        unsafe { self.seq.read() }
    }
    pub fn read_version(&self) -> (u64, T) {
        unsafe { self.seq.read_version() }
    }
    pub fn try_read(&self) -> Option<T> {
        unsafe { self.seq.try_read() }
    }
    pub fn try_read_version(&self) -> Option<(u64, T)> {
        unsafe { self.seq.try_read_version() }
    }

    pub fn write(&self, value: T) {
        self.write_version(value);
    }
    pub fn write_version(&self, value: T) -> u64 {
        let _guard = unsafe { self.mutex.lock().unwrap_unchecked() };
        unsafe { self.seq.write_version(value) }
    }
    pub fn try_write(&self, value: T) -> Result<(), MutexSeqLockError> {
        self.try_write_version(value).map(|_| ())
    }
    pub fn try_write_version(&self, value: T) -> Result<u64, MutexSeqLockError> {
        match self.mutex.try_lock() {
            Ok(_guard) => unsafe { Ok(self.seq.write_version(value)) },
            Err(_) => Err(MutexSeqLockError),
        }
    }
}

#[derive(Debug, Clone, Copy)]
pub struct MutexSeqLockError;

impl fmt::Display for MutexSeqLockError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("operation would block")
    }
}

impl From<MutexSeqLockError> for io::ErrorKind {
    fn from(MutexSeqLockError: MutexSeqLockError) -> Self {
        io::ErrorKind::WouldBlock
    }
}

impl From<MutexSeqLockError> for io::Error {
    fn from(value: MutexSeqLockError) -> Self {
        io::Error::new(value.into(), value)
    }
}

impl std::error::Error for MutexSeqLockError {}