use core::{cell::Cell, ops::Add};
use critical_section::Mutex;
use crate::traits::LoadStore;
pub struct AtomicCell<T> {
inner: Mutex<Cell<T>>,
}
impl<T: Send + Copy> AtomicCell<T> {
pub fn load(&self) -> T {
critical_section::with(|cs| self.inner.borrow(cs).get())
}
pub fn borrow<'a>(&'a self, cs: critical_section::CriticalSection<'a>) -> &'a Cell<T> {
self.inner.borrow(cs)
}
pub fn fetch_update(&self, mut f: impl FnMut(T) -> Option<T>) -> Result<T, T> {
critical_section::with(|cs| {
let old_value = self.inner.borrow(cs).get();
if let Some(new_value) = f(old_value) {
self.inner.borrow(cs).set(new_value);
Ok(old_value)
} else {
Err(old_value)
}
})
}
}
impl<T: Send> AtomicCell<T> {
pub const fn new(value: T) -> Self {
Self {
inner: Mutex::new(Cell::new(value)),
}
}
pub fn store(&self, value: T) {
critical_section::with(|cs| self.inner.borrow(cs).set(value));
}
}
impl<T: Send + Default> AtomicCell<T> {
pub fn take(&self) -> T {
critical_section::with(|cs| self.inner.borrow(cs).take())
}
}
impl<T: Copy + Add<Output = T>> AtomicCell<T> {
pub fn fetch_add(&self, value: T) -> T {
critical_section::with(|cs| {
let old_value = self.inner.borrow(cs).get();
self.inner.borrow(cs).set(old_value + value);
old_value
})
}
}
impl<T: Default> Default for AtomicCell<T> {
fn default() -> Self {
Self {
inner: Mutex::new(Cell::new(T::default())),
}
}
}
impl<T: Default + Copy + Send> LoadStore<T> for AtomicCell<T> {
fn load(&self) -> T {
self.load()
}
fn store(&self, value: T) {
self.store(value)
}
}