1#![deny(warnings)]
2#![cfg_attr(not(feature = "std"), no_std)]
3
4#[cfg(not(feature = "std"))]
41extern crate alloc;
42#[cfg(feature = "std")]
43use std as alloc;
44
45use alloc::sync::*;
46use core::fmt;
47use core::ops::*;
48use core::sync::atomic::*;
49
50pub struct ScopedReference<'a, T: ?Sized> {
53 reference: Result<&'a T, &'a mut T>,
54 alive: Arc<AtomicUsize>,
55}
56
57impl<'a, T: ?Sized> ScopedReference<'a, T> {
58 pub fn new(reference: &'a T) -> Self {
60 let alive = Arc::new(AtomicUsize::new(0));
61 let reference = Ok(reference);
62 Self { reference, alive }
63 }
64
65 pub fn new_mut(reference: &'a mut T) -> Self {
67 let alive = Arc::new(AtomicUsize::new(0));
68 let reference = Err(reference);
69 Self { reference, alive }
70 }
71
72 pub fn borrow(&self) -> ScopedBorrow<T> {
74 match &self.reference {
75 Ok(r) => {
76 self.alive.fetch_add(1, Ordering::Release);
77 ScopedBorrow {
78 pointer: *r as *const T,
79 alive: self.alive.clone(),
80 }
81 }
82 Err(r) => {
83 if self.alive.load(Ordering::Acquire) == usize::MAX {
84 panic_abort(
85 "Cannot borrow a lifetime mutably while it is already borrowed immutably.",
86 );
87 } else {
88 self.alive.fetch_add(1, Ordering::Release);
89 ScopedBorrow {
90 pointer: *r as *const T,
91 alive: self.alive.clone(),
92 }
93 }
94 }
95 }
96 }
97
98 pub fn borrow_mut(&mut self) -> ScopedBorrowMut<T> {
100 if self.alive.load(Ordering::Acquire) != 0 {
101 panic_abort("Scoped lifetime is already borrowed.")
102 } else {
103 self.alive.store(usize::MAX, Ordering::Release);
104 ScopedBorrowMut {
105 pointer: unsafe {
106 self.reference
107 .as_mut()
108 .map_err(|x| *x as *mut T)
109 .unwrap_err_unchecked()
110 },
111 alive: self.alive.clone(),
112 }
113 }
114 }
115}
116
117impl<'a, T: ?Sized> fmt::Debug for ScopedReference<'a, T> {
118 fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
119 Ok(())
120 }
121}
122
123impl<'a, T: ?Sized> fmt::Display for ScopedReference<'a, T> {
124 fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
125 Ok(())
126 }
127}
128
129impl<'a, T: ?Sized> Drop for ScopedReference<'a, T> {
130 fn drop(&mut self) {
131 if self.alive.load(Ordering::Acquire) != 0 {
132 panic_abort("Scoped lifetime was dropped while a borrow was out.")
133 }
134 }
135}
136
137pub struct ScopedBorrow<T: ?Sized> {
139 pointer: *const T,
140 alive: Arc<AtomicUsize>,
141}
142
143impl<T: ?Sized> Deref for ScopedBorrow<T> {
144 type Target = T;
145
146 fn deref(&self) -> &Self::Target {
147 unsafe { &*self.pointer }
148 }
149}
150
151impl<T: ?Sized> Drop for ScopedBorrow<T> {
152 fn drop(&mut self) {
153 self.alive.fetch_sub(1, Ordering::Release);
154 }
155}
156
157impl<T: ?Sized> Clone for ScopedBorrow<T> {
158 fn clone(&self) -> Self {
159 self.alive.fetch_add(1, Ordering::Release);
160 Self {
161 pointer: self.pointer,
162 alive: self.alive.clone(),
163 }
164 }
165}
166
167impl<T: fmt::Debug + ?Sized> fmt::Debug for ScopedBorrow<T> {
168 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169 fmt::Debug::fmt(&**self, f)
170 }
171}
172
173impl<T: fmt::Display + ?Sized> fmt::Display for ScopedBorrow<T> {
174 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
175 fmt::Display::fmt(&**self, f)
176 }
177}
178
179unsafe impl<T: ?Sized + Send> Send for ScopedBorrow<T> {}
180unsafe impl<T: ?Sized + Sync> Sync for ScopedBorrow<T> {}
181
182pub struct ScopedBorrowMut<T: ?Sized> {
184 pointer: *mut T,
185 alive: Arc<AtomicUsize>,
186}
187
188impl<T: ?Sized> Deref for ScopedBorrowMut<T> {
189 type Target = T;
190
191 fn deref(&self) -> &Self::Target {
192 unsafe { &*self.pointer }
193 }
194}
195
196impl<T: ?Sized> DerefMut for ScopedBorrowMut<T> {
197 fn deref_mut(&mut self) -> &mut Self::Target {
198 unsafe { &mut *self.pointer }
199 }
200}
201
202impl<T: ?Sized> Drop for ScopedBorrowMut<T> {
203 fn drop(&mut self) {
204 self.alive.store(0, Ordering::Release);
205 }
206}
207
208impl<T: fmt::Debug + ?Sized> fmt::Debug for ScopedBorrowMut<T> {
209 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210 fmt::Debug::fmt(&**self, f)
211 }
212}
213
214impl<T: fmt::Display + ?Sized> fmt::Display for ScopedBorrowMut<T> {
215 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
216 fmt::Display::fmt(&**self, f)
217 }
218}
219
220unsafe impl<T: ?Sized + Send> Send for ScopedBorrowMut<T> {}
221unsafe impl<T: ?Sized + Sync> Sync for ScopedBorrowMut<T> {}
222
223#[allow(unreachable_code)]
224fn panic_abort(error: &str) -> ! {
225 #[cfg(panic = "abort")]
226 {
227 panic!("{error}");
228 }
229 #[cfg(all(not(panic = "abort"), feature = "std"))]
230 {
231 println!("{error}");
232 std::process::abort();
233 }
234 #[cfg(all(not(panic = "abort"), not(feature = "std")))]
235 {
236 struct Abort;
237
238 impl Drop for Abort {
240 fn drop(&mut self) {
241 panic!();
242 }
243 }
244
245 #[allow(unused_variables)]
246 let abort = Abort;
247
248 panic!("{error}");
249
250 core::mem::forget(abort);
251 }
252}
253
254#[cfg(test)]
255mod tests {
256 use super::*;
257
258 struct StaticBorrow(ScopedBorrow<i32>);
259
260 #[test]
261 fn test_borrow_mut() {
262 let mut x = 10;
263 let borrowed_x = &mut x;
264 let mut scoped_ref = ScopedReference::new_mut(borrowed_x);
265
266 let mut mut_ref_to_x = scoped_ref.borrow_mut();
267 *mut_ref_to_x = 9;
268
269 drop(mut_ref_to_x);
273
274 let static_borrow = StaticBorrow(scoped_ref.borrow());
275 assert_eq!(*static_borrow.0, 9);
276
277 drop(static_borrow);
281 drop(scoped_ref);
282 }
283}