qrwcell/
raw.rs

1//! The raw quick read-write cell.
2
3use std::sync::atomic::AtomicUsize;
4use std::sync::atomic::Ordering as AtomicOrdering;
5use std::sync::Arc;
6use std::sync::Weak;
7
8use parking_lot::Mutex;
9use parking_lot::Once;
10use parking_lot::OnceState;
11use parking_lot::RwLock;
12
13/// Raw quick read-write cell.
14pub(crate) struct RawQrwCell<T> {
15    inner: [RwLock<Option<Arc<T>>>; 2],
16    selector: AtomicUsize,
17    update_lock: Mutex<()>,
18    init: Once,
19}
20
21impl<T: Default> Default for RawQrwCell<T> {
22    fn default() -> Self {
23        let init = Once::new();
24        init.call_once(|| ());
25        Self {
26            inner: [RwLock::new(Some(Arc::new(T::default()))), RwLock::new(None)],
27            selector: AtomicUsize::new(0),
28            update_lock: Mutex::new(()),
29            init,
30        }
31    }
32}
33
34impl<T> RawQrwCell<T> {
35    /// Create a new, empty RawQrwCell.
36    pub(crate) const fn new() -> Self {
37        Self {
38            inner: [
39                parking_lot::const_rwlock(None),
40                parking_lot::const_rwlock(None),
41            ],
42            selector: AtomicUsize::new(0),
43            update_lock: parking_lot::const_mutex(()),
44            init: Once::new(),
45        }
46    }
47
48    /// Create a new RawQrwCell with a value.
49    pub(crate) fn with_value(value: T) -> Self {
50        let init = Once::new();
51        init.call_once(|| ());
52        Self {
53            inner: [RwLock::new(Some(Arc::new(value))), RwLock::new(None)],
54            selector: AtomicUsize::new(0),
55            update_lock: Mutex::new(()),
56            init,
57        }
58    }
59
60    /// Get the current value of the cell.
61    pub(crate) fn get(&self) -> Arc<T> {
62        if self.init.state() != OnceState::Done {
63            panic!("Attempted to read from a qrwcell that has not been initialized!");
64        }
65        loop {
66            let selector = self.get_selector();
67            let guard = self.inner[selector].read();
68            if let Some(value) = guard.as_ref() {
69                break Arc::clone(value);
70            }
71        }
72    }
73
74    /// Get the current value of the cell (as a weak pointer).
75    pub(crate) fn get_weak(&self) -> Weak<T> {
76        if self.init.state() != OnceState::Done {
77            panic!("Attempted to read from a qrwcell that has not been initialized!");
78        }
79        loop {
80            let selector = self.get_selector();
81            let guard = self.inner[selector].read();
82            if let Some(value) = guard.as_ref() {
83                break Arc::downgrade(value);
84            }
85        }
86    }
87
88    /// Update the cell, returning the old value.
89    pub(crate) fn update(&self, new: T) -> Arc<T> {
90        self.init.call_once(|| ());
91        let _update_lock = self.update_lock.lock();
92        let new_arc = Arc::new(new);
93        let selector = self.get_selector() ^ 1;
94        {
95            let mut cell = self.inner[selector].write();
96            *cell = Some(Arc::clone(&new_arc));
97        }
98        let selector = self.switch_selector();
99        {
100            let mut cell = self.inner[selector].write();
101            cell.take().unwrap_or(new_arc)
102        }
103    }
104
105    #[inline]
106    fn get_selector(&self) -> usize {
107        self.selector.load(AtomicOrdering::Acquire)
108    }
109
110    #[inline]
111    fn switch_selector(&self) -> usize {
112        self.selector.fetch_xor(1, AtomicOrdering::Release)
113    }
114}