1use crate::loom::sync::atomic::AtomicPtr;
2
3use std::ptr;
4use std::sync::atomic::Ordering::AcqRel;
5
6pub(crate) struct AtomicCell<T> {
7 data: AtomicPtr<T>,
8}
9
10unsafe impl<T: Send> Send for AtomicCell<T> {}
11unsafe impl<T: Send> Sync for AtomicCell<T> {}
12
13impl<T> AtomicCell<T> {
14 pub(crate) fn new(data: Option<Box<T>>) -> AtomicCell<T> {
15 AtomicCell {
16 data: AtomicPtr::new(to_raw(data)),
17 }
18 }
19
20 pub(crate) fn swap(&self, val: Option<Box<T>>) -> Option<Box<T>> {
21 let old = self.data.swap(to_raw(val), AcqRel);
22 from_raw(old)
23 }
24
25 pub(crate) fn set(&self, val: Box<T>) {
26 let _ = self.swap(Some(val));
27 }
28
29 pub(crate) fn take(&self) -> Option<Box<T>> {
30 self.swap(None)
31 }
32}
33
34fn to_raw<T>(data: Option<Box<T>>) -> *mut T {
35 data.map_or(ptr::null_mut(), Box::into_raw)
36}
37
38fn from_raw<T>(val: *mut T) -> Option<Box<T>> {
39 if val.is_null() {
40 None
41 } else {
42 Some(unsafe { Box::from_raw(val) })
43 }
44}
45
46impl<T> Drop for AtomicCell<T> {
47 fn drop(&mut self) {
48 // Free any data still held by the cell
49 let _ = self.take();
50 }
51}
52