Auto merge of #117107 - zachs18:mapped-mutex-guard, r=Amanieu · rust-lang/rust@a2f3c0c (original) (raw)
`@@ -3,7 +3,10 @@ mod tests;
`
3
3
``
4
4
`use crate::cell::UnsafeCell;
`
5
5
`use crate::fmt;
`
``
6
`+
use crate:📑:PhantomData;
`
``
7
`+
use crate::mem::ManuallyDrop;
`
6
8
`use crate::ops::{Deref, DerefMut};
`
``
9
`+
use crate::ptr::NonNull;
`
7
10
`use crate::sync::{poison, LockResult, TryLockError, TryLockResult};
`
8
11
`use crate::sys::locks as sys;
`
9
12
``
`@@ -213,6 +216,47 @@ impl<T: ?Sized> !Send for MutexGuard<'_, T> {}
`
213
216
`#[stable(feature = "mutexguard", since = "1.19.0")]
`
214
217
`unsafe impl<T: ?Sized + Sync> Sync for MutexGuard<'_, T> {}
`
215
218
``
``
219
`` +
/// An RAII mutex guard returned by MutexGuard::map
, which can point to a
``
``
220
`+
/// subfield of the protected data. When this structure is dropped (falls out
`
``
221
`+
/// of scope), the lock will be unlocked.
`
``
222
`+
///
`
``
223
`` +
/// The main difference between MappedMutexGuard
and [MutexGuard
] is that the
``
``
224
`` +
/// former cannot be used with [Condvar
], since that
``
``
225
`+
/// could introduce soundness issues if the locked object is modified by another
`
``
226
`` +
/// thread while the Mutex
is unlocked.
``
``
227
`+
///
`
``
228
`+
/// The data protected by the mutex can be accessed through this guard via its
`
``
229
`` +
/// [Deref
] and [DerefMut
] implementations.
``
``
230
`+
///
`
``
231
`` +
/// This structure is created by the [map
] and [try_map
] methods on
``
``
232
`` +
/// [MutexGuard
].
``
``
233
`+
///
`
``
234
`` +
/// [map
]: MutexGuard::map
``
``
235
`` +
/// [try_map
]: MutexGuard::try_map
``
``
236
`` +
/// [Condvar
]: crate::sync::Condvar
``
``
237
`+
#[must_use = "if unused the Mutex will immediately unlock"]
`
``
238
`+
#[must_not_suspend = "holding a MappedMutexGuard across suspend \
`
``
239
`+
points can cause deadlocks, delays, \
`
``
240
`` +
and cause Futures to not implement Send
"]
``
``
241
`+
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
`
``
242
`+
#[clippy::has_significant_drop]
`
``
243
`+
pub struct MappedMutexGuard<'a, T: ?Sized + 'a> {
`
``
244
`` +
// NB: we use a pointer instead of &'a mut T
to avoid noalias
violations, because a
``
``
245
`` +
// MappedMutexGuard
argument doesn't hold uniqueness for its whole scope, only until it drops.
``
``
246
`` +
// NonNull
is covariant over T
, so we add a PhantomData<&'a mut T>
field
``
``
247
`` +
// below for the correct variance over T
(invariance).
``
``
248
`+
data: NonNull,
`
``
249
`+
inner: &'a sys::Mutex,
`
``
250
`+
poison_flag: &'a poison::Flag,
`
``
251
`+
poison: poison::Guard,
`
``
252
`+
_variance: PhantomData<&'a mut T>,
`
``
253
`+
}
`
``
254
+
``
255
`+
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
`
``
256
`+
impl<T: ?Sized> !Send for MappedMutexGuard<'_, T> {}
`
``
257
`+
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
`
``
258
`+
unsafe impl<T: ?Sized + Sync> Sync for MappedMutexGuard<'_, T> {}
`
``
259
+
216
260
`impl Mutex {
`
217
261
`/// Creates a new mutex in an unlocked state ready for use.
`
218
262
`///
`
`@@ -550,3 +594,178 @@ pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex {
`
550
594
`pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag {
`
551
595
`&guard.lock.poison
`
552
596
`}
`
``
597
+
``
598
`+
impl<'a, T: ?Sized> MutexGuard<'a, T> {
`
``
599
`` +
/// Makes a [MappedMutexGuard
] for a component of the borrowed data, e.g.
``
``
600
`+
/// an enum variant.
`
``
601
`+
///
`
``
602
`` +
/// The Mutex
is already locked, so this cannot fail.
``
``
603
`+
///
`
``
604
`+
/// This is an associated function that needs to be used as
`
``
605
`` +
/// MutexGuard::map(...)
. A method would interfere with methods of the
``
``
606
`` +
/// same name on the contents of the MutexGuard
used through Deref
.
``
``
607
`+
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
`
``
608
`+
pub fn map<U, F>(orig: Self, f: F) -> MappedMutexGuard<'a, U>
`
``
609
`+
where
`
``
610
`+
F: FnOnce(&mut T) -> &mut U,
`
``
611
`+
U: ?Sized,
`
``
612
`+
{
`
``
613
`` +
// SAFETY: the conditions of MutexGuard::new
were satisfied when the original guard
``
``
614
`` +
// was created, and have been upheld throughout map
and/or try_map
.
``
``
615
`+
// The signature of the closure guarantees that it will not "leak" the lifetime of the reference
`
``
616
`+
// passed to it. If the closure panics, the guard will be dropped.
`
``
617
`+
let data = NonNull::from(f(unsafe { &mut *orig.lock.data.get() }));
`
``
618
`+
let orig = ManuallyDrop::new(orig);
`
``
619
`+
MappedMutexGuard {
`
``
620
`+
data,
`
``
621
`+
inner: &orig.lock.inner,
`
``
622
`+
poison_flag: &orig.lock.poison,
`
``
623
`+
poison: orig.poison.clone(),
`
``
624
`+
_variance: PhantomData,
`
``
625
`+
}
`
``
626
`+
}
`
``
627
+
``
628
`` +
/// Makes a [MappedMutexGuard
] for a component of the borrowed data. The
``
``
629
`` +
/// original guard is returned as an Err(...)
if the closure returns
``
``
630
`` +
/// None
.
``
``
631
`+
///
`
``
632
`` +
/// The Mutex
is already locked, so this cannot fail.
``
``
633
`+
///
`
``
634
`+
/// This is an associated function that needs to be used as
`
``
635
`` +
/// MutexGuard::try_map(...)
. A method would interfere with methods of the
``
``
636
`` +
/// same name on the contents of the MutexGuard
used through Deref
.
``
``
637
`+
#[doc(alias = "filter_map")]
`
``
638
`+
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
`
``
639
`+
pub fn try_map<U, F>(orig: Self, f: F) -> Result<MappedMutexGuard<'a, U>, Self>
`
``
640
`+
where
`
``
641
`+
F: FnOnce(&mut T) -> Option<&mut U>,
`
``
642
`+
U: ?Sized,
`
``
643
`+
{
`
``
644
`` +
// SAFETY: the conditions of MutexGuard::new
were satisfied when the original guard
``
``
645
`` +
// was created, and have been upheld throughout map
and/or try_map
.
``
``
646
`+
// The signature of the closure guarantees that it will not "leak" the lifetime of the reference
`
``
647
`+
// passed to it. If the closure panics, the guard will be dropped.
`
``
648
`+
match f(unsafe { &mut *orig.lock.data.get() }) {
`
``
649
`+
Some(data) => {
`
``
650
`+
let data = NonNull::from(data);
`
``
651
`+
let orig = ManuallyDrop::new(orig);
`
``
652
`+
Ok(MappedMutexGuard {
`
``
653
`+
data,
`
``
654
`+
inner: &orig.lock.inner,
`
``
655
`+
poison_flag: &orig.lock.poison,
`
``
656
`+
poison: orig.poison.clone(),
`
``
657
`+
_variance: PhantomData,
`
``
658
`+
})
`
``
659
`+
}
`
``
660
`+
None => Err(orig),
`
``
661
`+
}
`
``
662
`+
}
`
``
663
`+
}
`
``
664
+
``
665
`+
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
`
``
666
`+
impl<T: ?Sized> Deref for MappedMutexGuard<'_, T> {
`
``
667
`+
type Target = T;
`
``
668
+
``
669
`+
fn deref(&self) -> &T {
`
``
670
`+
unsafe { self.data.as_ref() }
`
``
671
`+
}
`
``
672
`+
}
`
``
673
+
``
674
`+
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
`
``
675
`+
impl<T: ?Sized> DerefMut for MappedMutexGuard<'_, T> {
`
``
676
`+
fn deref_mut(&mut self) -> &mut T {
`
``
677
`+
unsafe { self.data.as_mut() }
`
``
678
`+
}
`
``
679
`+
}
`
``
680
+
``
681
`+
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
`
``
682
`+
impl<T: ?Sized> Drop for MappedMutexGuard<'_, T> {
`
``
683
`+
#[inline]
`
``
684
`+
fn drop(&mut self) {
`
``
685
`+
unsafe {
`
``
686
`+
self.poison_flag.done(&self.poison);
`
``
687
`+
self.inner.unlock();
`
``
688
`+
}
`
``
689
`+
}
`
``
690
`+
}
`
``
691
+
``
692
`+
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
`
``
693
`+
impl<T: ?Sized + fmt::Debug> fmt::Debug for MappedMutexGuard<'_, T> {
`
``
694
`+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
`
``
695
`+
fmt::Debug::fmt(&**self, f)
`
``
696
`+
}
`
``
697
`+
}
`
``
698
+
``
699
`+
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
`
``
700
`+
impl<T: ?Sized + fmt::Display> fmt::Display for MappedMutexGuard<'_, T> {
`
``
701
`+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
`
``
702
`+
(**self).fmt(f)
`
``
703
`+
}
`
``
704
`+
}
`
``
705
+
``
706
`+
impl<'a, T: ?Sized> MappedMutexGuard<'a, T> {
`
``
707
`` +
/// Makes a [MappedMutexGuard
] for a component of the borrowed data, e.g.
``
``
708
`+
/// an enum variant.
`
``
709
`+
///
`
``
710
`` +
/// The Mutex
is already locked, so this cannot fail.
``
``
711
`+
///
`
``
712
`+
/// This is an associated function that needs to be used as
`
``
713
`` +
/// MappedMutexGuard::map(...)
. A method would interfere with methods of the
``
``
714
`` +
/// same name on the contents of the MutexGuard
used through Deref
.
``
``
715
`+
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
`
``
716
`+
pub fn map<U, F>(mut orig: Self, f: F) -> MappedMutexGuard<'a, U>
`
``
717
`+
where
`
``
718
`+
F: FnOnce(&mut T) -> &mut U,
`
``
719
`+
U: ?Sized,
`
``
720
`+
{
`
``
721
`` +
// SAFETY: the conditions of MutexGuard::new
were satisfied when the original guard
``
``
722
`` +
// was created, and have been upheld throughout map
and/or try_map
.
``
``
723
`+
// The signature of the closure guarantees that it will not "leak" the lifetime of the reference
`
``
724
`+
// passed to it. If the closure panics, the guard will be dropped.
`
``
725
`+
let data = NonNull::from(f(unsafe { orig.data.as_mut() }));
`
``
726
`+
let orig = ManuallyDrop::new(orig);
`
``
727
`+
MappedMutexGuard {
`
``
728
`+
data,
`
``
729
`+
inner: orig.inner,
`
``
730
`+
poison_flag: orig.poison_flag,
`
``
731
`+
poison: orig.poison.clone(),
`
``
732
`+
_variance: PhantomData,
`
``
733
`+
}
`
``
734
`+
}
`
``
735
+
``
736
`` +
/// Makes a [MappedMutexGuard
] for a component of the borrowed data. The
``
``
737
`` +
/// original guard is returned as an Err(...)
if the closure returns
``
``
738
`` +
/// None
.
``
``
739
`+
///
`
``
740
`` +
/// The Mutex
is already locked, so this cannot fail.
``
``
741
`+
///
`
``
742
`+
/// This is an associated function that needs to be used as
`
``
743
`` +
/// MappedMutexGuard::try_map(...)
. A method would interfere with methods of the
``
``
744
`` +
/// same name on the contents of the MutexGuard
used through Deref
.
``
``
745
`+
#[doc(alias = "filter_map")]
`
``
746
`+
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
`
``
747
`+
pub fn try_map<U, F>(mut orig: Self, f: F) -> Result<MappedMutexGuard<'a, U>, Self>
`
``
748
`+
where
`
``
749
`+
F: FnOnce(&mut T) -> Option<&mut U>,
`
``
750
`+
U: ?Sized,
`
``
751
`+
{
`
``
752
`` +
// SAFETY: the conditions of MutexGuard::new
were satisfied when the original guard
``
``
753
`` +
// was created, and have been upheld throughout map
and/or try_map
.
``
``
754
`+
// The signature of the closure guarantees that it will not "leak" the lifetime of the reference
`
``
755
`+
// passed to it. If the closure panics, the guard will be dropped.
`
``
756
`+
match f(unsafe { orig.data.as_mut() }) {
`
``
757
`+
Some(data) => {
`
``
758
`+
let data = NonNull::from(data);
`
``
759
`+
let orig = ManuallyDrop::new(orig);
`
``
760
`+
Ok(MappedMutexGuard {
`
``
761
`+
data,
`
``
762
`+
inner: orig.inner,
`
``
763
`+
poison_flag: orig.poison_flag,
`
``
764
`+
poison: orig.poison.clone(),
`
``
765
`+
_variance: PhantomData,
`
``
766
`+
})
`
``
767
`+
}
`
``
768
`+
None => Err(orig),
`
``
769
`+
}
`
``
770
`+
}
`
``
771
`+
}
`