wait_list/
lock.rs

1//! Traits for locks that can be used inside a [`WaitList`](crate::WaitList).
2
3/// Associated types of a [`Lock`] with a specific lifetime applied.
4pub trait Lifetime<'this, ImplicitBounds: bounds::Sealed = bounds::Bounds<&'this Self>> {
5    /// A RAII exclusive guard on the lock; when this type is dropped, the lock must unlock.
6    type ExclusiveGuard;
7
8    /// A RAII shared guard on the lock; when this type is dropped, the lock must unlock.
9    type SharedGuard;
10}
11
12/// A lock.
13///
14/// # Safety
15///
16/// This lock must uphold XOR mutability: at any give time either one exclusive guard or
17/// multiple shared guards can be handed out.
18///
19/// Note that the shared implementation does not actually have to be shared; it is just an
20/// optimization for implementations that support it.
21pub unsafe trait Lock: for<'this> Lifetime<'this> {
22    /// Acquire an exclusive lock.
23    ///
24    /// When called recursively, this function must panic, abort or deadlock.
25    ///
26    /// If the previous guard was dropped during a panic, this function may or may not panic.
27    fn lock_exclusive(&self) -> <Self as Lifetime<'_>>::ExclusiveGuard;
28
29    /// Acquire a shared lock.
30    ///
31    /// When called recursively, this function may succeed, panic, abort or deadlock.
32    ///
33    /// If the previous guard was dropped during a panic, this function may or may not panic.
34    fn lock_shared(&self) -> <Self as Lifetime<'_>>::SharedGuard;
35}
36
37macro_rules! impl_for_wrapper {
38    ($($t:ty),*) => { $(
39        impl<'this, L: Lock> Lifetime<'this> for $t {
40            type ExclusiveGuard = <L as Lifetime<'this>>::ExclusiveGuard;
41            type SharedGuard = <L as Lifetime<'this>>::SharedGuard;
42        }
43        unsafe impl<L: Lock> Lock for $t {
44            fn lock_exclusive(&self) -> <Self as Lifetime<'_>>::ExclusiveGuard {
45                (**self).lock_exclusive()
46            }
47            fn lock_shared(&self) -> <Self as Lifetime<'_>>::SharedGuard {
48                (**self).lock_shared()
49            }
50        }
51    )* };
52}
53impl_for_wrapper!(&L, &mut L);
54
55#[cfg(feature = "alloc")]
56impl_for_wrapper!(alloc::boxed::Box<L>, alloc::rc::Rc<L>, alloc::sync::Arc<L>);
57
58/// [`Local`] provides a thread-local exclusive-only lock — like [`RefCell`], but it can be smaller
59/// and it lacks read support.
60///
61/// [`RefCell`]: core::cell::RefCell
62pub mod local {
63    use crate::lock;
64    use crate::lock::Lock;
65    use core::cell::Cell;
66    use core::cell::UnsafeCell;
67    use core::ops::Deref;
68    use core::ops::DerefMut;
69
70    /// A thread-local implementation of [`Lock`].
71    ///
72    /// This type is very similar to [`core::cell::RefCell`] but because it only supports
73    /// exclusive locking it can be smaller.
74    #[derive(Debug)]
75    pub struct Local<T> {
76        locked: Cell<bool>,
77        data: UnsafeCell<T>,
78    }
79
80    impl<T> Local<T> {
81        /// Create a new local lock around a value.
82        #[must_use]
83        pub const fn new(value: T) -> Self {
84            Self {
85                locked: Cell::new(false),
86                data: UnsafeCell::new(value),
87            }
88        }
89
90        /// Get a unique reference to the inner value from a unique reference to the lock.
91        #[must_use]
92        pub fn get_mut(&mut self) -> &mut T {
93            self.data.get_mut()
94        }
95
96        /// Consume this lock, returning the inner data.
97        #[must_use]
98        pub fn into_inner(self) -> T {
99            self.data.into_inner()
100        }
101
102        /// Check whether the lock is currently locked.
103        #[must_use]
104        pub fn is_locked(&self) -> bool {
105            self.locked.get()
106        }
107    }
108
109    impl<T: Default> Default for Local<T> {
110        fn default() -> Self {
111            Self::new(T::default())
112        }
113    }
114
115    impl<T> From<T> for Local<T> {
116        fn from(value: T) -> Self {
117            Self::new(value)
118        }
119    }
120
121    impl<'this, T> lock::Lifetime<'this> for Local<T> {
122        type ExclusiveGuard = Guard<'this, T>;
123        type SharedGuard = Guard<'this, T>;
124    }
125    unsafe impl<T> Lock for Local<T> {
126        #[track_caller]
127        fn lock_exclusive(&self) -> <Self as lock::Lifetime<'_>>::ExclusiveGuard {
128            assert!(!self.is_locked(), "Attempted to recursively lock `Local`");
129            self.locked.set(true);
130            Guard { lock: self }
131        }
132        fn lock_shared(&self) -> <Self as lock::Lifetime<'_>>::SharedGuard {
133            self.lock_exclusive()
134        }
135    }
136
137    /// The lock guard for [`Local`].
138    ///
139    /// Because this lock type only supports exclusive locking, the same guard type is used for
140    /// both exclusive and shared guards.
141    #[derive(Debug)]
142    pub struct Guard<'lock, T> {
143        lock: &'lock Local<T>,
144    }
145
146    impl<T> Deref for Guard<'_, T> {
147        type Target = T;
148        fn deref(&self) -> &Self::Target {
149            unsafe { &*self.lock.data.get() }
150        }
151    }
152    impl<T> DerefMut for Guard<'_, T> {
153        fn deref_mut(&mut self) -> &mut Self::Target {
154            unsafe { &mut *self.lock.data.get() }
155        }
156    }
157
158    impl<T> Drop for Guard<'_, T> {
159        fn drop(&mut self) {
160            debug_assert!(self.lock.is_locked());
161            self.lock.locked.set(false);
162        }
163    }
164}
165#[doc(no_inline)]
166pub use local::Local;
167
168mod ref_cell {
169    use crate::lock;
170    use crate::lock::Lock;
171    use core::cell;
172    use core::cell::RefCell;
173
174    impl<'this, T> lock::Lifetime<'this> for RefCell<T> {
175        type ExclusiveGuard = cell::RefMut<'this, T>;
176        type SharedGuard = cell::Ref<'this, T>;
177    }
178    unsafe impl<T> Lock for RefCell<T> {
179        fn lock_exclusive(&self) -> <Self as lock::Lifetime<'_>>::ExclusiveGuard {
180            self.borrow_mut()
181        }
182        fn lock_shared(&self) -> <Self as lock::Lifetime<'_>>::SharedGuard {
183            self.borrow()
184        }
185    }
186}
187
188#[cfg(feature = "std")]
189mod std {
190    use crate::lock;
191    use crate::lock::Lock;
192    use std::sync::Mutex;
193    use std::sync::MutexGuard;
194    use std::sync::RwLock;
195    use std::sync::RwLockReadGuard;
196    use std::sync::RwLockWriteGuard;
197
198    #[cfg_attr(doc_nightly, doc(cfg(feature = "std")))]
199    impl<'this, T> lock::Lifetime<'this> for Mutex<T> {
200        type ExclusiveGuard = MutexGuard<'this, T>;
201        type SharedGuard = MutexGuard<'this, T>;
202    }
203    #[cfg_attr(doc_nightly, doc(cfg(feature = "std")))]
204    unsafe impl<T> Lock for Mutex<T> {
205        fn lock_exclusive(&self) -> <Self as lock::Lifetime<'_>>::ExclusiveGuard {
206            self.lock().unwrap()
207        }
208        fn lock_shared(&self) -> <Self as lock::Lifetime<'_>>::SharedGuard {
209            self.lock_exclusive()
210        }
211    }
212
213    #[cfg_attr(doc_nightly, doc(cfg(feature = "std")))]
214    impl<'this, T> lock::Lifetime<'this> for RwLock<T> {
215        type ExclusiveGuard = RwLockWriteGuard<'this, T>;
216        type SharedGuard = RwLockReadGuard<'this, T>;
217    }
218    #[cfg_attr(doc_nightly, doc(cfg(feature = "std")))]
219    unsafe impl<T> Lock for RwLock<T> {
220        fn lock_exclusive(&self) -> <Self as lock::Lifetime<'_>>::ExclusiveGuard {
221            self.write().unwrap()
222        }
223        fn lock_shared(&self) -> <Self as lock::Lifetime<'_>>::SharedGuard {
224            self.read().unwrap()
225        }
226    }
227}
228
229#[cfg(feature = "lock_api_04")]
230mod lock_api_04 {
231    use crate::lock;
232    use crate::lock::Lock;
233    use lock_api_04::Mutex;
234    use lock_api_04::MutexGuard;
235    use lock_api_04::RawMutex;
236    use lock_api_04::RawRwLock;
237    use lock_api_04::RwLock;
238    use lock_api_04::RwLockReadGuard;
239    use lock_api_04::RwLockWriteGuard;
240
241    #[cfg_attr(doc_nightly, doc(cfg(feature = "lock_api_04")))]
242    impl<'this, R: RawMutex, T> lock::Lifetime<'this> for Mutex<R, T> {
243        type ExclusiveGuard = MutexGuard<'this, R, T>;
244        type SharedGuard = MutexGuard<'this, R, T>;
245    }
246    #[cfg_attr(doc_nightly, doc(cfg(feature = "lock_api_04")))]
247    unsafe impl<R: RawMutex, T> Lock for Mutex<R, T> {
248        fn lock_exclusive(&self) -> <Self as lock::Lifetime<'_>>::ExclusiveGuard {
249            self.lock()
250        }
251        fn lock_shared(&self) -> <Self as lock::Lifetime<'_>>::SharedGuard {
252            self.lock_exclusive()
253        }
254    }
255
256    #[cfg_attr(doc_nightly, doc(cfg(feature = "lock_api_04")))]
257    impl<'this, R: RawRwLock, T> lock::Lifetime<'this> for RwLock<R, T> {
258        type ExclusiveGuard = RwLockWriteGuard<'this, R, T>;
259        type SharedGuard = RwLockReadGuard<'this, R, T>;
260    }
261    #[cfg_attr(doc_nightly, doc(cfg(feature = "lock_api_04")))]
262    unsafe impl<R: RawRwLock, T> Lock for RwLock<R, T> {
263        fn lock_exclusive(&self) -> <Self as lock::Lifetime<'_>>::ExclusiveGuard {
264            self.write()
265        }
266        fn lock_shared(&self) -> <Self as lock::Lifetime<'_>>::SharedGuard {
267            self.read()
268        }
269    }
270}
271
272#[cfg(feature = "loom_05")]
273mod loom_05 {
274    use crate::lock;
275    use crate::lock::Lock;
276    use loom_05_crate::sync::Mutex;
277    use loom_05_crate::sync::MutexGuard;
278    use loom_05_crate::sync::RwLock;
279    use loom_05_crate::sync::RwLockReadGuard;
280    use loom_05_crate::sync::RwLockWriteGuard;
281
282    #[cfg_attr(doc_nightly, doc(cfg(feature = "loom")))]
283    impl<'this, T> lock::Lifetime<'this> for Mutex<T> {
284        type ExclusiveGuard = MutexGuard<'this, T>;
285        type SharedGuard = MutexGuard<'this, T>;
286    }
287    #[cfg_attr(doc_nightly, doc(cfg(feature = "loom")))]
288    unsafe impl<T> Lock for Mutex<T> {
289        fn lock_exclusive(&self) -> <Self as lock::Lifetime<'_>>::ExclusiveGuard {
290            self.lock().unwrap()
291        }
292        fn lock_shared(&self) -> <Self as lock::Lifetime<'_>>::SharedGuard {
293            self.lock_exclusive()
294        }
295    }
296
297    #[cfg_attr(doc_nightly, doc(cfg(feature = "loom")))]
298    impl<'this, T> lock::Lifetime<'this> for RwLock<T> {
299        type ExclusiveGuard = RwLockWriteGuard<'this, T>;
300        type SharedGuard = RwLockReadGuard<'this, T>;
301    }
302    #[cfg_attr(doc_nightly, doc(cfg(feature = "loom")))]
303    unsafe impl<T> Lock for RwLock<T> {
304        fn lock_exclusive(&self) -> <Self as lock::Lifetime<'_>>::ExclusiveGuard {
305            self.write().unwrap()
306        }
307        fn lock_shared(&self) -> <Self as lock::Lifetime<'_>>::SharedGuard {
308            self.read().unwrap()
309        }
310    }
311}
312
313mod bounds {
314    #[allow(missing_debug_implementations)]
315    pub struct Bounds<T>(T);
316    pub trait Sealed {}
317    impl<T> Sealed for Bounds<T> {}
318}