1 | use crate::loom::sync::atomic::AtomicPtr; |
2 | |
3 | use std::ptr; |
4 | use std::sync::atomic::Ordering::AcqRel; |
5 | |
6 | pub(crate) struct AtomicCell<T> { |
7 | data: AtomicPtr<T>, |
8 | } |
9 | |
10 | unsafe impl<T: Send> Send for AtomicCell<T> {} |
11 | unsafe impl<T: Send> Sync for AtomicCell<T> {} |
12 | |
13 | impl<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: *mut T = self.data.swap(ptr:to_raw(val), order:AcqRel); |
22 | from_raw(val:old) |
23 | } |
24 | |
25 | pub(crate) fn set(&self, val: Box<T>) { |
26 | let _ = self.swap(val:Some(val)); |
27 | } |
28 | |
29 | pub(crate) fn take(&self) -> Option<Box<T>> { |
30 | self.swap(val:None) |
31 | } |
32 | } |
33 | |
34 | fn to_raw<T>(data: Option<Box<T>>) -> *mut T { |
35 | data.map_or(default:ptr::null_mut(), f:Box::into_raw) |
36 | } |
37 | |
38 | fn 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 | |
46 | impl<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 | |