futures_signals/
atomic.rs

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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use std::sync::atomic::{AtomicPtr, Ordering};


/*#[derive(Debug)]
pub(crate) struct Atomic<A> {
    // TODO only box if the value is too big
    ptr: AtomicPtr<A>,
}

impl<A> Atomic<A> {
    pub(crate) fn new(value: A) -> Self {
        Self {
            ptr: AtomicPtr::new(Box::into_raw(Box::new(value))),
        }
    }

    fn ptr_swap(&self, value: A) -> *mut A {
        let new_ptr = Box::into_raw(Box::new(value));
        self.ptr.swap(new_ptr, Ordering::AcqRel)
    }

    pub(crate) fn swap(&self, value: A) -> A {
        let ptr = self.ptr_swap(value);
        unsafe { *Box::from_raw(ptr) }
    }

    #[inline]
    pub(crate) fn store(&self, value: A) {
        // TODO make this more efficient by using drop_in_place ?
        drop(self.swap(value));
    }
}

impl<A> Atomic<A> where A: Default {
    #[inline]
    pub(crate) fn take(&self) -> A {
        self.swap(Default::default())
    }
}

impl<A> Drop for Atomic<A> {
    fn drop(&mut self) {
        let ptr = self.ptr.load(Ordering::Acquire);

        // TODO verify the safety of this
        unsafe { drop(Box::from_raw(ptr)); }
    }
}*/


/// The same as `Atomic<Option<A>>` except faster and uses less memory.
///
/// This is because it represents `None` as a null pointer, which avoids boxing.
#[derive(Debug)]
pub(crate) struct AtomicOption<A> {
    ptr: AtomicPtr<A>,
}

impl<A> AtomicOption<A> {
    fn to_ptr(value: Option<A>) -> *mut A {
        match value {
            // TODO only box if the value is too big
            Some(value) => Box::into_raw(Box::new(value)),
            None => std::ptr::null_mut(),
        }
    }

    fn from_ptr(ptr: *mut A) -> Option<A> {
        if ptr.is_null() {
            None

        } else {
            // This is safe because we only do this for pointers created with `Box::into_raw`
            unsafe { Some(*Box::from_raw(ptr)) }
        }
    }

    #[inline]
    pub(crate) fn new(value: Option<A>) -> Self {
        Self {
            ptr: AtomicPtr::new(Self::to_ptr(value)),
        }
    }

    pub(crate) fn swap(&self, value: Option<A>) -> Option<A> {
        let new_ptr = Self::to_ptr(value);
        let old_ptr = self.ptr.swap(new_ptr, Ordering::AcqRel);
        Self::from_ptr(old_ptr)
    }

    #[inline]
    pub(crate) fn store(&self, value: Option<A>) {
        // TODO make this more efficient by using drop_in_place ?
        drop(self.swap(value));
    }

    #[inline]
    pub(crate) fn take(&self) -> Option<A> {
        self.swap(None)
    }
}

impl<A> Drop for AtomicOption<A> {
    fn drop(&mut self) {
        let ptr = self.ptr.load(Ordering::Acquire);

        if !ptr.is_null() {
            // This is safe because we only do this for pointers created with `Box::into_raw`
            unsafe { drop(Box::from_raw(ptr)); }
        }
    }
}