1#![deny(unsafe_op_in_unsafe_fn)]
2
3use std::{
6 ops::{Deref, DerefMut},
7 sync::atomic::{AtomicUsize, Ordering},
8};
9
10#[repr(transparent)]
12#[derive(Debug, Default)]
13pub struct AtomicBorrow {
14 borrow: AtomicUsize,
15}
16
17impl AtomicBorrow {
18 pub const SHARED_MASK: usize = usize::MAX >> 1;
20 pub const UNIQUE_MASK: usize = !Self::SHARED_MASK;
22
23 const SPIN_COUNT: usize = 1 << 10;
24
25 #[inline]
27 pub const fn new() -> Self {
28 Self {
29 borrow: AtomicUsize::new(0),
30 }
31 }
32
33 #[inline]
35 pub fn shared_count(&self) -> usize {
36 self.borrow.load(Ordering::Acquire) & Self::SHARED_MASK
37 }
38
39 #[inline]
41 pub fn is_unique(&self) -> bool {
42 self.borrow.load(Ordering::Acquire) & Self::UNIQUE_MASK == 0
43 }
44
45 #[inline]
47 pub fn is_borrowed(&self) -> bool {
48 self.borrow.load(Ordering::Acquire) != 0
49 }
50
51 #[inline]
55 pub fn borrow(&self) -> bool {
56 let prev = self.borrow.fetch_add(1, Ordering::Acquire);
57
58 if prev & Self::SHARED_MASK == Self::SHARED_MASK {
59 panic!("borrow counter overflowed");
60 }
61
62 if prev & Self::UNIQUE_MASK != 0 {
63 self.borrow.fetch_sub(1, Ordering::Release);
65 false
66 } else {
67 true
68 }
69 }
70
71 #[inline]
75 pub fn borrow_mut(&self) -> bool {
76 self.borrow
77 .compare_exchange(0, Self::UNIQUE_MASK, Ordering::Acquire, Ordering::Relaxed)
78 .is_ok()
79 }
80
81 #[inline]
87 pub fn release(&self) {
88 let prev = self.borrow.fetch_sub(1, Ordering::Release);
89 debug_assert_ne!(
90 prev, 0,
91 "borrow counter underflow, this means you released more times than you borrowed"
92 );
93 debug_assert_eq!(
94 prev & Self::UNIQUE_MASK,
95 0,
96 "shared release of unique borrow"
97 );
98 }
99
100 #[inline]
105 pub fn release_mut(&self) {
106 let prev = self.borrow.fetch_and(!Self::UNIQUE_MASK, Ordering::Release);
107 debug_assert_ne!(
108 prev & Self::UNIQUE_MASK,
109 0,
110 "unique release of shared borrow"
111 );
112 }
113
114 #[inline]
116 pub fn spin_borrow(&self) {
117 for _ in 0..Self::SPIN_COUNT {
118 if self.borrow() {
119 return;
120 }
121
122 std::hint::spin_loop();
123 }
124
125 while !self.borrow() {
126 std::thread::yield_now();
127 }
128 }
129
130 #[inline]
132 pub fn spin_borrow_mut(&self) {
133 for _ in 0..Self::SPIN_COUNT {
134 if self.borrow_mut() {
135 return;
136 }
137
138 std::hint::spin_loop();
139 }
140
141 while !self.borrow_mut() {
142 std::thread::yield_now();
143 }
144 }
145}
146
147pub struct SharedGuard<'a, T> {
149 data: *const T,
150 borrow: &'a AtomicBorrow,
151}
152
153impl<'a, T> SharedGuard<'a, T> {
154 #[inline]
156 pub fn new(data: &'a T, borrow: &'a AtomicBorrow) -> Self {
157 Self { data, borrow }
158 }
159
160 #[inline]
166 pub unsafe fn try_new(data: *const T, borrow: &'a AtomicBorrow) -> Option<Self> {
167 if borrow.borrow() {
168 Some(Self { data, borrow })
169 } else {
170 None
171 }
172 }
173
174 #[inline]
180 pub unsafe fn spin(data: *const T, borrow: &'a AtomicBorrow) -> Self {
181 borrow.spin_borrow();
182 Self { data, borrow }
183 }
184
185 #[inline]
187 pub fn get_borrow(&self) -> &'a AtomicBorrow {
188 self.borrow
189 }
190
191 #[inline]
193 pub fn ptr(&self) -> *const T {
194 self.data
195 }
196
197 #[inline]
199 pub fn forget(self) -> *const T {
200 let ptr = self.ptr();
201 std::mem::forget(self);
202 ptr
203 }
204}
205
206impl<'a, T> Deref for SharedGuard<'a, T> {
207 type Target = T;
208
209 #[inline]
210 fn deref(&self) -> &Self::Target {
211 unsafe { &*self.data }
212 }
213}
214
215impl<'a, T> Drop for SharedGuard<'a, T> {
216 #[inline]
217 fn drop(&mut self) {
218 self.borrow.release();
219 }
220}
221
222pub struct UniqueGuard<'a, T> {
224 data: *mut T,
225 borrow: &'a AtomicBorrow,
226}
227
228impl<'a, T> UniqueGuard<'a, T> {
229 #[inline]
231 pub fn new(data: &'a mut T, borrow: &'a AtomicBorrow) -> Self {
232 Self { data, borrow }
233 }
234
235 #[inline]
241 pub unsafe fn try_new(data: *mut T, borrow: &'a AtomicBorrow) -> Option<Self> {
242 if borrow.borrow_mut() {
243 Some(Self { data, borrow })
244 } else {
245 None
246 }
247 }
248
249 #[inline]
255 pub unsafe fn spin(data: *mut T, borrow: &'a AtomicBorrow) -> Self {
256 borrow.spin_borrow_mut();
257 Self { data, borrow }
258 }
259
260 #[inline]
262 pub fn get_borrow(&self) -> &'a AtomicBorrow {
263 self.borrow
264 }
265
266 #[inline]
268 pub fn ptr(&self) -> *mut T {
269 self.data
270 }
271
272 #[inline]
274 pub fn forget(self) -> *mut T {
275 let ptr = self.ptr();
276 std::mem::forget(self);
277 ptr
278 }
279}
280
281impl<'a, T> Deref for UniqueGuard<'a, T> {
282 type Target = T;
283
284 #[inline]
285 fn deref(&self) -> &Self::Target {
286 unsafe { &*self.data }
287 }
288}
289
290impl<'a, T> DerefMut for UniqueGuard<'a, T> {
291 #[inline]
292 fn deref_mut(&mut self) -> &mut Self::Target {
293 unsafe { &mut *self.data }
294 }
295}
296
297impl<'a, T> Drop for UniqueGuard<'a, T> {
298 #[inline]
299 fn drop(&mut self) {
300 self.borrow.release_mut();
301 }
302}
303
304#[cfg(test)]
305mod tests {
306 use super::*;
307
308 #[test]
309 fn atomic_borrow() {
310 let borrow = AtomicBorrow::new();
311
312 assert!(borrow.borrow());
313 assert!(borrow.borrow());
314
315 assert!(!borrow.borrow_mut());
316
317 borrow.release();
318 borrow.release();
319
320 assert!(borrow.borrow_mut());
321
322 assert!(!borrow.borrow());
323
324 borrow.release_mut();
325 }
326}