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