@@ -3,7 +3,10 @@ mod tests;
3
3
4
4
use crate :: cell:: UnsafeCell ;
5
5
use crate :: fmt;
6
+ use crate :: marker:: 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 < T > ,
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 < T > Mutex < T > {
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
+ }
0 commit comments