Skip to content

Commit 9be1321

Browse files
committed
Implement MappedMutexGuard.
1 parent f842d7b commit 9be1321

1 file changed

Lines changed: 193 additions & 0 deletions

File tree

‎library/std/src/sync/mutex.rs‎

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ mod tests;
33

44
usecrate::cell::UnsafeCell;
55
usecrate::fmt;
6+
usecrate::marker::PhantomData;
7+
usecrate::mem::ManuallyDrop;
68
usecrate::ops::{Deref,DerefMut};
9+
usecrate::ptr::NonNull;
710
usecrate::sync::{poison,LockResult,TryLockError,TryLockResult};
811
usecrate::sys::locks as sys;
912

@@ -213,6 +216,43 @@ impl<T: ?Sized> !Send for MutexGuard<'_, T> {}
213216
#[stable(feature = "mutexguard", since = "1.19.0")]
214217
unsafeimpl<T: ?Sized + Sync>SyncforMutexGuard<'_,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+
pubstructMappedMutexGuard<'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<&'amutT>,
249+
}
250+
251+
#[unstable(feature = "mapped_lock_guards", issue = "none")]
252+
impl<T: ?Sized> !SendforMappedMutexGuard<'_,T>{}
253+
#[unstable(feature = "mapped_lock_guards", issue = "none")]
254+
unsafeimpl<T: ?Sized + Sync>SyncforMappedMutexGuard<'_,T>{}
255+
216256
impl<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 {
552592
pubfnguard_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+
pubfnmap<U,F>(orig:Self,f:F) -> MappedMutexGuard<'a,U>
607+
where
608+
F:FnOnce(&mutT) -> &mutU,
609+
U: ?Sized,
610+
{
611+
letmut 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+
pubfntry_map<U,F>(orig:Self,f:F) -> Result<MappedMutexGuard<'a,U>,Self>
634+
where
635+
F:FnOnce(&mutT) -> Option<&mutU>,
636+
U: ?Sized,
637+
{
638+
letmut orig = ManuallyDrop::new(orig);
639+
matchf(&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>DerefforMappedMutexGuard<'_,T>{
654+
typeTarget = T;
655+
656+
fnderef(&self) -> &T{
657+
unsafe{self.data.as_ref()}
658+
}
659+
}
660+
661+
#[unstable(feature = "mapped_lock_guards", issue = "none")]
662+
impl<T: ?Sized>DerefMutforMappedMutexGuard<'_,T>{
663+
fnderef_mut(&mutself) -> &mutT{
664+
unsafe{self.data.as_mut()}
665+
}
666+
}
667+
668+
#[unstable(feature = "mapped_lock_guards", issue = "none")]
669+
impl<T: ?Sized>DropforMappedMutexGuard<'_,T>{
670+
#[inline]
671+
fndrop(&mutself){
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::DebugforMappedMutexGuard<'_,T>{
681+
fnfmt(&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::DisplayforMappedMutexGuard<'_,T>{
688+
fnfmt(&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+
pubfnmap<U,F>(orig:Self,f:F) -> MappedMutexGuard<'a,U>
704+
where
705+
F:FnOnce(&mutT) -> &mutU,
706+
U: ?Sized,
707+
{
708+
letmut 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+
pubfntry_map<U,F>(orig:Self,f:F) -> Result<MappedMutexGuard<'a,U>,Self>
731+
where
732+
F:FnOnce(&mutT) -> Option<&mutU>,
733+
U: ?Sized,
734+
{
735+
letmut orig = ManuallyDrop::new(orig);
736+
matchf(&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

Comments
 (0)