1#[cfg(doc)]
3use crate::{FIFO, LIFO, queue::*};
4use crate::{
5 Priority, RwLock,
6 queue::{PriorityQueue, PriorityQueueHandle},
7 waiter::{self, Waiter, WaiterFlagFut},
8};
9use core::{
10 cell::UnsafeCell,
11 fmt::{Debug, Display},
12 format_args,
13 marker::PhantomData,
14 mem::ManuallyDrop,
15 ops::{Deref, DerefMut},
16};
17
18#[cfg(feature = "const-default")]
19use const_default::ConstDefault;
20
21impl<'a, P: Priority, T: ?Sized, Q: MutexQueue<P>> waiter::WaiterHandle
22 for MutexGuard<'a, P, T, Q>
23{
24 #[inline]
25 fn with_waker<R>(&self, f: impl FnOnce(&Waiter) -> R) -> R {
26 if Self::HAS_PURE_LOAD {
29 unsafe { f(&Q::Handle::LOAD_PURE.unwrap_unchecked()(&self.node).waiter) }
30 } else {
31 let queue = self.mutex.queue.read();
32
33 f(&queue.get_by_handle(&self.node).waiter)
34 }
35 }
36}
37
38#[derive(Debug)]
39pub struct MutexWaiter<P: Priority> {
43 priority: P,
44 waiter: Waiter,
45}
46
47impl<P: Priority> Priority for MutexWaiter<P> {
49 #[inline]
50 fn compare(&self, other: &Self) -> core::cmp::Ordering {
51 self.priority.compare(&other.priority)
52 }
53
54 #[inline]
55 fn compare_new(&self, old: &Self) -> std::cmp::Ordering {
56 if old.waiter.has_lock() {
57 return core::cmp::Ordering::Less;
58 }
59
60 self.priority.compare_new(&old.priority)
61 }
62}
63
64impl<P: Priority> MutexWaiter<P> {
65 #[inline]
66 const fn new<'a>(holder: P, has_lock: bool) -> Self {
67 Self {
68 priority: holder,
69 waiter: Waiter::new(has_lock),
70 }
71 }
72}
73
74#[cfg(all(feature = "arena-queue", target_pointer_width = "64"))]
75type DefaultMutexQueue_<P> = crate::queue::SingleLinkArenaQueue<MutexWaiter<P>>;
76
77#[cfg(all(not(feature = "arena-queue"), feature = "box-queue"))]
78type DefaultMutexQueue_<P> = crate::queue::DualLinkBoxQueue<MutexWaiter<P>>;
79
80#[cfg(any(feature = "arena-queue", feature = "box-queue"))]
94pub type DefaultMutexQueue<P> = DefaultMutexQueue_<P>;
95
96pub struct Mutex<
137 P: Priority,
138 T: ?Sized,
139 #[cfg(any(feature = "box-queue", feature = "arena-queue"))] Q: MutexQueue<P> = DefaultMutexQueue<P>,
140 #[cfg(not(any(feature = "box-queue", feature = "arena-queue")))] Q: MutexQueue<P>,
141> {
142 queue: RwLock<Q>,
143 _phantom: PhantomData<P>,
144 data: UnsafeCell<T>,
145}
146
147impl<P: Priority, T: Default, Q: MutexQueue<P>> Default for Mutex<P, T, Q> {
148 fn default() -> Self {
149 Self {
150 queue: Default::default(),
151 data: Default::default(),
152 _phantom: Default::default(),
153 }
154 }
155}
156
157unsafe impl<P: Priority, T: ?Sized + Send, Q: Send + Sync + MutexQueue<P>> Sync for Mutex<P, T, Q> {}
164unsafe impl<P: Priority, T: ?Sized + Send, Q: Send + MutexQueue<P>> Send for Mutex<P, T, Q> {}
165impl<P: Priority, T: ?Sized + Unpin, Q: Unpin + MutexQueue<P>> Unpin for Mutex<P, T, Q> {}
166
167pub trait MutexQueue<P: Priority>: PriorityQueue<MutexWaiter<P>> {}
169impl<P: Priority, Q: PriorityQueue<MutexWaiter<P>>> MutexQueue<P> for Q {}
170
171#[cfg(feature = "serde")]
172impl<'de, P: Priority, T, Q: MutexQueue<P>> serde::Deserialize<'de> for Mutex<P, T, Q>
173where
174 T: serde::Deserialize<'de>,
175{
176 #[inline]
177 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
178 where
179 D: serde::Deserializer<'de>,
180 {
181 Ok(Self::new(T::deserialize(deserializer)?))
183 }
184}
185
186pub struct MutexGuard<'a, P: Priority, T: ?Sized, Q: MutexQueue<P>> {
191 mutex: &'a Mutex<P, T, Q>,
192 node: ManuallyDrop<Q::Handle>,
193}
194
195unsafe impl<'a, P: Priority, T: ?Sized + Sync, Q: MutexQueue<P>> Sync for MutexGuard<'a, P, T, Q> where
196 Mutex<P, T, Q>: Sync
197{
198}
199unsafe impl<'a, P: Priority, T: ?Sized + Send, Q: MutexQueue<P>> Send for MutexGuard<'a, P, T, Q>
200where
201 Mutex<P, T, Q>: Sync,
202 Q::Handle: Send,
203{
204}
205
206impl<'a, P: Priority, T: ?Sized, Q: MutexQueue<P>> Display for MutexGuard<'a, P, T, Q>
207where
208 T: Display,
209{
210 #[inline]
211 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
212 self.deref().fmt(f)
213 }
214}
215
216impl<'a, P: Priority, T: ?Sized, Q: MutexQueue<P>> Debug for MutexGuard<'a, P, T, Q>
217where
218 T: Debug,
219{
220 #[inline]
221 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
222 self.deref().fmt(f)
223 }
224}
225
226impl<'a, P: Priority, T: ?Sized, Q: MutexQueue<P>> Deref for MutexGuard<'a, P, T, Q> {
227 type Target = T;
228
229 #[inline]
230 fn deref(&self) -> &Self::Target {
231 unsafe { &*self.mutex.data.get() }
232 }
233}
234
235impl<'a, P: Priority, T: ?Sized, Q: MutexQueue<P>> DerefMut for MutexGuard<'a, P, T, Q> {
236 #[inline]
237 fn deref_mut(&mut self) -> &mut Self::Target {
238 unsafe { &mut *self.mutex.data.get() }
239 }
240}
241
242impl<'a, P: Priority, T: ?Sized, Q: MutexQueue<P>> MutexGuard<'a, P, T, Q> {
243 #[inline]
251 #[cfg(feature = "evict")]
252 pub fn evicted(this: &mut Self) -> impl Future<Output = ()> {
253 waiter::VoidFut(WaiterFlagFut::<_, { waiter::WAITER_FLAG_WANTS_EVICT }>::new(this))
254 }
255
256 const HAS_PURE_LOAD: bool = Q::Handle::LOAD_PURE.is_some();
257}
258
259impl<'a, P: Priority, T: ?Sized, Q: MutexQueue<P>> Drop for MutexGuard<'a, P, T, Q> {
260 #[inline]
261 fn drop(&mut self) {
262 let mut queue = self.mutex.queue.write();
263
264 let was_head = queue.get_by_handle(&self.node).waiter.has_lock();
265 queue.dequeue(unsafe { ManuallyDrop::take(&mut self.node) });
266
267 if was_head {
271 if let Some(handle) = queue.head() {
272 handle.waiter.start();
273 }
274 }
275 }
276}
277
278#[derive(Debug, Default, Clone, Copy)]
280pub struct TryLockError;
281
282impl Display for TryLockError {
283 #[inline]
284 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
285 write!(f, "lock is already held")
286 }
287}
288
289impl core::error::Error for TryLockError {}
290
291impl<P: Priority, T: ?Sized, Q: MutexQueue<P>> Debug for Mutex<P, T, Q>
292where
293 T: Debug,
294 P: Default,
295{
296 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
297 let mut d = f.debug_tuple("Mutex");
298 match self.try_lock(P::default()) {
299 Ok(data) => d.field(&data.deref()),
300 Err(_) => d.field(&format_args!("<locked>")),
301 };
302
303 d.finish()
304 }
305}
306
307impl<P: Priority, T: ?Sized, Q: MutexQueue<P>> Mutex<P, T, Q> {
308 pub fn try_lock(
315 &self,
316 priority: impl Into<P>,
317 ) -> Result<MutexGuard<'_, P, T, Q>, TryLockError> {
318 let priority = priority.into();
319 let mut queue = self.queue.write();
320
321 if !queue.is_empty() {
322 return Err(TryLockError);
323 }
324
325 let node = MutexWaiter::new(priority, true);
326 let handle = queue.enqueue(node);
327
328 Ok(MutexGuard {
329 mutex: self,
330 node: ManuallyDrop::new(handle),
331 })
332 }
333
334 pub async fn lock(&self, priority: P) -> MutexGuard<'_, P, T, Q> {
344 let priority = priority.into();
345 let guard = {
346 let mut queue = self.queue.write();
347
348 let maybe_head = queue.head();
349 if maybe_head.is_none() {
350 let handle = queue.enqueue(MutexWaiter::new(priority, true));
351
352 return MutexGuard {
353 mutex: self,
354 node: ManuallyDrop::new(handle),
355 };
356 }
357
358 #[cfg(feature = "evict")]
359 {
360 let head = maybe_head.unwrap();
361
362 if priority.compare(&maybe_head.unwrap().priority).is_gt() {
363 head.waiter.evict();
364 }
365 }
366
367 let handle = queue.enqueue(MutexWaiter::new(priority, false));
368
369 MutexGuard {
370 mutex: self,
371 node: ManuallyDrop::new(handle),
372 }
373 };
374
375 WaiterFlagFut::<_, { waiter::WAITER_FLAG_HAS_LOCK }>::new(&guard).await;
376
377 guard
378 }
379
380 pub fn lock_from(
387 &self,
388 priority: impl Into<P>,
389 ) -> impl Future<Output = MutexGuard<'_, P, T, Q>> {
390 self.lock(priority.into())
391 }
392
393 pub fn lock_default(&self) -> impl Future<Output = MutexGuard<'_, P, T, Q>>
400 where
401 P: Default,
402 {
403 self.lock(Default::default())
404 }
405
406 #[inline]
407 pub fn new(val: T) -> Self
409 where
410 T: Sized,
411 {
412 Self {
413 queue: Default::default(),
414 data: UnsafeCell::new(val),
415 _phantom: PhantomData,
416 }
417 }
418
419 #[cfg(feature = "const-default")]
425 pub const fn const_new(val: T) -> Self
426 where
427 Q: const_default::ConstDefault,
428 T: Sized,
429 {
430 Self {
431 queue: RwLock::new(Q::DEFAULT),
432 data: UnsafeCell::new(val),
433 _phantom: PhantomData,
434 }
435 }
436}
437
438#[cfg(feature = "const-default")]
439impl<P: Priority, T: ConstDefault, Q: ConstDefault + MutexQueue<P>> ConstDefault
440 for Mutex<P, T, Q>
441{
442 const DEFAULT: Self = Self::const_new(T::DEFAULT);
443}