1#![doc = include_str!("../README.md")]
2#![no_std]
3
4extern crate alloc;
5
6mod link;
7mod rcu_cell;
8mod rcu_weak;
9
10pub use rcu_cell::RcuCell;
11pub use rcu_weak::RcuWeak;
12
13const _: () = assert!(usize::MAX.count_ones() == 64);
15const _: () = assert!(core::mem::size_of::<*const ()>() == 8);
16
17use alloc::sync::Arc;
18
19pub trait ArcPointer<T> {
20 fn as_ptr(&self) -> *const T;
21 fn into_raw(self) -> *const T;
22 unsafe fn from_raw(ptr: *const T) -> Self;
25}
26
27impl<T> ArcPointer<T> for Option<Arc<T>> {
28 fn as_ptr(&self) -> *const T {
29 match self {
30 Some(v) => Arc::as_ptr(v),
31 None => core::ptr::null(),
32 }
33 }
34
35 fn into_raw(self) -> *const T {
36 match self {
37 Some(v) => Arc::into_raw(v),
38 None => core::ptr::null(),
39 }
40 }
41
42 unsafe fn from_raw(ptr: *const T) -> Self {
43 (!ptr.is_null()).then(|| Arc::from_raw(ptr))
44 }
45}
46
47#[cfg(test)]
48mod test {
49 use super::RcuCell;
50 use alloc::sync::Arc;
51 use core::sync::atomic::{AtomicUsize, Ordering};
52
53 #[test]
54 fn test_default() {
55 let x = RcuCell::<u32>::default();
56 assert!(x.read().is_none());
57 }
58
59 #[test]
60 fn simple_drop() {
61 static REF: AtomicUsize = AtomicUsize::new(0);
62 struct Foo(usize);
63 impl Foo {
64 fn new(data: usize) -> Self {
65 REF.fetch_add(data, Ordering::Relaxed);
66 Foo(data)
67 }
68 }
69 impl Drop for Foo {
70 fn drop(&mut self) {
71 REF.fetch_sub(self.0, Ordering::Relaxed);
72 }
73 }
74 let a = RcuCell::new(Foo::new(10));
75 let b = a.read().unwrap();
76 assert_eq!(REF.load(Ordering::Relaxed), 10);
77 drop(b);
78 assert_eq!(REF.load(Ordering::Relaxed), 10);
79 drop(a);
80 assert_eq!(REF.load(Ordering::Relaxed), 0);
81 }
82
83 #[test]
84 fn single_thread() {
85 let t = RcuCell::new(Some(10));
86 let x = t.read();
87 let y = t.read();
88 t.take();
89 let z = t.read();
90 let a = z.clone();
91 drop(t); assert_eq!(x.map(|v| *v), Some(10));
93 assert_eq!(y.map(|v| *v), Some(10));
94 assert_eq!(z.map(|v| *v), None);
95 assert_eq!(a.map(|v| *v), None);
96 }
97
98 #[test]
99 fn single_thread_clone() {
100 let t = Arc::new(RcuCell::new(Some(10)));
101 let t1 = t.clone();
102 assert_eq!(t1.read().map(|v| *v), Some(10));
103 t1.write(5);
104 assert_eq!(t.read().map(|v| *v), Some(5));
105 }
106
107 #[test]
108 fn test_rcu_update() {
109 let t = RcuCell::new(Some(10));
110 let old = t.update(|v| v.map(|x| *x + 1));
111 assert_eq!(t.read().map(|v| *v), Some(11));
112 assert_eq!(old.map(|v| *v), Some(10));
113 let old = t.update(|v| match v {
114 Some(x) if *x == 11 => None,
115 _ => Some(42),
116 });
117 assert!(t.read().is_none());
118 assert_eq!(old.map(|v| *v), Some(11));
119 }
120
121 #[test]
122 fn test_is_none() {
123 let t = RcuCell::new(10);
124 assert!(!t.is_none());
125 t.take();
126 assert!(t.is_none());
127 }
128
129 #[test]
130 fn test_clone_rcu_cell() {
131 let t = Arc::new(RcuCell::new(Some(10)));
132 let t1 = t.clone();
133 let t2 = t.clone();
134 let t3 = t.clone();
135 t1.write(11);
136 drop(t1);
137 assert_eq!(t.read().map(|v| *v), Some(11));
138 t2.write(12);
139 drop(t2);
140 assert_eq!(t.read().map(|v| *v), Some(12));
141 t3.write(13);
142 drop(t3);
143 assert_eq!(t.read().map(|v| *v), Some(13));
144 }
145
146 #[test]
147 fn test_rcu_reader() {
148 let t = Arc::new(RcuCell::new(10));
149 let t1 = t.clone();
150 let t2 = t.clone();
151 let t3 = t.clone();
152 let d1 = t1.read().unwrap();
153 let d3 = t3.read().unwrap();
154 t1.write(11);
155 let d2 = t2.read().unwrap();
156 assert_ne!(d1, d2);
157 assert_eq!(d1, d3);
158 assert_ne!(d2, d3);
159 }
160
161 #[test]
162 fn test_rcu_take() {
163 let t = Arc::new(RcuCell::new(10));
164 let t1 = t.clone();
165 let t2 = t.clone();
166 let d1 = t1.take().unwrap();
167 assert_eq!(*d1, 10);
168 assert_eq!(t1.read(), None);
169 let d2 = t2.write(42);
170 assert!(d2.is_none());
171 let d3 = t2.read().unwrap();
172 assert_eq!(*d3, 42);
173 }
174
175 #[test]
176 fn test_arc_eq() {
177 let t = RcuCell::new(10);
178 let v = t.read().unwrap();
179 assert!(t.arc_eq(&v));
180 t.write(11);
181 assert!(!t.arc_eq(&v));
182 let t1 = RcuCell::from(v.clone());
183 assert!(t1.arc_eq(&v));
184 let v2 = t.write(v);
185 let t2 = RcuCell::from(v2.clone());
186 assert!(RcuCell::ptr_eq(&t, &t1));
187 assert!(t2.arc_eq(v2.as_ref().unwrap()));
188 }
189
190 #[test]
191 fn cas_test() {
192 use super::ArcPointer;
193 use Ordering::SeqCst;
194
195 let a = RcuCell::new(1234);
196
197 let curr = a.read().as_ptr();
198 let res1 = unsafe { a.compare_exchange(curr, None, SeqCst, SeqCst) }.unwrap();
199 assert_eq!(res1, curr);
200 assert!(a.is_none());
201 let res2 = unsafe { a.compare_exchange(res1, Some(&Arc::new(5678)), SeqCst, SeqCst) };
202 assert!(res2.is_err());
203
204 let null = core::ptr::null();
205 let res2 = unsafe { a.compare_exchange(null, Some(&Arc::new(5678)), SeqCst, SeqCst) };
206 assert!(res2.is_ok());
207 assert_eq!(a.read().map(|v| *v), Some(5678));
208 }
209}