aboutsummaryrefslogtreecommitdiff
path: root/src/sync/rwlock/read_guard.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/sync/rwlock/read_guard.rs')
-rw-r--r--src/sync/rwlock/read_guard.rs55
1 files changed, 34 insertions, 21 deletions
diff --git a/src/sync/rwlock/read_guard.rs b/src/sync/rwlock/read_guard.rs
index f5fc1d6..a04b595 100644
--- a/src/sync/rwlock/read_guard.rs
+++ b/src/sync/rwlock/read_guard.rs
@@ -1,8 +1,6 @@
use crate::sync::batch_semaphore::Semaphore;
-use std::fmt;
-use std::marker;
-use std::mem;
-use std::ops;
+use std::marker::PhantomData;
+use std::{fmt, mem, ops};
/// RAII structure used to release the shared read access of a lock when
/// dropped.
@@ -12,16 +10,39 @@ use std::ops;
///
/// [`read`]: method@crate::sync::RwLock::read
/// [`RwLock`]: struct@crate::sync::RwLock
+#[clippy::has_significant_drop]
#[must_use = "if unused the RwLock will immediately unlock"]
pub struct RwLockReadGuard<'a, T: ?Sized> {
+ // When changing the fields in this struct, make sure to update the
+ // `skip_drop` method.
#[cfg(all(tokio_unstable, feature = "tracing"))]
pub(super) resource_span: tracing::Span,
pub(super) s: &'a Semaphore,
pub(super) data: *const T,
- pub(super) marker: marker::PhantomData<&'a T>,
+ pub(super) marker: PhantomData<&'a T>,
+}
+
+#[allow(dead_code)] // Unused fields are still used in Drop.
+struct Inner<'a, T: ?Sized> {
+ #[cfg(all(tokio_unstable, feature = "tracing"))]
+ resource_span: tracing::Span,
+ s: &'a Semaphore,
+ data: *const T,
}
impl<'a, T: ?Sized> RwLockReadGuard<'a, T> {
+ fn skip_drop(self) -> Inner<'a, T> {
+ let me = mem::ManuallyDrop::new(self);
+ // SAFETY: This duplicates the values in every field of the guard, then
+ // forgets the originals, so in the end no value is duplicated.
+ Inner {
+ #[cfg(all(tokio_unstable, feature = "tracing"))]
+ resource_span: unsafe { std::ptr::read(&me.resource_span) },
+ s: me.s,
+ data: me.data,
+ }
+ }
+
/// Makes a new `RwLockReadGuard` for a component of the locked data.
///
/// This operation cannot fail as the `RwLockReadGuard` passed in already
@@ -61,18 +82,14 @@ impl<'a, T: ?Sized> RwLockReadGuard<'a, T> {
F: FnOnce(&T) -> &U,
{
let data = f(&*this) as *const U;
- let s = this.s;
- #[cfg(all(tokio_unstable, feature = "tracing"))]
- let resource_span = this.resource_span.clone();
- // NB: Forget to avoid drop impl from being called.
- mem::forget(this);
+ let this = this.skip_drop();
RwLockReadGuard {
- s,
+ s: this.s,
data,
- marker: marker::PhantomData,
+ marker: PhantomData,
#[cfg(all(tokio_unstable, feature = "tracing"))]
- resource_span,
+ resource_span: this.resource_span,
}
}
@@ -120,18 +137,14 @@ impl<'a, T: ?Sized> RwLockReadGuard<'a, T> {
Some(data) => data as *const U,
None => return Err(this),
};
- let s = this.s;
- #[cfg(all(tokio_unstable, feature = "tracing"))]
- let resource_span = this.resource_span.clone();
- // NB: Forget to avoid drop impl from being called.
- mem::forget(this);
+ let this = this.skip_drop();
Ok(RwLockReadGuard {
- s,
+ s: this.s,
data,
- marker: marker::PhantomData,
+ marker: PhantomData,
#[cfg(all(tokio_unstable, feature = "tracing"))]
- resource_span,
+ resource_span: this.resource_span,
})
}
}