use super::AtomicU64;
use crate::loom::sync::{atomic::Ordering, Mutex};
use crate::util::once_cell::OnceCell;

pub(crate) struct StaticAtomicU64 {
    init: u64,
    cell: OnceCell<Mutex<u64>>,
}

impl AtomicU64 {
    pub(crate) fn new(val: u64) -> Self {
        Self {
            inner: Mutex::new(val),
        }
    }
}

impl StaticAtomicU64 {
    pub(crate) const fn new(val: u64) -> StaticAtomicU64 {
        StaticAtomicU64 {
            init: val,
            cell: OnceCell::new(),
        }
    }

    pub(crate) fn load(&self, order: Ordering) -> u64 {
        *self.inner().lock()
    }

    pub(crate) fn fetch_add(&self, val: u64, order: Ordering) -> u64 {
        let mut lock = self.inner().lock();
        let prev = *lock;
        *lock = prev + val;
        prev
    }

    pub(crate) fn compare_exchange_weak(
        &self,
        current: u64,
        new: u64,
        _success: Ordering,
        _failure: Ordering,
    ) -> Result<u64, u64> {
        let mut lock = self.inner().lock();

        if *lock == current {
            *lock = new;
            Ok(current)
        } else {
            Err(*lock)
        }
    }

    fn inner(&self) -> &Mutex<u64> {
        self.cell.get(|| Mutex::new(self.init))
    }
}
