1use parking_lot::RwLock;
2use std::{fmt::Debug, sync::Arc};
3
4pub 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 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 pub fn read(&self) -> RcuReadGuard<T> {
31 RcuReadGuard {
32 value: self.lock.read().clone(),
33 }
34 }
35
36 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}