tokio/util/
atomic_cell.rs

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}