mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-02 03:33:59 +00:00
Implmement MappedRwLock(Read|Write)Guard
.
This commit is contained in:
parent
9be1321676
commit
ea97c1f2dc
@ -3,6 +3,8 @@ mod tests;
|
||||
|
||||
use crate::cell::UnsafeCell;
|
||||
use crate::fmt;
|
||||
use crate::marker::PhantomData;
|
||||
use crate::mem::ManuallyDrop;
|
||||
use crate::ops::{Deref, DerefMut};
|
||||
use crate::ptr::NonNull;
|
||||
use crate::sync::{poison, LockResult, TryLockError, TryLockResult};
|
||||
@ -105,7 +107,7 @@ unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {}
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "RwLockReadGuard")]
|
||||
pub struct RwLockReadGuard<'a, T: ?Sized + 'a> {
|
||||
// NB: we use a pointer instead of `&'a T` to avoid `noalias` violations, because a
|
||||
// `Ref` argument doesn't hold immutability for its whole scope, only until it drops.
|
||||
// `RwLockReadGuard` argument doesn't hold immutability for its whole scope, only until it drops.
|
||||
// `NonNull` is also covariant over `T`, just like we would have with `&T`. `NonNull`
|
||||
// is preferable over `const* T` to allow for niche optimization.
|
||||
data: NonNull<T>,
|
||||
@ -144,6 +146,63 @@ impl<T: ?Sized> !Send for RwLockWriteGuard<'_, T> {}
|
||||
#[stable(feature = "rwlock_guard_sync", since = "1.23.0")]
|
||||
unsafe impl<T: ?Sized + Sync> Sync for RwLockWriteGuard<'_, T> {}
|
||||
|
||||
/// RAII structure used to release the shared read access of a lock when
|
||||
/// dropped, which can point to a subfield of the protected data.
|
||||
///
|
||||
/// This structure is created by the [`map`] and [`try_map`] methods
|
||||
/// on [`RwLockReadGuard`].
|
||||
///
|
||||
/// [`map`]: RwLockReadGuard::map
|
||||
/// [`try_map`]: RwLockReadGuard::try_map
|
||||
#[must_use = "if unused the RwLock will immediately unlock"]
|
||||
#[must_not_suspend = "holding a MappedRwLockReadGuard across suspend \
|
||||
points can cause deadlocks, delays, \
|
||||
and cause Futures to not implement `Send`"]
|
||||
#[unstable(feature = "mapped_lock_guards", issue = "none")]
|
||||
#[clippy::has_significant_drop]
|
||||
pub struct MappedRwLockReadGuard<'a, T: ?Sized + 'a> {
|
||||
// NB: we use a pointer instead of `&'a T` to avoid `noalias` violations, because a
|
||||
// `MappedRwLockReadGuard` argument doesn't hold immutability for its whole scope, only until it drops.
|
||||
// `NonNull` is also covariant over `T`, just like we would have with `&T`. `NonNull`
|
||||
// is preferable over `const* T` to allow for niche optimization.
|
||||
data: NonNull<T>,
|
||||
inner_lock: &'a sys::RwLock,
|
||||
}
|
||||
|
||||
#[unstable(feature = "mapped_lock_guards", issue = "none")]
|
||||
impl<T: ?Sized> !Send for MappedRwLockReadGuard<'_, T> {}
|
||||
|
||||
#[unstable(feature = "mapped_lock_guards", issue = "none")]
|
||||
unsafe impl<T: ?Sized + Sync> Sync for MappedRwLockReadGuard<'_, T> {}
|
||||
|
||||
/// RAII structure used to release the exclusive write access of a lock when
|
||||
/// dropped, which can point to a subfield of the protected data.
|
||||
///
|
||||
/// This structure is created by the [`map`] and [`try_map`] methods
|
||||
/// on [`RwLockWriteGuard`].
|
||||
///
|
||||
/// [`map`]: RwLockWriteGuard::map
|
||||
/// [`try_map`]: RwLockWriteGuard::try_map
|
||||
#[must_use = "if unused the RwLock will immediately unlock"]
|
||||
#[must_not_suspend = "holding a MappedRwLockWriteGuard across suspend \
|
||||
points can cause deadlocks, delays, \
|
||||
and cause Future's to not implement `Send`"]
|
||||
#[unstable(feature = "mapped_lock_guards", issue = "none")]
|
||||
#[clippy::has_significant_drop]
|
||||
pub struct MappedRwLockWriteGuard<'a, T: ?Sized + 'a> {
|
||||
data: NonNull<T>,
|
||||
inner_lock: &'a sys::RwLock,
|
||||
poison_flag: &'a poison::Flag,
|
||||
poison: poison::Guard,
|
||||
_variance: PhantomData<&'a mut T>,
|
||||
}
|
||||
|
||||
#[unstable(feature = "mapped_lock_guards", issue = "none")]
|
||||
impl<T: ?Sized> !Send for MappedRwLockWriteGuard<'_, T> {}
|
||||
|
||||
#[unstable(feature = "mapped_lock_guards", issue = "none")]
|
||||
unsafe impl<T: ?Sized + Sync> Sync for MappedRwLockWriteGuard<'_, T> {}
|
||||
|
||||
impl<T> RwLock<T> {
|
||||
/// Creates a new instance of an `RwLock<T>` which is unlocked.
|
||||
///
|
||||
@ -527,7 +586,10 @@ impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> {
|
||||
// SAFETY: if and only if `lock.inner.write()` (or `lock.inner.try_write()`) has been
|
||||
// successfully called from the same thread before instantiating this object.
|
||||
unsafe fn new(lock: &'rwlock RwLock<T>) -> LockResult<RwLockWriteGuard<'rwlock, T>> {
|
||||
poison::map_result(lock.poison.guard(), |guard| RwLockWriteGuard { lock, poison: guard })
|
||||
poison::map_result(lock.poison.guard(), |guard| RwLockWriteGuard {
|
||||
lock,
|
||||
poison: guard,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -559,12 +621,40 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RwLockWriteGuard<'_, T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "mapped_lock_guards", issue = "none")]
|
||||
impl<T: ?Sized + fmt::Debug> fmt::Debug for MappedRwLockReadGuard<'_, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
(**self).fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "mapped_lock_guards", issue = "none")]
|
||||
impl<T: ?Sized + fmt::Display> fmt::Display for MappedRwLockReadGuard<'_, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
(**self).fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "mapped_lock_guards", issue = "none")]
|
||||
impl<T: ?Sized + fmt::Debug> fmt::Debug for MappedRwLockWriteGuard<'_, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
(**self).fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "mapped_lock_guards", issue = "none")]
|
||||
impl<T: ?Sized + fmt::Display> fmt::Display for MappedRwLockWriteGuard<'_, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
(**self).fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Deref for RwLockReadGuard<'_, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
// SAFETY: the conditions of `RwLockGuard::new` were satisfied when created.
|
||||
// SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when created.
|
||||
unsafe { self.data.as_ref() }
|
||||
}
|
||||
}
|
||||
@ -587,6 +677,37 @@ impl<T: ?Sized> DerefMut for RwLockWriteGuard<'_, T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "mapped_lock_guards", issue = "none")]
|
||||
impl<T: ?Sized> Deref for MappedRwLockReadGuard<'_, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
// SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard
|
||||
// was created, and have been upheld throughout `map` and/or `try_map`.
|
||||
unsafe { self.data.as_ref() }
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "mapped_lock_guards", issue = "none")]
|
||||
impl<T: ?Sized> Deref for MappedRwLockWriteGuard<'_, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
// SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard
|
||||
// was created, and have been upheld throughout `map` and/or `try_map`.
|
||||
unsafe { self.data.as_ref() }
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "mapped_lock_guards", issue = "none")]
|
||||
impl<T: ?Sized> DerefMut for MappedRwLockWriteGuard<'_, T> {
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
// SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard
|
||||
// was created, and have been upheld throughout `map` and/or `try_map`.
|
||||
unsafe { self.data.as_mut() }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Drop for RwLockReadGuard<'_, T> {
|
||||
fn drop(&mut self) {
|
||||
@ -607,3 +728,234 @@ impl<T: ?Sized> Drop for RwLockWriteGuard<'_, T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "mapped_lock_guards", issue = "none")]
|
||||
impl<T: ?Sized> Drop for MappedRwLockReadGuard<'_, T> {
|
||||
fn drop(&mut self) {
|
||||
// SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard
|
||||
// was created, and have been upheld throughout `map` and/or `try_map`.
|
||||
unsafe {
|
||||
self.inner_lock.read_unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "mapped_lock_guards", issue = "none")]
|
||||
impl<T: ?Sized> Drop for MappedRwLockWriteGuard<'_, T> {
|
||||
fn drop(&mut self) {
|
||||
self.poison_flag.done(&self.poison);
|
||||
// SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard
|
||||
// was created, and have been upheld throughout `map` and/or `try_map`.
|
||||
unsafe {
|
||||
self.inner_lock.write_unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized> RwLockReadGuard<'a, T> {
|
||||
/// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data, e.g.
|
||||
/// an enum variant.
|
||||
///
|
||||
/// The `RwLock` is already locked for reading, so this cannot fail.
|
||||
///
|
||||
/// This is an associated function that needs to be used as
|
||||
/// `RwLockReadGuard::map(...)`. A method would interfere with methods of
|
||||
/// the same name on the contents of the `RwLockReadGuard` used through
|
||||
/// `Deref`.
|
||||
#[unstable(feature = "mapped_lock_guards", issue = "none")]
|
||||
pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockReadGuard<'a, U>
|
||||
where
|
||||
F: FnOnce(&T) -> &U,
|
||||
U: ?Sized,
|
||||
{
|
||||
let orig = ManuallyDrop::new(orig);
|
||||
let value = NonNull::from(f(&*orig));
|
||||
MappedRwLockReadGuard { data: value, inner_lock: &orig.inner_lock }
|
||||
}
|
||||
|
||||
/// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data. The
|
||||
/// original guard is returned as an `Err(...)` if the closure returns
|
||||
/// `None`.
|
||||
///
|
||||
/// The `RwLock` is already locked for reading, so this cannot fail.
|
||||
///
|
||||
/// This is an associated function that needs to be used as
|
||||
/// `RwLockReadGuard::try_map(...)`. A method would interfere with methods
|
||||
/// of the same name on the contents of the `RwLockReadGuard` used through
|
||||
/// `Deref`.
|
||||
#[doc(alias = "filter_map")]
|
||||
#[unstable(feature = "mapped_lock_guards", issue = "none")]
|
||||
pub fn try_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockReadGuard<'a, U>, Self>
|
||||
where
|
||||
F: FnOnce(&T) -> Option<&U>,
|
||||
U: ?Sized,
|
||||
{
|
||||
let orig = ManuallyDrop::new(orig);
|
||||
match f(&*orig).map(NonNull::from) {
|
||||
Some(value) => Ok(MappedRwLockReadGuard { data: value, inner_lock: &orig.inner_lock }),
|
||||
None => Err(ManuallyDrop::into_inner(orig)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized> MappedRwLockReadGuard<'a, T> {
|
||||
/// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data,
|
||||
/// e.g. an enum variant.
|
||||
///
|
||||
/// The `RwLock` is already locked for reading, so this cannot fail.
|
||||
///
|
||||
/// This is an associated function that needs to be used as
|
||||
/// `MappedRwLockReadGuard::map(...)`. A method would interfere with
|
||||
/// methods of the same name on the contents of the `MappedRwLockReadGuard`
|
||||
/// used through `Deref`.
|
||||
#[unstable(feature = "mapped_lock_guards", issue = "none")]
|
||||
pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockReadGuard<'a, U>
|
||||
where
|
||||
F: FnOnce(&T) -> &U,
|
||||
U: ?Sized,
|
||||
{
|
||||
let orig = ManuallyDrop::new(orig);
|
||||
let value = NonNull::from(f(&*orig));
|
||||
MappedRwLockReadGuard { data: value, inner_lock: &orig.inner_lock }
|
||||
}
|
||||
|
||||
/// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data.
|
||||
/// The original guard is returned as an `Err(...)` if the closure returns
|
||||
/// `None`.
|
||||
///
|
||||
/// The `RwLock` is already locked for reading, so this cannot fail.
|
||||
///
|
||||
/// This is an associated function that needs to be used as
|
||||
/// `MappedRwLockReadGuard::try_map(...)`. A method would interfere with
|
||||
/// methods of the same name on the contents of the `MappedRwLockReadGuard`
|
||||
/// used through `Deref`.
|
||||
#[doc(alias = "filter_map")]
|
||||
#[unstable(feature = "mapped_lock_guards", issue = "none")]
|
||||
pub fn try_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockReadGuard<'a, U>, Self>
|
||||
where
|
||||
F: FnOnce(&T) -> Option<&U>,
|
||||
U: ?Sized,
|
||||
{
|
||||
let orig = ManuallyDrop::new(orig);
|
||||
match f(&*orig).map(NonNull::from) {
|
||||
Some(value) => Ok(MappedRwLockReadGuard { data: value, inner_lock: &orig.inner_lock }),
|
||||
None => Err(ManuallyDrop::into_inner(orig)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> {
|
||||
/// Makes a [`MappedRwLockWriteGuard`] for a component of the borrowed data, e.g.
|
||||
/// an enum variant.
|
||||
///
|
||||
/// The `RwLock` is already locked for writing, so this cannot fail.
|
||||
///
|
||||
/// This is an associated function that needs to be used as
|
||||
/// `RwLockWriteGuard::map(...)`. A method would interfere with methods of
|
||||
/// the same name on the contents of the `RwLockWriteGuard` used through
|
||||
/// `Deref`.
|
||||
#[unstable(feature = "mapped_lock_guards", issue = "none")]
|
||||
pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockWriteGuard<'a, U>
|
||||
where
|
||||
F: FnOnce(&mut T) -> &mut U,
|
||||
U: ?Sized,
|
||||
{
|
||||
let mut orig = ManuallyDrop::new(orig);
|
||||
let value = NonNull::from(f(&mut *orig));
|
||||
MappedRwLockWriteGuard {
|
||||
data: value,
|
||||
inner_lock: &orig.lock.inner,
|
||||
poison_flag: &orig.lock.poison,
|
||||
poison: orig.poison.clone(),
|
||||
_variance: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Makes a [`MappedRwLockWriteGuard`] for a component of the borrowed data. The
|
||||
/// original guard is returned as an `Err(...)` if the closure returns
|
||||
/// `None`.
|
||||
///
|
||||
/// The `RwLock` is already locked for writing, so this cannot fail.
|
||||
///
|
||||
/// This is an associated function that needs to be used as
|
||||
/// `RwLockWriteGuard::try_map(...)`. A method would interfere with methods
|
||||
/// of the same name on the contents of the `RwLockWriteGuard` used through
|
||||
/// `Deref`.
|
||||
#[doc(alias = "filter_map")]
|
||||
#[unstable(feature = "mapped_lock_guards", issue = "none")]
|
||||
pub fn try_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockWriteGuard<'a, U>, Self>
|
||||
where
|
||||
F: FnOnce(&mut T) -> Option<&mut U>,
|
||||
U: ?Sized,
|
||||
{
|
||||
let mut orig = ManuallyDrop::new(orig);
|
||||
match f(&mut *orig).map(NonNull::from) {
|
||||
Some(value) => Ok(MappedRwLockWriteGuard {
|
||||
data: value,
|
||||
inner_lock: &orig.lock.inner,
|
||||
poison_flag: &orig.lock.poison,
|
||||
poison: orig.poison.clone(),
|
||||
_variance: PhantomData,
|
||||
}),
|
||||
None => Err(ManuallyDrop::into_inner(orig)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized> MappedRwLockWriteGuard<'a, T> {
|
||||
/// Makes a [`MappedRwLockWriteGuard`] for a component of the borrowed data,
|
||||
/// e.g. an enum variant.
|
||||
///
|
||||
/// The `RwLock` is already locked for writing, so this cannot fail.
|
||||
///
|
||||
/// This is an associated function that needs to be used as
|
||||
/// `MappedRwLockWriteGuard::map(...)`. A method would interfere with
|
||||
/// methods of the same name on the contents of the `MappedRwLockWriteGuard`
|
||||
/// used through `Deref`.
|
||||
#[unstable(feature = "mapped_lock_guards", issue = "none")]
|
||||
pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockWriteGuard<'a, U>
|
||||
where
|
||||
F: FnOnce(&mut T) -> &mut U,
|
||||
U: ?Sized,
|
||||
{
|
||||
let mut orig = ManuallyDrop::new(orig);
|
||||
let value = NonNull::from(f(&mut *orig));
|
||||
MappedRwLockWriteGuard {
|
||||
data: value,
|
||||
inner_lock: orig.inner_lock,
|
||||
poison_flag: orig.poison_flag,
|
||||
poison: orig.poison.clone(),
|
||||
_variance: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Makes a [`MappedRwLockWriteGuard`] for a component of the borrowed data.
|
||||
/// The original guard is returned as an `Err(...)` if the closure returns
|
||||
/// `None`.
|
||||
///
|
||||
/// The `RwLock` is already locked for writing, so this cannot fail.
|
||||
///
|
||||
/// This is an associated function that needs to be used as
|
||||
/// `MappedRwLockWriteGuard::try_map(...)`. A method would interfere with
|
||||
/// methods of the same name on the contents of the `MappedRwLockWriteGuard`
|
||||
/// used through `Deref`.
|
||||
#[doc(alias = "filter_map")]
|
||||
#[unstable(feature = "mapped_lock_guards", issue = "none")]
|
||||
pub fn try_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockWriteGuard<'a, U>, Self>
|
||||
where
|
||||
F: FnOnce(&mut T) -> Option<&mut U>,
|
||||
U: ?Sized,
|
||||
{
|
||||
let mut orig = ManuallyDrop::new(orig);
|
||||
match f(&mut *orig).map(NonNull::from) {
|
||||
Some(value) => Ok(MappedRwLockWriteGuard {
|
||||
data: value,
|
||||
inner_lock: orig.inner_lock,
|
||||
poison_flag: orig.poison_flag,
|
||||
poison: orig.poison.clone(),
|
||||
_variance: PhantomData,
|
||||
}),
|
||||
None => Err(ManuallyDrop::into_inner(orig)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user