mod reentrancy;
pub trait MutableHelper {
type Value;
fn with_mut<R>(&self, callback: impl FnOnce(&mut Self::Value) -> R) -> R;
fn with_ref<R>(&self, callback: impl FnOnce(&Self::Value) -> R) -> R;
}
pub trait MutableExt: MutableHelper {
fn clone_value(&self) -> Self::Value
where
Self::Value: Clone,
{
self.with_ref(Clone::clone)
}
fn replace_value(&self, value: Self::Value) -> Self::Value {
self.with_mut(|current| std::mem::replace(current, value))
}
fn take_value(&self) -> Self::Value
where
Self::Value: Default,
{
self.with_mut(std::mem::take)
}
}
impl<M: MutableHelper + ?Sized> MutableExt for M {}
pub trait MutableBoolHelper {
fn read(&self) -> bool;
fn write(&self, value: bool);
fn change_if_not_equal(&self, value: bool) -> bool;
}
cfg_if::cfg_if! {
if #[cfg(feature = "single-threaded")] {
use std::cell::{Cell, RefCell};
pub type Mutable<T> = RefCell<T>;
impl<T> MutableHelper for RefCell<T> {
type Value = T;
fn with_mut<R>(&self, callback: impl FnOnce(&mut T) -> R) -> R {
let _held = reentrancy::held_lock(self);
callback(&mut self.borrow_mut())
}
fn with_ref<R>(&self, callback: impl FnOnce(&T) -> R) -> R {
let _held = reentrancy::held_lock(self);
callback(&self.borrow())
}
}
pub type MutableBool = Cell<bool>;
impl MutableBoolHelper for Cell<bool> {
fn read(&self) -> bool {
self.get()
}
fn write(&self, value: bool) {
self.set(value)
}
fn change_if_not_equal(&self, value: bool) -> bool {
let old = self.replace(value);
old != value
}
}
} else {
use std::sync::Mutex;
use std::sync::atomic::{AtomicBool, Ordering};
pub type Mutable<T> = Mutex<T>;
impl<T> MutableHelper for Mutex<T> {
type Value = T;
fn with_mut<R>(&self, callback: impl FnOnce(&mut T) -> R) -> R {
let _held = reentrancy::held_lock(self);
callback(&mut self.lock().unwrap())
}
fn with_ref<R>(&self, callback: impl FnOnce(&T) -> R) -> R {
let _held = reentrancy::held_lock(self);
callback(&self.lock().unwrap())
}
}
pub type MutableBool = AtomicBool;
impl MutableBoolHelper for MutableBool {
fn read(&self) -> bool {
self.load(Ordering::SeqCst)
}
fn write(&self, value: bool) {
self.store(value, Ordering::SeqCst)
}
fn change_if_not_equal(&self, value: bool) -> bool {
self.compare_exchange(!value, value, Ordering::SeqCst, Ordering::SeqCst).is_ok()
}
}
}
}