atomicoption 0.2.0

An atomic, nullable, owned pointer.
Documentation
#[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);
  }
}