Skip to main content

keepcalm/
rcu.rs

1use parking_lot::RwLock;
2use std::{fmt::Debug, sync::Arc};
3
4/// A read/copy/update "lock". Reads are nearly instantaneous as they work from the current version at the time of
5/// the read. Writes are not blocked by reads.
6pub struct RcuLock<T: ?Sized> {
7    cloner: fn(&Arc<T>) -> Box<T>,
8    lock: RwLock<Arc<T>>,
9}
10
11impl<T: ?Sized + Debug> Debug for RcuLock<T> {
12    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13        self.lock.fmt(f)
14    }
15}
16
17impl<T: ?Sized> RcuLock<T> {
18    /// Create a new [`RcuLock`] from the given [`std::clone::Clone`]able value.
19    pub fn new(value: T) -> Self
20    where
21        T: Clone + Sized,
22    {
23        Self {
24            cloner: |x| Box::new((**x).clone()),
25            lock: RwLock::new(Arc::new(value)),
26        }
27    }
28
29    /// Take a read lock on this [`RcuLock`], which is basically just a clone of a reference the current value. This value will never change.
30    pub fn read(&self) -> RcuReadGuard<T> {
31        RcuReadGuard {
32            value: self.lock.read().clone(),
33        }
34    }
35
36    /// Take a write lock on this [`RcuLock`], which will commit to the current value of the [`RcuLock`] when the lock is dropped.
37    pub fn write(&self) -> RcuWriteGuard<T> {
38        RcuWriteGuard {
39            lock: &self.lock,
40            writer: Some((self.cloner)(&*self.lock.read())),
41        }
42    }
43
44    pub fn try_unwrap(self) -> Result<T, Self>
45    where
46        T: Sized,
47    {
48        let lock = self.lock.into_inner();
49        match Arc::try_unwrap(lock) {
50            Ok(x) => Ok(x),
51            Err(lock) => Err(Self {
52                cloner: self.cloner,
53                lock: RwLock::new(lock),
54            }),
55        }
56    }
57}
58
59pub struct RcuReadGuard<T: ?Sized> {
60    value: Arc<T>,
61}
62
63impl<T: ?Sized> std::ops::Deref for RcuReadGuard<T> {
64    type Target = T;
65    fn deref(&self) -> &Self::Target {
66        self.value.deref()
67    }
68}
69
70pub struct RcuWriteGuard<'a, T: ?Sized> {
71    lock: &'a RwLock<Arc<T>>,
72    writer: Option<Box<T>>,
73}
74
75impl<'a, T: ?Sized> std::ops::Deref for RcuWriteGuard<'a, T> {
76    type Target = T;
77    fn deref(&self) -> &Self::Target {
78        self.writer.as_deref().expect("Cannot deref after drop")
79    }
80}
81
82impl<'a, T: ?Sized> std::ops::DerefMut for RcuWriteGuard<'a, T> {
83    fn deref_mut(&mut self) -> &mut Self::Target {
84        self.writer.as_deref_mut().expect("Cannot deref after drop")
85    }
86}
87
88impl<'a, T: ?Sized> Drop for RcuWriteGuard<'a, T> {
89    fn drop(&mut self) {
90        if let Some(value) = self.writer.take() {
91            *self.lock.write() = value.into();
92        }
93    }
94}