@@ -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,43 @@ 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 = "none" ) ]
242
+ #[ clippy:: has_significant_drop]
243
+ pub struct MappedMutexGuard < ' a , T : ?Sized + ' a > {
244
+ data : NonNull < T > ,
245
+ inner : & ' a sys:: Mutex ,
246
+ poison_flag : & ' a poison:: Flag ,
247
+ poison : poison:: Guard ,
248
+ _variance : PhantomData < & ' a mut T > ,
249
+ }
250
+
251
+ #[ unstable( feature = "mapped_lock_guards" , issue = "none" ) ]
252
+ impl < T : ?Sized > !Send for MappedMutexGuard < ' _ , T > { }
253
+ #[ unstable( feature = "mapped_lock_guards" , issue = "none" ) ]
254
+ unsafe impl < T : ?Sized + Sync > Sync for MappedMutexGuard < ' _ , T > { }
255
+
216
256
impl < T > Mutex < T > {
217
257
/// Creates a new mutex in an unlocked state ready for use.
218
258
///
@@ -552,3 +592,156 @@ pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex {
552
592
pub fn guard_poison < ' a , T : ?Sized > ( guard : & MutexGuard < ' a , T > ) -> & ' a poison:: Flag {
553
593
& guard. lock . poison
554
594
}
595
+
596
+ impl < ' a , T : ?Sized > MutexGuard < ' a , T > {
597
+ /// Makes a [`MappedMutexGuard`] for a component of the borrowed data, e.g.
598
+ /// an enum variant.
599
+ ///
600
+ /// The `Mutex` is already locked, so this cannot fail.
601
+ ///
602
+ /// This is an associated function that needs to be used as
603
+ /// `MutexGuard::map(...)`. A method would interfere with methods of the
604
+ /// same name on the contents of the `MutexGuard` used through `Deref`.
605
+ #[ unstable( feature = "mapped_lock_guards" , issue = "none" ) ]
606
+ pub fn map < U , F > ( orig : Self , f : F ) -> MappedMutexGuard < ' a , U >
607
+ where
608
+ F : FnOnce ( & mut T ) -> & mut U ,
609
+ U : ?Sized ,
610
+ {
611
+ let mut orig = ManuallyDrop :: new ( orig) ;
612
+ let value = NonNull :: from ( f ( & mut * orig) ) ;
613
+ MappedMutexGuard {
614
+ data : value,
615
+ inner : & orig. lock . inner ,
616
+ poison_flag : & orig. lock . poison ,
617
+ poison : orig. poison . clone ( ) ,
618
+ _variance : PhantomData ,
619
+ }
620
+ }
621
+
622
+ /// Makes a [`MappedMutexGuard`] for a component of the borrowed data. The
623
+ /// original guard is returned as an `Err(...)` if the closure returns
624
+ /// `None`.
625
+ ///
626
+ /// The `Mutex` is already locked, so this cannot fail.
627
+ ///
628
+ /// This is an associated function that needs to be used as
629
+ /// `MutexGuard::try_map(...)`. A method would interfere with methods of the
630
+ /// same name on the contents of the `MutexGuard` used through `Deref`.
631
+ #[ doc( alias = "filter_map" ) ]
632
+ #[ unstable( feature = "mapped_lock_guards" , issue = "none" ) ]
633
+ pub fn try_map < U , F > ( orig : Self , f : F ) -> Result < MappedMutexGuard < ' a , U > , Self >
634
+ where
635
+ F : FnOnce ( & mut T ) -> Option < & mut U > ,
636
+ U : ?Sized ,
637
+ {
638
+ let mut orig = ManuallyDrop :: new ( orig) ;
639
+ match f ( & mut * orig) . map ( NonNull :: from) {
640
+ Some ( value) => Ok ( MappedMutexGuard {
641
+ data : value,
642
+ inner : & orig. lock . inner ,
643
+ poison_flag : & orig. lock . poison ,
644
+ poison : orig. poison . clone ( ) ,
645
+ _variance : PhantomData ,
646
+ } ) ,
647
+ None => Err ( ManuallyDrop :: into_inner ( orig) ) ,
648
+ }
649
+ }
650
+ }
651
+
652
+ #[ unstable( feature = "mapped_lock_guards" , issue = "none" ) ]
653
+ impl < T : ?Sized > Deref for MappedMutexGuard < ' _ , T > {
654
+ type Target = T ;
655
+
656
+ fn deref ( & self ) -> & T {
657
+ unsafe { self . data . as_ref ( ) }
658
+ }
659
+ }
660
+
661
+ #[ unstable( feature = "mapped_lock_guards" , issue = "none" ) ]
662
+ impl < T : ?Sized > DerefMut for MappedMutexGuard < ' _ , T > {
663
+ fn deref_mut ( & mut self ) -> & mut T {
664
+ unsafe { self . data . as_mut ( ) }
665
+ }
666
+ }
667
+
668
+ #[ unstable( feature = "mapped_lock_guards" , issue = "none" ) ]
669
+ impl < T : ?Sized > Drop for MappedMutexGuard < ' _ , T > {
670
+ #[ inline]
671
+ fn drop ( & mut self ) {
672
+ unsafe {
673
+ self . poison_flag . done ( & self . poison ) ;
674
+ self . inner . unlock ( ) ;
675
+ }
676
+ }
677
+ }
678
+
679
+ #[ unstable( feature = "mapped_lock_guards" , issue = "none" ) ]
680
+ impl < T : ?Sized + fmt:: Debug > fmt:: Debug for MappedMutexGuard < ' _ , T > {
681
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
682
+ fmt:: Debug :: fmt ( & * * self , f)
683
+ }
684
+ }
685
+
686
+ #[ unstable( feature = "mapped_lock_guards" , issue = "none" ) ]
687
+ impl < T : ?Sized + fmt:: Display > fmt:: Display for MappedMutexGuard < ' _ , T > {
688
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
689
+ ( * * self ) . fmt ( f)
690
+ }
691
+ }
692
+
693
+ impl < ' a , T : ?Sized > MappedMutexGuard < ' a , T > {
694
+ /// Makes a [`MappedMutexGuard`] for a component of the borrowed data, e.g.
695
+ /// an enum variant.
696
+ ///
697
+ /// The `Mutex` is already locked, so this cannot fail.
698
+ ///
699
+ /// This is an associated function that needs to be used as
700
+ /// `MutexGuard::map(...)`. A method would interfere with methods of the
701
+ /// same name on the contents of the `MutexGuard` used through `Deref`.
702
+ #[ unstable( feature = "mapped_lock_guards" , issue = "none" ) ]
703
+ pub fn map < U , F > ( orig : Self , f : F ) -> MappedMutexGuard < ' a , U >
704
+ where
705
+ F : FnOnce ( & mut T ) -> & mut U ,
706
+ U : ?Sized ,
707
+ {
708
+ let mut orig = ManuallyDrop :: new ( orig) ;
709
+ let value = NonNull :: from ( f ( & mut * orig) ) ;
710
+ MappedMutexGuard {
711
+ data : value,
712
+ inner : orig. inner ,
713
+ poison_flag : orig. poison_flag ,
714
+ poison : orig. poison . clone ( ) ,
715
+ _variance : PhantomData ,
716
+ }
717
+ }
718
+
719
+ /// Makes a [`MappedMutexGuard`] for a component of the borrowed data. The
720
+ /// original guard is returned as an `Err(...)` if the closure returns
721
+ /// `None`.
722
+ ///
723
+ /// The `Mutex` is already locked, so this cannot fail.
724
+ ///
725
+ /// This is an associated function that needs to be used as
726
+ /// `MutexGuard::try_map(...)`. A method would interfere with methods of the
727
+ /// same name on the contents of the `MutexGuard` used through `Deref`.
728
+ #[ doc( alias = "filter_map" ) ]
729
+ #[ unstable( feature = "mapped_lock_guards" , issue = "none" ) ]
730
+ pub fn try_map < U , F > ( orig : Self , f : F ) -> Result < MappedMutexGuard < ' a , U > , Self >
731
+ where
732
+ F : FnOnce ( & mut T ) -> Option < & mut U > ,
733
+ U : ?Sized ,
734
+ {
735
+ let mut orig = ManuallyDrop :: new ( orig) ;
736
+ match f ( & mut * orig) . map ( NonNull :: from) {
737
+ Some ( value) => Ok ( MappedMutexGuard {
738
+ data : value,
739
+ inner : orig. inner ,
740
+ poison_flag : orig. poison_flag ,
741
+ poison : orig. poison . clone ( ) ,
742
+ _variance : PhantomData ,
743
+ } ) ,
744
+ None => Err ( ManuallyDrop :: into_inner ( orig) ) ,
745
+ }
746
+ }
747
+ }
0 commit comments