1 use crate::sync::rwlock::RwLock;
2 use std::marker::PhantomData;
3 use std::sync::Arc;
4 use std::{fmt, mem, ops, ptr};
5 
6 /// Owned RAII structure used to release the shared read access of a lock when
7 /// dropped.
8 ///
9 /// This structure is created by the [`read_owned`] method on
10 /// [`RwLock`].
11 ///
12 /// [`read_owned`]: method@crate::sync::RwLock::read_owned
13 /// [`RwLock`]: struct@crate::sync::RwLock
14 #[clippy::has_significant_drop]
15 pub struct OwnedRwLockReadGuard<T: ?Sized, U: ?Sized = T> {
16     // When changing the fields in this struct, make sure to update the
17     // `skip_drop` method.
18     #[cfg(all(tokio_unstable, feature = "tracing"))]
19     pub(super) resource_span: tracing::Span,
20     pub(super) lock: Arc<RwLock<T>>,
21     pub(super) data: *const U,
22     pub(super) _p: PhantomData<T>,
23 }
24 
25 #[allow(dead_code)] // Unused fields are still used in Drop.
26 struct Inner<T: ?Sized, U: ?Sized> {
27     #[cfg(all(tokio_unstable, feature = "tracing"))]
28     resource_span: tracing::Span,
29     lock: Arc<RwLock<T>>,
30     data: *const U,
31 }
32 
33 impl<T: ?Sized, U: ?Sized> OwnedRwLockReadGuard<T, U> {
skip_drop(self) -> Inner<T, U>34     fn skip_drop(self) -> Inner<T, U> {
35         let me = mem::ManuallyDrop::new(self);
36         // SAFETY: This duplicates the values in every field of the guard, then
37         // forgets the originals, so in the end no value is duplicated.
38         unsafe {
39             Inner {
40                 #[cfg(all(tokio_unstable, feature = "tracing"))]
41                 resource_span: ptr::read(&me.resource_span),
42                 lock: ptr::read(&me.lock),
43                 data: me.data,
44             }
45         }
46     }
47 
48     /// Makes a new `OwnedRwLockReadGuard` for a component of the locked data.
49     /// This operation cannot fail as the `OwnedRwLockReadGuard` passed in
50     /// already locked the data.
51     ///
52     /// This is an associated function that needs to be
53     /// used as `OwnedRwLockReadGuard::map(...)`. A method would interfere with
54     /// methods of the same name on the contents of the locked data.
55     ///
56     /// # Examples
57     ///
58     /// ```
59     /// use std::sync::Arc;
60     /// use tokio::sync::{RwLock, OwnedRwLockReadGuard};
61     ///
62     /// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
63     /// struct Foo(u32);
64     ///
65     /// # #[tokio::main]
66     /// # async fn main() {
67     /// let lock = Arc::new(RwLock::new(Foo(1)));
68     ///
69     /// let guard = lock.read_owned().await;
70     /// let guard = OwnedRwLockReadGuard::map(guard, |f| &f.0);
71     ///
72     /// assert_eq!(1, *guard);
73     /// # }
74     /// ```
75     #[inline]
map<F, V: ?Sized>(this: Self, f: F) -> OwnedRwLockReadGuard<T, V> where F: FnOnce(&U) -> &V,76     pub fn map<F, V: ?Sized>(this: Self, f: F) -> OwnedRwLockReadGuard<T, V>
77     where
78         F: FnOnce(&U) -> &V,
79     {
80         let data = f(&*this) as *const V;
81         let this = this.skip_drop();
82 
83         OwnedRwLockReadGuard {
84             lock: this.lock,
85             data,
86             _p: PhantomData,
87             #[cfg(all(tokio_unstable, feature = "tracing"))]
88             resource_span: this.resource_span,
89         }
90     }
91 
92     /// Attempts to make a new [`OwnedRwLockReadGuard`] for a component of the
93     /// locked data. The original guard is returned if the closure returns
94     /// `None`.
95     ///
96     /// This operation cannot fail as the `OwnedRwLockReadGuard` passed in
97     /// already locked the data.
98     ///
99     /// This is an associated function that needs to be used as
100     /// `OwnedRwLockReadGuard::try_map(..)`. A method would interfere with
101     /// methods of the same name on the contents of the locked data.
102     ///
103     /// # Examples
104     ///
105     /// ```
106     /// use std::sync::Arc;
107     /// use tokio::sync::{RwLock, OwnedRwLockReadGuard};
108     ///
109     /// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
110     /// struct Foo(u32);
111     ///
112     /// # #[tokio::main]
113     /// # async fn main() {
114     /// let lock = Arc::new(RwLock::new(Foo(1)));
115     ///
116     /// let guard = lock.read_owned().await;
117     /// let guard = OwnedRwLockReadGuard::try_map(guard, |f| Some(&f.0)).expect("should not fail");
118     ///
119     /// assert_eq!(1, *guard);
120     /// # }
121     /// ```
122     #[inline]
try_map<F, V: ?Sized>(this: Self, f: F) -> Result<OwnedRwLockReadGuard<T, V>, Self> where F: FnOnce(&U) -> Option<&V>,123     pub fn try_map<F, V: ?Sized>(this: Self, f: F) -> Result<OwnedRwLockReadGuard<T, V>, Self>
124     where
125         F: FnOnce(&U) -> Option<&V>,
126     {
127         let data = match f(&*this) {
128             Some(data) => data as *const V,
129             None => return Err(this),
130         };
131         let this = this.skip_drop();
132 
133         Ok(OwnedRwLockReadGuard {
134             lock: this.lock,
135             data,
136             _p: PhantomData,
137             #[cfg(all(tokio_unstable, feature = "tracing"))]
138             resource_span: this.resource_span,
139         })
140     }
141 
142     /// Returns a reference to the original `Arc<RwLock>`.
143     ///
144     /// # Examples
145     ///
146     /// ```
147     /// use std::sync::Arc;
148     /// use tokio::sync::{RwLock, OwnedRwLockReadGuard};
149     ///
150     /// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
151     /// struct Foo(u32);
152     ///
153     /// # #[tokio::main]
154     /// # async fn main() {
155     /// let lock = Arc::new(RwLock::new(Foo(1)));
156     ///
157     /// let guard = lock.clone().read_owned().await;
158     /// assert!(Arc::ptr_eq(&lock, OwnedRwLockReadGuard::rwlock(&guard)));
159     ///
160     /// let guard = OwnedRwLockReadGuard::map(guard, |f| &f.0);
161     /// assert!(Arc::ptr_eq(&lock, OwnedRwLockReadGuard::rwlock(&guard)));
162     /// # }
163     /// ```
rwlock(this: &Self) -> &Arc<RwLock<T>>164     pub fn rwlock(this: &Self) -> &Arc<RwLock<T>> {
165         &this.lock
166     }
167 }
168 
169 impl<T: ?Sized, U: ?Sized> ops::Deref for OwnedRwLockReadGuard<T, U> {
170     type Target = U;
171 
deref(&self) -> &U172     fn deref(&self) -> &U {
173         unsafe { &*self.data }
174     }
175 }
176 
177 impl<T: ?Sized, U: ?Sized> fmt::Debug for OwnedRwLockReadGuard<T, U>
178 where
179     U: fmt::Debug,
180 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result181     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182         fmt::Debug::fmt(&**self, f)
183     }
184 }
185 
186 impl<T: ?Sized, U: ?Sized> fmt::Display for OwnedRwLockReadGuard<T, U>
187 where
188     U: fmt::Display,
189 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result190     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
191         fmt::Display::fmt(&**self, f)
192     }
193 }
194 
195 impl<T: ?Sized, U: ?Sized> Drop for OwnedRwLockReadGuard<T, U> {
drop(&mut self)196     fn drop(&mut self) {
197         self.lock.s.release(1);
198 
199         #[cfg(all(tokio_unstable, feature = "tracing"))]
200         self.resource_span.in_scope(|| {
201             tracing::trace!(
202             target: "runtime::resource::state_update",
203             current_readers = 1,
204             current_readers.op = "sub",
205             )
206         });
207     }
208 }
209