@@ -3,7 +3,10 @@ mod tests;
33
44use crate :: cell:: UnsafeCell ;
55use crate :: fmt;
6+ use crate :: marker:: PhantomData ;
7+ use crate :: mem:: ManuallyDrop ;
68use crate :: ops:: { Deref , DerefMut } ;
9+ use crate :: ptr:: NonNull ;
710use crate :: sync:: { poison, LockResult , TryLockError , TryLockResult } ;
811use crate :: sys:: locks as sys;
912
@@ -213,6 +216,43 @@ impl<T: ?Sized> !Send for MutexGuard<'_, T> {}
213216#[ stable( feature = "mutexguard" , since = "1.19.0" ) ]
214217unsafe impl < T : ?Sized + Sync > Sync for MutexGuard < ' _ , T > { }
215218
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+
216256impl < T > Mutex < T > {
217257 /// Creates a new mutex in an unlocked state ready for use.
218258 ///
@@ -552,3 +592,156 @@ pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex {
552592pub fn guard_poison < ' a , T : ?Sized > ( guard : & MutexGuard < ' a , T > ) -> & ' a poison:: Flag {
553593 & guard. lock . poison
554594}
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