Specify behavior if the closure passed to *Guard::*map panics.

This commit is contained in:
Zachary S
2023-10-26 13:33:54 -05:00
parent 6aebcbee0a
commit 3ef4b083ac
4 changed files with 364 additions and 69 deletions

View File

@@ -612,10 +612,14 @@ impl<'a, T: ?Sized> MutexGuard<'a, T> {
F: FnOnce(&mut T) -> &mut U,
U: ?Sized,
{
let mut orig = ManuallyDrop::new(orig);
let value = NonNull::from(f(&mut *orig));
// SAFETY: the conditions of `MutedGuard::new` were satisfied when the original guard
// was created, and have been upheld throughout `map` and/or `try_map`.
// The signature of the closure guarantees that it will not "leak" the lifetime of the reference
// passed to it. If the closure panics, the guard will be dropped.
let data = NonNull::from(f(unsafe { &mut *orig.lock.data.get() }));
let orig = ManuallyDrop::new(orig);
MappedMutexGuard {
data: value,
data,
inner: &orig.lock.inner,
poison_flag: &orig.lock.poison,
poison: orig.poison.clone(),
@@ -639,16 +643,23 @@ impl<'a, T: ?Sized> MutexGuard<'a, T> {
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(MappedMutexGuard {
data: value,
inner: &orig.lock.inner,
poison_flag: &orig.lock.poison,
poison: orig.poison.clone(),
_variance: PhantomData,
}),
None => Err(ManuallyDrop::into_inner(orig)),
// SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard
// was created, and have been upheld throughout `map` and/or `try_map`.
// The signature of the closure guarantees that it will not "leak" the lifetime of the reference
// passed to it. If the closure panics, the guard will be dropped.
match f(unsafe { &mut *orig.lock.data.get() }) {
Some(data) => {
let data = NonNull::from(data);
let orig = ManuallyDrop::new(orig);
Ok(MappedMutexGuard {
data,
inner: &orig.lock.inner,
poison_flag: &orig.lock.poison,
poison: orig.poison.clone(),
_variance: PhantomData,
})
}
None => Err(orig),
}
}
}
@@ -704,15 +715,19 @@ impl<'a, T: ?Sized> MappedMutexGuard<'a, T> {
/// `MappedMutexGuard::map(...)`. A method would interfere with methods of the
/// same name on the contents of the `MutexGuard` used through `Deref`.
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
pub fn map<U, F>(orig: Self, f: F) -> MappedMutexGuard<'a, U>
pub fn map<U, F>(mut orig: Self, f: F) -> MappedMutexGuard<'a, U>
where
F: FnOnce(&mut T) -> &mut U,
U: ?Sized,
{
let mut orig = ManuallyDrop::new(orig);
let value = NonNull::from(f(&mut *orig));
// SAFETY: the conditions of `MutedGuard::new` were satisfied when the original guard
// was created, and have been upheld throughout `map` and/or `try_map`.
// The signature of the closure guarantees that it will not "leak" the lifetime of the reference
// passed to it. If the closure panics, the guard will be dropped.
let data = NonNull::from(f(unsafe { orig.data.as_mut() }));
let orig = ManuallyDrop::new(orig);
MappedMutexGuard {
data: value,
data,
inner: orig.inner,
poison_flag: orig.poison_flag,
poison: orig.poison.clone(),
@@ -731,21 +746,28 @@ impl<'a, T: ?Sized> MappedMutexGuard<'a, T> {
/// same name on the contents of the `MutexGuard` used through `Deref`.
#[doc(alias = "filter_map")]
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
pub fn try_map<U, F>(orig: Self, f: F) -> Result<MappedMutexGuard<'a, U>, Self>
pub fn try_map<U, F>(mut orig: Self, f: F) -> Result<MappedMutexGuard<'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(MappedMutexGuard {
data: value,
inner: orig.inner,
poison_flag: orig.poison_flag,
poison: orig.poison.clone(),
_variance: PhantomData,
}),
None => Err(ManuallyDrop::into_inner(orig)),
// SAFETY: the conditions of `MutedGuard::new` were satisfied when the original guard
// was created, and have been upheld throughout `map` and/or `try_map`.
// The signature of the closure guarantees that it will not "leak" the lifetime of the reference
// passed to it. If the closure panics, the guard will be dropped.
match f(unsafe { orig.data.as_mut() }) {
Some(data) => {
let data = NonNull::from(data);
let orig = ManuallyDrop::new(orig);
Ok(MappedMutexGuard {
data,
inner: orig.inner,
poison_flag: orig.poison_flag,
poison: orig.poison.clone(),
_variance: PhantomData,
})
}
None => Err(orig),
}
}
}

View File

@@ -1,6 +1,6 @@
use crate::sync::atomic::{AtomicUsize, Ordering};
use crate::sync::mpsc::channel;
use crate::sync::{Arc, Condvar, MappedMutexGuard, Mutex, MutexGuard};
use crate::sync::{Arc, Condvar, MappedMutexGuard, Mutex, MutexGuard, TryLockError};
use crate::thread;
struct Packet<T>(Arc<(Mutex<T>, Condvar)>);
@@ -264,3 +264,64 @@ fn test_mapping_mapped_guard() {
drop(guard);
assert_eq!(*lock.get_mut().unwrap(), [0, 42, 0, 0]);
}
#[test]
fn panic_while_mapping_unlocked_poison() {
let lock = Mutex::new(());
let _ = crate::panic::catch_unwind(|| {
let guard = lock.lock().unwrap();
let _guard = MutexGuard::map::<(), _>(guard, |_| panic!());
});
match lock.try_lock() {
Ok(_) => panic!("panicking in a MutexGuard::map closure should poison the Mutex"),
Err(TryLockError::WouldBlock) => {
panic!("panicking in a MutexGuard::map closure should unlock the mutex")
}
Err(TryLockError::Poisoned(_)) => {}
}
let _ = crate::panic::catch_unwind(|| {
let guard = lock.lock().unwrap();
let _guard = MutexGuard::try_map::<(), _>(guard, |_| panic!());
});
match lock.try_lock() {
Ok(_) => panic!("panicking in a MutexGuard::try_map closure should poison the Mutex"),
Err(TryLockError::WouldBlock) => {
panic!("panicking in a MutexGuard::try_map closure should unlock the mutex")
}
Err(TryLockError::Poisoned(_)) => {}
}
let _ = crate::panic::catch_unwind(|| {
let guard = lock.lock().unwrap();
let guard = MutexGuard::map::<(), _>(guard, |val| val);
let _guard = MappedMutexGuard::map::<(), _>(guard, |_| panic!());
});
match lock.try_lock() {
Ok(_) => panic!("panicking in a MappedMutexGuard::map closure should poison the Mutex"),
Err(TryLockError::WouldBlock) => {
panic!("panicking in a MappedMutexGuard::map closure should unlock the mutex")
}
Err(TryLockError::Poisoned(_)) => {}
}
let _ = crate::panic::catch_unwind(|| {
let guard = lock.lock().unwrap();
let guard = MutexGuard::map::<(), _>(guard, |val| val);
let _guard = MappedMutexGuard::try_map::<(), _>(guard, |_| panic!());
});
match lock.try_lock() {
Ok(_) => panic!("panicking in a MappedMutexGuard::try_map closure should poison the Mutex"),
Err(TryLockError::WouldBlock) => {
panic!("panicking in a MappedMutexGuard::try_map closure should unlock the mutex")
}
Err(TryLockError::Poisoned(_)) => {}
}
drop(lock);
}

View File

@@ -766,15 +766,23 @@ impl<'a, T: ?Sized> RwLockReadGuard<'a, T> {
/// `RwLockReadGuard::map(...)`. A method would interfere with methods of
/// the same name on the contents of the `RwLockReadGuard` used through
/// `Deref`.
///
/// # Panics
///
/// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be poisoned.
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockReadGuard<'a, U>
where
F: FnOnce(&T) -> &U,
U: ?Sized,
{
// SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard
// was created, and have been upheld throughout `map` and/or `try_map`.
// The signature of the closure guarantees that it will not "leak" the lifetime of the reference
// passed to it. If the closure panics, the guard will be dropped.
let data = NonNull::from(f(unsafe { orig.data.as_ref() }));
let orig = ManuallyDrop::new(orig);
let value = NonNull::from(f(&*orig));
MappedRwLockReadGuard { data: value, inner_lock: &orig.inner_lock }
MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock }
}
/// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data. The
@@ -787,6 +795,10 @@ impl<'a, T: ?Sized> RwLockReadGuard<'a, T> {
/// `RwLockReadGuard::try_map(...)`. A method would interfere with methods
/// of the same name on the contents of the `RwLockReadGuard` used through
/// `Deref`.
///
/// # Panics
///
/// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be poisoned.
#[doc(alias = "filter_map")]
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
pub fn try_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockReadGuard<'a, U>, Self>
@@ -794,10 +806,17 @@ impl<'a, T: ?Sized> RwLockReadGuard<'a, T> {
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)),
// SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard
// was created, and have been upheld throughout `map` and/or `try_map`.
// The signature of the closure guarantees that it will not "leak" the lifetime of the reference
// passed to it. If the closure panics, the guard will be dropped.
match f(unsafe { orig.data.as_ref() }) {
Some(data) => {
let data = NonNull::from(data);
let orig = ManuallyDrop::new(orig);
Ok(MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock })
}
None => Err(orig),
}
}
}
@@ -812,15 +831,23 @@ impl<'a, T: ?Sized> MappedRwLockReadGuard<'a, T> {
/// `MappedRwLockReadGuard::map(...)`. A method would interfere with
/// methods of the same name on the contents of the `MappedRwLockReadGuard`
/// used through `Deref`.
///
/// # Panics
///
/// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be poisoned.
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockReadGuard<'a, U>
where
F: FnOnce(&T) -> &U,
U: ?Sized,
{
// SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard
// was created, and have been upheld throughout `map` and/or `try_map`.
// The signature of the closure guarantees that it will not "leak" the lifetime of the reference
// passed to it. If the closure panics, the guard will be dropped.
let data = NonNull::from(f(unsafe { orig.data.as_ref() }));
let orig = ManuallyDrop::new(orig);
let value = NonNull::from(f(&*orig));
MappedRwLockReadGuard { data: value, inner_lock: &orig.inner_lock }
MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock }
}
/// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data.
@@ -833,6 +860,10 @@ impl<'a, T: ?Sized> MappedRwLockReadGuard<'a, T> {
/// `MappedRwLockReadGuard::try_map(...)`. A method would interfere with
/// methods of the same name on the contents of the `MappedRwLockReadGuard`
/// used through `Deref`.
///
/// # Panics
///
/// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be poisoned.
#[doc(alias = "filter_map")]
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
pub fn try_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockReadGuard<'a, U>, Self>
@@ -840,10 +871,17 @@ impl<'a, T: ?Sized> MappedRwLockReadGuard<'a, T> {
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)),
// SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard
// was created, and have been upheld throughout `map` and/or `try_map`.
// The signature of the closure guarantees that it will not "leak" the lifetime of the reference
// passed to it. If the closure panics, the guard will be dropped.
match f(unsafe { orig.data.as_ref() }) {
Some(data) => {
let data = NonNull::from(data);
let orig = ManuallyDrop::new(orig);
Ok(MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock })
}
None => Err(orig),
}
}
}
@@ -858,16 +896,24 @@ impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> {
/// `RwLockWriteGuard::map(...)`. A method would interfere with methods of
/// the same name on the contents of the `RwLockWriteGuard` used through
/// `Deref`.
///
/// # Panics
///
/// If the closure panics, the guard will be dropped (unlocked) and the RwLock will be poisoned.
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
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));
// SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard
// was created, and have been upheld throughout `map` and/or `try_map`.
// The signature of the closure guarantees that it will not "leak" the lifetime of the reference
// passed to it. If the closure panics, the guard will be dropped.
let data = NonNull::from(f(unsafe { &mut *orig.lock.data.get() }));
let orig = ManuallyDrop::new(orig);
MappedRwLockWriteGuard {
data: value,
data,
inner_lock: &orig.lock.inner,
poison_flag: &orig.lock.poison,
poison: orig.poison.clone(),
@@ -885,6 +931,10 @@ impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> {
/// `RwLockWriteGuard::try_map(...)`. A method would interfere with methods
/// of the same name on the contents of the `RwLockWriteGuard` used through
/// `Deref`.
///
/// # Panics
///
/// If the closure panics, the guard will be dropped (unlocked) and the RwLock will be poisoned.
#[doc(alias = "filter_map")]
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
pub fn try_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockWriteGuard<'a, U>, Self>
@@ -892,16 +942,23 @@ impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> {
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)),
// SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard
// was created, and have been upheld throughout `map` and/or `try_map`.
// The signature of the closure guarantees that it will not "leak" the lifetime of the reference
// passed to it. If the closure panics, the guard will be dropped.
match f(unsafe { &mut *orig.lock.data.get() }) {
Some(data) => {
let data = NonNull::from(data);
let orig = ManuallyDrop::new(orig);
Ok(MappedRwLockWriteGuard {
data,
inner_lock: &orig.lock.inner,
poison_flag: &orig.lock.poison,
poison: orig.poison.clone(),
_variance: PhantomData,
})
}
None => Err(orig),
}
}
}
@@ -916,16 +973,24 @@ impl<'a, T: ?Sized> MappedRwLockWriteGuard<'a, T> {
/// `MappedRwLockWriteGuard::map(...)`. A method would interfere with
/// methods of the same name on the contents of the `MappedRwLockWriteGuard`
/// used through `Deref`.
///
/// # Panics
///
/// If the closure panics, the guard will be dropped (unlocked) and the RwLock will be poisoned.
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockWriteGuard<'a, U>
pub fn map<U, F>(mut 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));
// SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard
// was created, and have been upheld throughout `map` and/or `try_map`.
// The signature of the closure guarantees that it will not "leak" the lifetime of the reference
// passed to it. If the closure panics, the guard will be dropped.
let data = NonNull::from(f(unsafe { orig.data.as_mut() }));
let orig = ManuallyDrop::new(orig);
MappedRwLockWriteGuard {
data: value,
data,
inner_lock: orig.inner_lock,
poison_flag: orig.poison_flag,
poison: orig.poison.clone(),
@@ -943,23 +1008,34 @@ impl<'a, T: ?Sized> MappedRwLockWriteGuard<'a, T> {
/// `MappedRwLockWriteGuard::try_map(...)`. A method would interfere with
/// methods of the same name on the contents of the `MappedRwLockWriteGuard`
/// used through `Deref`.
///
/// # Panics
///
/// If the closure panics, the guard will be dropped (unlocked) and the RwLock will be poisoned.
#[doc(alias = "filter_map")]
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
pub fn try_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockWriteGuard<'a, U>, Self>
pub fn try_map<U, F>(mut 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)),
// SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard
// was created, and have been upheld throughout `map` and/or `try_map`.
// The signature of the closure guarantees that it will not "leak" the lifetime of the reference
// passed to it. If the closure panics, the guard will be dropped.
match f(unsafe { orig.data.as_mut() }) {
Some(data) => {
let data = NonNull::from(data);
let orig = ManuallyDrop::new(orig);
Ok(MappedRwLockWriteGuard {
data,
inner_lock: orig.inner_lock,
poison_flag: orig.poison_flag,
poison: orig.poison.clone(),
_variance: PhantomData,
})
}
None => Err(orig),
}
}
}

View File

@@ -360,3 +360,139 @@ fn test_mapping_mapped_guard() {
drop(guard);
assert_eq!(*lock.get_mut().unwrap(), [0, 42, 0, 0]);
}
#[test]
fn panic_while_mapping_read_unlocked_no_poison() {
let lock = RwLock::new(());
let _ = crate::panic::catch_unwind(|| {
let guard = lock.read().unwrap();
let _guard = RwLockReadGuard::map::<(), _>(guard, |_| panic!());
});
match lock.try_write() {
Ok(_) => {}
Err(TryLockError::WouldBlock) => {
panic!("panicking in a RwLockReadGuard::map closure should release the read lock")
}
Err(TryLockError::Poisoned(_)) => {
panic!("panicking in a RwLockReadGuard::map closure should not poison the RwLock")
}
}
let _ = crate::panic::catch_unwind(|| {
let guard = lock.read().unwrap();
let _guard = RwLockReadGuard::try_map::<(), _>(guard, |_| panic!());
});
match lock.try_write() {
Ok(_) => {}
Err(TryLockError::WouldBlock) => {
panic!("panicking in a RwLockReadGuard::try_map closure should release the read lock")
}
Err(TryLockError::Poisoned(_)) => {
panic!("panicking in a RwLockReadGuard::try_map closure should not poison the RwLock")
}
}
let _ = crate::panic::catch_unwind(|| {
let guard = lock.read().unwrap();
let guard = RwLockReadGuard::map::<(), _>(guard, |val| val);
let _guard = MappedRwLockReadGuard::map::<(), _>(guard, |_| panic!());
});
match lock.try_write() {
Ok(_) => {}
Err(TryLockError::WouldBlock) => {
panic!("panicking in a MappedRwLockReadGuard::map closure should release the read lock")
}
Err(TryLockError::Poisoned(_)) => {
panic!("panicking in a MappedRwLockReadGuard::map closure should not poison the RwLock")
}
}
let _ = crate::panic::catch_unwind(|| {
let guard = lock.read().unwrap();
let guard = RwLockReadGuard::map::<(), _>(guard, |val| val);
let _guard = MappedRwLockReadGuard::try_map::<(), _>(guard, |_| panic!());
});
match lock.try_write() {
Ok(_) => {}
Err(TryLockError::WouldBlock) => panic!(
"panicking in a MappedRwLockReadGuard::try_map closure should release the read lock"
),
Err(TryLockError::Poisoned(_)) => panic!(
"panicking in a MappedRwLockReadGuard::try_map closure should not poison the RwLock"
),
}
drop(lock);
}
#[test]
fn panic_while_mapping_write_unlocked_poison() {
let lock = RwLock::new(());
let _ = crate::panic::catch_unwind(|| {
let guard = lock.write().unwrap();
let _guard = RwLockWriteGuard::map::<(), _>(guard, |_| panic!());
});
match lock.try_write() {
Ok(_) => panic!("panicking in a RwLockWriteGuard::map closure should poison the RwLock"),
Err(TryLockError::WouldBlock) => {
panic!("panicking in a RwLockWriteGuard::map closure should release the write lock")
}
Err(TryLockError::Poisoned(_)) => {}
}
let _ = crate::panic::catch_unwind(|| {
let guard = lock.write().unwrap();
let _guard = RwLockWriteGuard::try_map::<(), _>(guard, |_| panic!());
});
match lock.try_write() {
Ok(_) => {
panic!("panicking in a RwLockWriteGuard::try_map closure should poison the RwLock")
}
Err(TryLockError::WouldBlock) => {
panic!("panicking in a RwLockWriteGuard::try_map closure should release the write lock")
}
Err(TryLockError::Poisoned(_)) => {}
}
let _ = crate::panic::catch_unwind(|| {
let guard = lock.write().unwrap();
let guard = RwLockWriteGuard::map::<(), _>(guard, |val| val);
let _guard = MappedRwLockWriteGuard::map::<(), _>(guard, |_| panic!());
});
match lock.try_write() {
Ok(_) => {
panic!("panicking in a MappedRwLockWriteGuard::map closure should poison the RwLock")
}
Err(TryLockError::WouldBlock) => panic!(
"panicking in a MappedRwLockWriteGuard::map closure should release the write lock"
),
Err(TryLockError::Poisoned(_)) => {}
}
let _ = crate::panic::catch_unwind(|| {
let guard = lock.write().unwrap();
let guard = RwLockWriteGuard::map::<(), _>(guard, |val| val);
let _guard = MappedRwLockWriteGuard::try_map::<(), _>(guard, |_| panic!());
});
match lock.try_write() {
Ok(_) => panic!(
"panicking in a MappedRwLockWriteGuard::try_map closure should poison the RwLock"
),
Err(TryLockError::WouldBlock) => panic!(
"panicking in a MappedRwLockWriteGuard::try_map closure should release the write lock"
),
Err(TryLockError::Poisoned(_)) => {}
}
drop(lock);
}