#[cfg(not(feature = "std"))]
use alloc::boxed::Box;
#[cfg(not(feature = "std"))]
use core::sync::atomic::{AtomicPtr, Ordering};
#[cfg(feature = "std")]
use std::sync::atomic::{AtomicPtr, Ordering};
pub struct AtomicValue<T>(AtomicPtr<T>);
unsafe impl<T> Send for AtomicValue<T> {}
unsafe impl<T> Sync for AtomicValue<T> {}
impl<T> AtomicValue<T> {
pub fn new(value: T) -> Self {
Self(AtomicPtr::new(Box::into_raw(Box::new(value))))
}
pub fn store(&self, ordering: Ordering, value: T) {
let new_ptr = Box::into_raw(Box::new(value));
let prev_ptr = self.0.swap(new_ptr, ordering);
if prev_ptr.is_null() {
unreachable!("null pointer in AtomicValue")
}
unsafe {
drop(Box::from_raw(prev_ptr));
}
}
pub fn as_ref(&self, ordering: Ordering) -> &T {
let ptr = self.0.load(ordering);
if ptr.is_null() {
unreachable!("null pointer in AtomicValue")
}
unsafe { &*ptr }
}
pub fn as_mut(&mut self, ordering: Ordering) -> &mut T {
let ptr = self.0.load(ordering);
if ptr.is_null() {
unreachable!("null pointer in AtomicValue")
}
unsafe { &mut *ptr }
}
}
impl<T> Drop for AtomicValue<T> {
fn drop(&mut self) {
let ptr = self.0.load(Ordering::SeqCst);
if ptr.is_null() {
unreachable!("null pointer in AtomicValue")
}
unsafe { drop(Box::from_raw(ptr)) };
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_atomic_value() {
let mut atomic_value = AtomicValue::new(1);
assert_eq!(atomic_value.as_ref(Ordering::SeqCst), &1);
assert_eq!(atomic_value.as_mut(Ordering::SeqCst), &mut 1);
atomic_value.store(Ordering::SeqCst, 2);
assert_eq!(atomic_value.as_ref(Ordering::SeqCst), &2);
assert_eq!(atomic_value.as_mut(Ordering::SeqCst), &mut 2);
}
}