async_lock/mutex.rs
1use core::borrow::Borrow;
2use core::cell::UnsafeCell;
3use core::fmt;
4use core::marker::{PhantomData, PhantomPinned};
5use core::ops::{Deref, DerefMut};
6use core::pin::Pin;
7use core::task::Poll;
8
9use alloc::sync::Arc;
10
11// We don't use loom::UnsafeCell as that doesn't work with the Mutex API.
12use crate::sync::atomic::{AtomicUsize, Ordering};
13
14#[cfg(all(feature = "std", not(target_family = "wasm")))]
15use std::time::{Duration, Instant};
16
17use event_listener::{Event, EventListener};
18use event_listener_strategy::{easy_wrapper, EventListenerFuture};
19
20/// An async mutex.
21///
22/// The locking mechanism uses eventual fairness to ensure locking will be fair on average without
23/// sacrificing performance. This is done by forcing a fair lock whenever a lock operation is
24/// starved for longer than 0.5 milliseconds.
25///
26/// # Examples
27///
28/// ```
29/// # futures_lite::future::block_on(async {
30/// use async_lock::Mutex;
31///
32/// let m = Mutex::new(1);
33///
34/// let mut guard = m.lock().await;
35/// *guard = 2;
36///
37/// assert!(m.try_lock().is_none());
38/// drop(guard);
39/// assert_eq!(*m.try_lock().unwrap(), 2);
40/// # })
41/// ```
42pub struct Mutex<T: ?Sized> {
43 /// Current state of the mutex.
44 ///
45 /// The least significant bit is set to 1 if the mutex is locked.
46 /// The other bits hold the number of starved lock operations.
47 state: AtomicUsize,
48
49 /// Lock operations waiting for the mutex to be released.
50 lock_ops: Event,
51
52 /// The value inside the mutex.
53 data: UnsafeCell<T>,
54}
55
56unsafe impl<T: Send + ?Sized> Send for Mutex<T> {}
57unsafe impl<T: Send + ?Sized> Sync for Mutex<T> {}
58
59impl<T> Mutex<T> {
60 const_fn! {
61 const_if: #[cfg(not(loom))];
62 /// Creates a new async mutex.
63 ///
64 /// # Examples
65 ///
66 /// ```
67 /// use async_lock::Mutex;
68 ///
69 /// let mutex = Mutex::new(0);
70 /// ```
71 pub const fn new(data: T) -> Mutex<T> {
72 Mutex {
73 state: AtomicUsize::new(0),
74 lock_ops: Event::new(),
75 data: UnsafeCell::new(data),
76 }
77 }
78 }
79
80 /// Consumes the mutex, returning the underlying data.
81 ///
82 /// # Examples
83 ///
84 /// ```
85 /// use async_lock::Mutex;
86 ///
87 /// let mutex = Mutex::new(10);
88 /// assert_eq!(mutex.into_inner(), 10);
89 /// ```
90 pub fn into_inner(self) -> T {
91 self.data.into_inner()
92 }
93}
94
95impl<T: ?Sized> Mutex<T> {
96 /// Acquires the mutex.
97 ///
98 /// Returns a guard that releases the mutex when dropped.
99 ///
100 /// # Examples
101 ///
102 /// ```
103 /// # futures_lite::future::block_on(async {
104 /// use async_lock::Mutex;
105 ///
106 /// let mutex = Mutex::new(10);
107 /// let guard = mutex.lock().await;
108 /// assert_eq!(*guard, 10);
109 /// # })
110 /// ```
111 #[inline]
112 pub fn lock(&self) -> Lock<'_, T> {
113 Lock::_new(LockInner {
114 mutex: self,
115 acquire_slow: None,
116 })
117 }
118
119 /// Acquires the mutex using the blocking strategy.
120 ///
121 /// Returns a guard that releases the mutex when dropped.
122 ///
123 /// # Blocking
124 ///
125 /// Rather than using asynchronous waiting, like the [`lock`][Mutex::lock] method,
126 /// this method will block the current thread until the lock is acquired.
127 ///
128 /// This method should not be used in an asynchronous context. It is intended to be
129 /// used in a way that a mutex can be used in both asynchronous and synchronous contexts.
130 /// Calling this method in an asynchronous context may result in a deadlock.
131 ///
132 /// # Examples
133 ///
134 /// ```
135 /// use async_lock::Mutex;
136 ///
137 /// let mutex = Mutex::new(10);
138 /// let guard = mutex.lock_blocking();
139 /// assert_eq!(*guard, 10);
140 /// ```
141 #[cfg(all(feature = "std", not(target_family = "wasm")))]
142 #[inline]
143 pub fn lock_blocking(&self) -> MutexGuard<'_, T> {
144 self.lock().wait()
145 }
146
147 /// Attempts to acquire the mutex.
148 ///
149 /// If the mutex could not be acquired at this time, then [`None`] is returned. Otherwise, a
150 /// guard is returned that releases the mutex when dropped.
151 ///
152 /// # Examples
153 ///
154 /// ```
155 /// use async_lock::Mutex;
156 ///
157 /// let mutex = Mutex::new(10);
158 /// if let Some(guard) = mutex.try_lock() {
159 /// assert_eq!(*guard, 10);
160 /// }
161 /// # ;
162 /// ```
163 #[inline]
164 pub fn try_lock(&self) -> Option<MutexGuard<'_, T>> {
165 if self
166 .state
167 .compare_exchange(0, 1, Ordering::Acquire, Ordering::Acquire)
168 .is_ok()
169 {
170 Some(MutexGuard(self))
171 } else {
172 None
173 }
174 }
175
176 /// Returns a mutable reference to the underlying data.
177 ///
178 /// Since this call borrows the mutex mutably, no actual locking takes place -- the mutable
179 /// borrow statically guarantees the mutex is not already acquired.
180 ///
181 /// # Examples
182 ///
183 /// ```
184 /// # futures_lite::future::block_on(async {
185 /// use async_lock::Mutex;
186 ///
187 /// let mut mutex = Mutex::new(0);
188 /// *mutex.get_mut() = 10;
189 /// assert_eq!(*mutex.lock().await, 10);
190 /// # })
191 /// ```
192 pub fn get_mut(&mut self) -> &mut T {
193 self.data.get_mut()
194 }
195
196 /// Unlocks the mutex directly.
197 ///
198 /// # Safety
199 ///
200 /// This function is intended to be used only in the case where the mutex is locked,
201 /// and the guard is subsequently forgotten. Calling this while you don't hold a lock
202 /// on the mutex will likely lead to UB.
203 pub(crate) unsafe fn unlock_unchecked(&self) {
204 // Remove the last bit and notify a waiting lock operation.
205 self.state.fetch_sub(1, Ordering::Release);
206 self.lock_ops.notify(1);
207 }
208}
209
210impl<T: ?Sized> Mutex<T> {
211 /// Acquires the mutex and clones a reference to it.
212 ///
213 /// Returns an owned guard that releases the mutex when dropped.
214 ///
215 /// # Examples
216 ///
217 /// ```
218 /// # futures_lite::future::block_on(async {
219 /// use async_lock::Mutex;
220 /// use std::sync::Arc;
221 ///
222 /// let mutex = Arc::new(Mutex::new(10));
223 /// let guard = mutex.lock_arc().await;
224 /// assert_eq!(*guard, 10);
225 /// # })
226 /// ```
227 #[inline]
228 pub fn lock_arc(self: &Arc<Self>) -> LockArc<T> {
229 LockArc::_new(LockArcInnards::Unpolled {
230 mutex: Some(self.clone()),
231 })
232 }
233
234 /// Acquires the mutex and clones a reference to it using the blocking strategy.
235 ///
236 /// Returns an owned guard that releases the mutex when dropped.
237 ///
238 /// # Blocking
239 ///
240 /// Rather than using asynchronous waiting, like the [`lock_arc`][Mutex::lock_arc] method,
241 /// this method will block the current thread until the lock is acquired.
242 ///
243 /// This method should not be used in an asynchronous context. It is intended to be
244 /// used in a way that a mutex can be used in both asynchronous and synchronous contexts.
245 /// Calling this method in an asynchronous context may result in a deadlock.
246 ///
247 /// # Examples
248 ///
249 /// ```
250 /// use async_lock::Mutex;
251 /// use std::sync::Arc;
252 ///
253 /// let mutex = Arc::new(Mutex::new(10));
254 /// let guard = mutex.lock_arc_blocking();
255 /// assert_eq!(*guard, 10);
256 /// ```
257 #[cfg(all(feature = "std", not(target_family = "wasm")))]
258 #[inline]
259 pub fn lock_arc_blocking(self: &Arc<Self>) -> MutexGuardArc<T> {
260 self.lock_arc().wait()
261 }
262
263 /// Attempts to acquire the mutex and clone a reference to it.
264 ///
265 /// If the mutex could not be acquired at this time, then [`None`] is returned. Otherwise, an
266 /// owned guard is returned that releases the mutex when dropped.
267 ///
268 /// # Examples
269 ///
270 /// ```
271 /// use async_lock::Mutex;
272 /// use std::sync::Arc;
273 ///
274 /// let mutex = Arc::new(Mutex::new(10));
275 /// if let Some(guard) = mutex.try_lock() {
276 /// assert_eq!(*guard, 10);
277 /// }
278 /// # ;
279 /// ```
280 #[inline]
281 pub fn try_lock_arc(self: &Arc<Self>) -> Option<MutexGuardArc<T>> {
282 if self
283 .state
284 .compare_exchange(0, 1, Ordering::Acquire, Ordering::Acquire)
285 .is_ok()
286 {
287 Some(MutexGuardArc(self.clone()))
288 } else {
289 None
290 }
291 }
292}
293
294impl<T: fmt::Debug + ?Sized> fmt::Debug for Mutex<T> {
295 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
296 struct Locked;
297 impl fmt::Debug for Locked {
298 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
299 f.write_str("<locked>")
300 }
301 }
302
303 match self.try_lock() {
304 None => f.debug_struct("Mutex").field("data", &Locked).finish(),
305 Some(guard) => f.debug_struct("Mutex").field("data", &&*guard).finish(),
306 }
307 }
308}
309
310impl<T> From<T> for Mutex<T> {
311 fn from(val: T) -> Mutex<T> {
312 Mutex::new(val)
313 }
314}
315
316impl<T: Default> Default for Mutex<T> {
317 fn default() -> Mutex<T> {
318 Mutex::new(Default::default())
319 }
320}
321
322easy_wrapper! {
323 /// The future returned by [`Mutex::lock`].
324 pub struct Lock<'a, T: ?Sized>(LockInner<'a, T> => MutexGuard<'a, T>);
325 #[cfg(all(feature = "std", not(target_family = "wasm")))]
326 pub(crate) wait();
327}
328
329pin_project_lite::pin_project! {
330 /// Inner future for acquiring the mutex.
331 struct LockInner<'a, T: ?Sized> {
332 // Reference to the mutex.
333 mutex: &'a Mutex<T>,
334
335 // The future that waits for the mutex to become available.
336 #[pin]
337 acquire_slow: Option<AcquireSlow<&'a Mutex<T>, T>>,
338 }
339}
340
341unsafe impl<T: Send + ?Sized> Send for Lock<'_, T> {}
342unsafe impl<T: Sync + ?Sized> Sync for Lock<'_, T> {}
343
344impl<T: ?Sized> fmt::Debug for Lock<'_, T> {
345 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
346 f.write_str("Lock { .. }")
347 }
348}
349
350impl<'a, T: ?Sized> EventListenerFuture for LockInner<'a, T> {
351 type Output = MutexGuard<'a, T>;
352
353 #[inline]
354 fn poll_with_strategy<'x, S: event_listener_strategy::Strategy<'x>>(
355 self: Pin<&mut Self>,
356 strategy: &mut S,
357 context: &mut S::Context,
358 ) -> Poll<Self::Output> {
359 let mut this = self.project();
360
361 // This may seem weird, but the borrow checker complains otherwise.
362 if this.acquire_slow.is_none() {
363 match this.mutex.try_lock() {
364 Some(guard) => return Poll::Ready(guard),
365 None => {
366 this.acquire_slow.set(Some(AcquireSlow::new(this.mutex)));
367 }
368 }
369 }
370
371 ready!(this
372 .acquire_slow
373 .as_pin_mut()
374 .unwrap()
375 .poll_with_strategy(strategy, context));
376 Poll::Ready(MutexGuard(this.mutex))
377 }
378}
379
380easy_wrapper! {
381 /// The future returned by [`Mutex::lock_arc`].
382 pub struct LockArc<T: ?Sized>(LockArcInnards<T> => MutexGuardArc<T>);
383 #[cfg(all(feature = "std", not(target_family = "wasm")))]
384 pub(crate) wait();
385}
386
387pin_project_lite::pin_project! {
388 #[project = LockArcInnardsProj]
389 enum LockArcInnards<T: ?Sized> {
390 /// We have not tried to poll the fast path yet.
391 Unpolled { mutex: Option<Arc<Mutex<T>>> },
392
393 /// We are acquiring the mutex through the slow path.
394 AcquireSlow {
395 #[pin]
396 inner: AcquireSlow<Arc<Mutex<T>>, T>
397 },
398 }
399}
400
401unsafe impl<T: Send + ?Sized> Send for LockArc<T> {}
402unsafe impl<T: Sync + ?Sized> Sync for LockArc<T> {}
403
404impl<T: ?Sized> fmt::Debug for LockArcInnards<T> {
405 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
406 f.write_str("LockArc { .. }")
407 }
408}
409
410impl<T: ?Sized> EventListenerFuture for LockArcInnards<T> {
411 type Output = MutexGuardArc<T>;
412
413 fn poll_with_strategy<'a, S: event_listener_strategy::Strategy<'a>>(
414 mut self: Pin<&mut Self>,
415 strategy: &mut S,
416 context: &mut S::Context,
417 ) -> Poll<Self::Output> {
418 // Set the inner future if needed.
419 if let LockArcInnardsProj::Unpolled { mutex } = self.as_mut().project() {
420 let mutex = mutex.take().expect("mutex taken more than once");
421
422 // Try the fast path before trying to register slowly.
423 if let Some(guard) = mutex.try_lock_arc() {
424 return Poll::Ready(guard);
425 }
426
427 // Set the inner future to the slow acquire path.
428 self.as_mut().set(LockArcInnards::AcquireSlow {
429 inner: AcquireSlow::new(mutex),
430 });
431 }
432
433 // Poll the inner future.
434 let value = match self.project() {
435 LockArcInnardsProj::AcquireSlow { inner } => {
436 ready!(inner.poll_with_strategy(strategy, context))
437 }
438 _ => unreachable!(),
439 };
440
441 Poll::Ready(MutexGuardArc(value))
442 }
443}
444
445pin_project_lite::pin_project! {
446 /// Future for acquiring the mutex slowly.
447 struct AcquireSlow<B: Borrow<Mutex<T>>, T: ?Sized> {
448 // Reference to the mutex.
449 mutex: Option<B>,
450
451 // The event listener waiting on the mutex.
452 listener: Option<EventListener>,
453
454 // The point at which the mutex lock was started.
455 start: Start,
456
457 // This lock operation is starving.
458 starved: bool,
459
460 // Capture the `T` lifetime.
461 #[pin]
462 _marker: PhantomData<T>,
463
464 // Keeping this type `!Unpin` enables future optimizations.
465 #[pin]
466 _pin: PhantomPinned
467 }
468
469 impl<T: ?Sized, B: Borrow<Mutex<T>>> PinnedDrop for AcquireSlow<B, T> {
470 fn drop(this: Pin<&mut Self>) {
471 // Make sure the starvation counter is decremented.
472 this.take_mutex();
473 }
474 }
475}
476
477/// `pin_project_lite` doesn't support `#[cfg]` yet, so we have to do this manually.
478struct Start {
479 #[cfg(all(feature = "std", not(target_family = "wasm")))]
480 start: Option<Instant>,
481}
482
483impl<T: ?Sized, B: Borrow<Mutex<T>>> AcquireSlow<B, T> {
484 /// Create a new `AcquireSlow` future.
485 #[cold]
486 fn new(mutex: B) -> Self {
487 AcquireSlow {
488 mutex: Some(mutex),
489 listener: None,
490 start: Start {
491 #[cfg(all(feature = "std", not(target_family = "wasm")))]
492 start: None,
493 },
494 starved: false,
495 _marker: PhantomData,
496 _pin: PhantomPinned,
497 }
498 }
499
500 /// Take the mutex reference out, decrementing the counter if necessary.
501 fn take_mutex(self: Pin<&mut Self>) -> Option<B> {
502 let this = self.project();
503 let mutex = this.mutex.take();
504
505 if *this.starved {
506 if let Some(mutex) = mutex.as_ref() {
507 // Decrement this counter before we exit.
508 mutex.borrow().state.fetch_sub(2, Ordering::Release);
509 }
510 }
511
512 mutex
513 }
514}
515
516impl<T: ?Sized, B: Unpin + Borrow<Mutex<T>>> EventListenerFuture for AcquireSlow<B, T> {
517 type Output = B;
518
519 #[cold]
520 fn poll_with_strategy<'a, S: event_listener_strategy::Strategy<'a>>(
521 mut self: Pin<&mut Self>,
522 strategy: &mut S,
523 context: &mut S::Context,
524 ) -> Poll<Self::Output> {
525 let this = self.as_mut().project();
526 #[cfg(all(feature = "std", not(target_family = "wasm")))]
527 let start = *this.start.start.get_or_insert_with(Instant::now);
528 let mutex = Borrow::<Mutex<T>>::borrow(
529 this.mutex.as_ref().expect("future polled after completion"),
530 );
531
532 // Only use this hot loop if we aren't currently starved.
533 if !*this.starved {
534 loop {
535 // Start listening for events.
536 if this.listener.is_none() {
537 *this.listener = Some(mutex.lock_ops.listen());
538
539 // Try locking if nobody is being starved.
540 match mutex
541 .state
542 .compare_exchange(0, 1, Ordering::Acquire, Ordering::Acquire)
543 .unwrap_or_else(|x| x)
544 {
545 // Lock acquired!
546 0 => return Poll::Ready(self.take_mutex().unwrap()),
547
548 // Lock is held and nobody is starved.
549 1 => {}
550
551 // Somebody is starved.
552 _ => break,
553 }
554 } else {
555 ready!(strategy.poll(this.listener, context));
556
557 // Try locking if nobody is being starved.
558 match mutex
559 .state
560 .compare_exchange(0, 1, Ordering::Acquire, Ordering::Acquire)
561 .unwrap_or_else(|x| x)
562 {
563 // Lock acquired!
564 0 => return Poll::Ready(self.take_mutex().unwrap()),
565
566 // Lock is held and nobody is starved.
567 1 => {}
568
569 // Somebody is starved.
570 _ => {
571 // Notify the first listener in line because we probably received a
572 // notification that was meant for a starved task.
573 mutex.lock_ops.notify(1);
574 break;
575 }
576 }
577
578 // If waiting for too long, fall back to a fairer locking strategy that will prevent
579 // newer lock operations from starving us forever.
580 #[cfg(all(feature = "std", not(target_family = "wasm")))]
581 if start.elapsed() > Duration::from_micros(500) {
582 break;
583 }
584 }
585 }
586
587 // Increment the number of starved lock operations.
588 if mutex.state.fetch_add(2, Ordering::Release) > usize::MAX / 2 {
589 // In case of potential overflow, abort.
590 crate::abort();
591 }
592
593 // Indicate that we are now starving and will use a fairer locking strategy.
594 *this.starved = true;
595 }
596
597 // Fairer locking loop.
598 loop {
599 if this.listener.is_none() {
600 // Start listening for events.
601 *this.listener = Some(mutex.lock_ops.listen());
602
603 // Try locking if nobody else is being starved.
604 match mutex
605 .state
606 .compare_exchange(2, 2 | 1, Ordering::Acquire, Ordering::Acquire)
607 .unwrap_or_else(|x| x)
608 {
609 // Lock acquired!
610 2 => return Poll::Ready(self.take_mutex().unwrap()),
611
612 // Lock is held by someone.
613 s if s % 2 == 1 => {}
614
615 // Lock is available.
616 _ => {
617 // Be fair: notify the first listener and then go wait in line.
618 mutex.lock_ops.notify(1);
619 }
620 }
621 } else {
622 // Wait for a notification.
623 ready!(strategy.poll(this.listener, context));
624
625 // Try acquiring the lock without waiting for others.
626 if mutex.state.fetch_or(1, Ordering::Acquire) % 2 == 0 {
627 return Poll::Ready(self.take_mutex().unwrap());
628 }
629 }
630 }
631 }
632}
633
634/// A guard that releases the mutex when dropped.
635#[clippy::has_significant_drop]
636pub struct MutexGuard<'a, T: ?Sized>(&'a Mutex<T>);
637
638unsafe impl<T: Send + ?Sized> Send for MutexGuard<'_, T> {}
639unsafe impl<T: Sync + ?Sized> Sync for MutexGuard<'_, T> {}
640
641impl<'a, T: ?Sized> MutexGuard<'a, T> {
642 /// Returns a reference to the mutex a guard came from.
643 ///
644 /// # Examples
645 ///
646 /// ```
647 /// # futures_lite::future::block_on(async {
648 /// use async_lock::{Mutex, MutexGuard};
649 ///
650 /// let mutex = Mutex::new(10i32);
651 /// let guard = mutex.lock().await;
652 /// dbg!(MutexGuard::source(&guard));
653 /// # })
654 /// ```
655 pub fn source(guard: &MutexGuard<'a, T>) -> &'a Mutex<T> {
656 guard.0
657 }
658}
659
660impl<T: ?Sized> Drop for MutexGuard<'_, T> {
661 #[inline]
662 fn drop(&mut self) {
663 // SAFETY: we are dropping the mutex guard, therefore unlocking the mutex.
664 unsafe {
665 self.0.unlock_unchecked();
666 }
667 }
668}
669
670impl<T: fmt::Debug + ?Sized> fmt::Debug for MutexGuard<'_, T> {
671 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
672 fmt::Debug::fmt(&**self, f)
673 }
674}
675
676impl<T: fmt::Display + ?Sized> fmt::Display for MutexGuard<'_, T> {
677 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
678 (**self).fmt(f)
679 }
680}
681
682impl<T: ?Sized> Deref for MutexGuard<'_, T> {
683 type Target = T;
684
685 fn deref(&self) -> &T {
686 unsafe { &*self.0.data.get() }
687 }
688}
689
690impl<T: ?Sized> DerefMut for MutexGuard<'_, T> {
691 fn deref_mut(&mut self) -> &mut T {
692 unsafe { &mut *self.0.data.get() }
693 }
694}
695
696/// An owned guard that releases the mutex when dropped.
697#[clippy::has_significant_drop]
698pub struct MutexGuardArc<T: ?Sized>(Arc<Mutex<T>>);
699
700unsafe impl<T: Send + ?Sized> Send for MutexGuardArc<T> {}
701unsafe impl<T: Sync + ?Sized> Sync for MutexGuardArc<T> {}
702
703impl<T: ?Sized> MutexGuardArc<T> {
704 /// Returns a reference to the mutex a guard came from.
705 ///
706 /// # Examples
707 ///
708 /// ```
709 /// # futures_lite::future::block_on(async {
710 /// use async_lock::{Mutex, MutexGuardArc};
711 /// use std::sync::Arc;
712 ///
713 /// let mutex = Arc::new(Mutex::new(10i32));
714 /// let guard = mutex.lock_arc().await;
715 /// dbg!(MutexGuardArc::source(&guard));
716 /// # })
717 /// ```
718 pub fn source(guard: &Self) -> &Arc<Mutex<T>>
719 where
720 // Required because `MutexGuardArc` implements `Sync` regardless of whether `T` is `Send`,
721 // but this method allows dropping `T` from a different thead than it was created in.
722 T: Send,
723 {
724 &guard.0
725 }
726}
727
728impl<T: ?Sized> Drop for MutexGuardArc<T> {
729 #[inline]
730 fn drop(&mut self) {
731 // SAFETY: we are dropping the mutex guard, therefore unlocking the mutex.
732 unsafe {
733 self.0.unlock_unchecked();
734 }
735 }
736}
737
738impl<T: fmt::Debug + ?Sized> fmt::Debug for MutexGuardArc<T> {
739 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
740 fmt::Debug::fmt(&**self, f)
741 }
742}
743
744impl<T: fmt::Display + ?Sized> fmt::Display for MutexGuardArc<T> {
745 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
746 (**self).fmt(f)
747 }
748}
749
750impl<T: ?Sized> Deref for MutexGuardArc<T> {
751 type Target = T;
752
753 fn deref(&self) -> &T {
754 unsafe { &*self.0.data.get() }
755 }
756}
757
758impl<T: ?Sized> DerefMut for MutexGuardArc<T> {
759 fn deref_mut(&mut self) -> &mut T {
760 unsafe { &mut *self.0.data.get() }
761 }
762}