1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
use super::common::MemoryState;
use atomic::Atomic;
use core::mem::MaybeUninit;
use core::ptr;
use core::sync::atomic::Ordering;

#[derive(Debug)]
pub struct AtomicOption<T> {
    buf: MaybeUninit<T>,
    state: Atomic<MemoryState>,
}
impl<T> AtomicOption<T> {
    pub const fn new() -> Self {
        AtomicOption {
            buf: MaybeUninit::uninit(),
            state: Atomic::new(MemoryState::Uninitialized),
        }
    }
    fn ptr(&self) -> *mut T {
        self.buf.as_ptr() as *mut T
    }
    pub fn is_some(&self) -> bool {
        self.state.load(Ordering::Relaxed) == MemoryState::Written
    }
    pub fn is_none(&self) -> bool {
        self.state.load(Ordering::Relaxed) == MemoryState::Uninitialized
    }
    pub fn take(&self) -> Option<T> {
        if let Err(_) = self
            .state
            .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |x| match x {
                MemoryState::Written => Some(MemoryState::Reading),
                _ => None,
            })
        {
            None
        } else {
            let ret = Some(unsafe { ptr::read(self.ptr()) });
            self.state
                .store(MemoryState::Uninitialized, Ordering::Relaxed);
            ret
        }
    }
    pub fn push(&self, value: T) -> Result<(), T> {
        if let Err(_) = self
            .state
            .fetch_update(
                Ordering::Relaxed,
                Ordering::Relaxed,
                |x| match MemoryState::from(x) {
                    MemoryState::Uninitialized => Some(MemoryState::Writting.into()),
                    _ => None,
                },
            )
        {
            Err(value)
        } else {
            unsafe { ptr::write(self.ptr(), value) };
            self.state
                .store(MemoryState::Written.into(), Ordering::Relaxed);
            Ok(())
        }
    }
}
impl<T> Drop for AtomicOption<T> {
    fn drop(&mut self) {
        self.take();
    }
}