Documentation
//! Deep seq lock library.

#![no_std]

use core::{
    cell::UnsafeCell,
    sync::atomic::{AtomicU64, Ordering::SeqCst},
};

use atomic_memcpy::{atomic_load, atomic_store};

cfg_select! {
    feature = "alloc" => {
        mod _alloc;
        pub use _alloc::*;
    }
    _ => {}
}

cfg_select! {
    feature = "std" => {
        mod _std;
        pub use _std::*;
    }
    _ => {}
}

pub struct UnsafeSeqLock<T> {
    version: AtomicU64,
    value: UnsafeCell<T>,
}

impl<T> UnsafeSeqLock<T> {
    pub const fn new(value: T) -> Self {
        Self {
            version: AtomicU64::new(0),
            value: UnsafeCell::new(value),
        }
    }

    pub unsafe fn read(&self) -> T {
        loop {
            if let Some(v) = unsafe { self.try_read() } {
                break v;
            }
        }
    }
    pub unsafe fn read_version(&self) -> (u64, T) {
        loop {
            if let Some((v0, v)) = unsafe { self.try_read_version() } {
                break (v0, v);
            }
        }
    }
    pub unsafe fn try_read(&self) -> Option<T> {
        unsafe { self.try_read_version() }.map(|(_, v)| v)
    }
    pub unsafe fn try_read_version(&self) -> Option<(u64, T)> {
        let Self { version, value } = self;
        let v0 = version.load(SeqCst);
        match v0.is_multiple_of(2) {
            true => {
                let mb = unsafe { atomic_load(value.get(), SeqCst) };
                let v1 = version.load(SeqCst);
                match v0 == v1 {
                    true => Some((v0, unsafe { mb.assume_init() })),
                    false => None,
                }
            }
            false => None,
        }
    }

    pub unsafe fn write(&self, value: T) {
        unsafe { self.write_version(value) };
    }
    pub unsafe fn write_version(&self, value: T) -> u64 {
        let Self { version, value: v } = self;
        version.fetch_add(1, SeqCst);
        unsafe { atomic_store(v.get(), value, SeqCst) }
        version.fetch_add(1, SeqCst)
    }
}

unsafe impl<T: Send> Send for UnsafeSeqLock<T> {}
unsafe impl<T: Sync> Sync for UnsafeSeqLock<T> {}