• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::sync::batch_semaphore::Semaphore;
2 use std::fmt;
3 use std::marker;
4 use std::mem;
5 use std::ops;
6 
7 /// RAII structure used to release the shared read access of a lock when
8 /// dropped.
9 ///
10 /// This structure is created by the [`read`] method on
11 /// [`RwLock`].
12 ///
13 /// [`read`]: method@crate::sync::RwLock::read
14 /// [`RwLock`]: struct@crate::sync::RwLock
15 #[must_use = "if unused the RwLock will immediately unlock"]
16 pub struct RwLockReadGuard<'a, T: ?Sized> {
17     #[cfg(all(tokio_unstable, feature = "tracing"))]
18     pub(super) resource_span: tracing::Span,
19     pub(super) s: &'a Semaphore,
20     pub(super) data: *const T,
21     pub(super) marker: marker::PhantomData<&'a T>,
22 }
23 
24 impl<'a, T: ?Sized> RwLockReadGuard<'a, T> {
25     /// Makes a new `RwLockReadGuard` for a component of the locked data.
26     ///
27     /// This operation cannot fail as the `RwLockReadGuard` passed in already
28     /// locked the data.
29     ///
30     /// This is an associated function that needs to be
31     /// used as `RwLockReadGuard::map(...)`. A method would interfere with
32     /// methods of the same name on the contents of the locked data.
33     ///
34     /// This is an asynchronous version of [`RwLockReadGuard::map`] from the
35     /// [`parking_lot` crate].
36     ///
37     /// [`RwLockReadGuard::map`]: https://docs.rs/lock_api/latest/lock_api/struct.RwLockReadGuard.html#method.map
38     /// [`parking_lot` crate]: https://crates.io/crates/parking_lot
39     ///
40     /// # Examples
41     ///
42     /// ```
43     /// use tokio::sync::{RwLock, RwLockReadGuard};
44     ///
45     /// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
46     /// struct Foo(u32);
47     ///
48     /// # #[tokio::main]
49     /// # async fn main() {
50     /// let lock = RwLock::new(Foo(1));
51     ///
52     /// let guard = lock.read().await;
53     /// let guard = RwLockReadGuard::map(guard, |f| &f.0);
54     ///
55     /// assert_eq!(1, *guard);
56     /// # }
57     /// ```
58     #[inline]
map<F, U: ?Sized>(this: Self, f: F) -> RwLockReadGuard<'a, U> where F: FnOnce(&T) -> &U,59     pub fn map<F, U: ?Sized>(this: Self, f: F) -> RwLockReadGuard<'a, U>
60     where
61         F: FnOnce(&T) -> &U,
62     {
63         let data = f(&*this) as *const U;
64         let s = this.s;
65         #[cfg(all(tokio_unstable, feature = "tracing"))]
66         let resource_span = this.resource_span.clone();
67         // NB: Forget to avoid drop impl from being called.
68         mem::forget(this);
69 
70         RwLockReadGuard {
71             s,
72             data,
73             marker: marker::PhantomData,
74             #[cfg(all(tokio_unstable, feature = "tracing"))]
75             resource_span,
76         }
77     }
78 
79     /// Attempts to make a new [`RwLockReadGuard`] for a component of the
80     /// locked data. The original guard is returned if the closure returns
81     /// `None`.
82     ///
83     /// This operation cannot fail as the `RwLockReadGuard` passed in already
84     /// locked the data.
85     ///
86     /// This is an associated function that needs to be used as
87     /// `RwLockReadGuard::try_map(..)`. A method would interfere with methods of the
88     /// same name on the contents of the locked data.
89     ///
90     /// This is an asynchronous version of [`RwLockReadGuard::try_map`] from the
91     /// [`parking_lot` crate].
92     ///
93     /// [`RwLockReadGuard::try_map`]: https://docs.rs/lock_api/latest/lock_api/struct.RwLockReadGuard.html#method.try_map
94     /// [`parking_lot` crate]: https://crates.io/crates/parking_lot
95     ///
96     /// # Examples
97     ///
98     /// ```
99     /// use tokio::sync::{RwLock, RwLockReadGuard};
100     ///
101     /// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
102     /// struct Foo(u32);
103     ///
104     /// # #[tokio::main]
105     /// # async fn main() {
106     /// let lock = RwLock::new(Foo(1));
107     ///
108     /// let guard = lock.read().await;
109     /// let guard = RwLockReadGuard::try_map(guard, |f| Some(&f.0)).expect("should not fail");
110     ///
111     /// assert_eq!(1, *guard);
112     /// # }
113     /// ```
114     #[inline]
try_map<F, U: ?Sized>(this: Self, f: F) -> Result<RwLockReadGuard<'a, U>, Self> where F: FnOnce(&T) -> Option<&U>,115     pub fn try_map<F, U: ?Sized>(this: Self, f: F) -> Result<RwLockReadGuard<'a, U>, Self>
116     where
117         F: FnOnce(&T) -> Option<&U>,
118     {
119         let data = match f(&*this) {
120             Some(data) => data as *const U,
121             None => return Err(this),
122         };
123         let s = this.s;
124         #[cfg(all(tokio_unstable, feature = "tracing"))]
125         let resource_span = this.resource_span.clone();
126         // NB: Forget to avoid drop impl from being called.
127         mem::forget(this);
128 
129         Ok(RwLockReadGuard {
130             s,
131             data,
132             marker: marker::PhantomData,
133             #[cfg(all(tokio_unstable, feature = "tracing"))]
134             resource_span,
135         })
136     }
137 }
138 
139 impl<T: ?Sized> ops::Deref for RwLockReadGuard<'_, T> {
140     type Target = T;
141 
deref(&self) -> &T142     fn deref(&self) -> &T {
143         unsafe { &*self.data }
144     }
145 }
146 
147 impl<'a, T: ?Sized> fmt::Debug for RwLockReadGuard<'a, T>
148 where
149     T: fmt::Debug,
150 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result151     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152         fmt::Debug::fmt(&**self, f)
153     }
154 }
155 
156 impl<'a, T: ?Sized> fmt::Display for RwLockReadGuard<'a, T>
157 where
158     T: fmt::Display,
159 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result160     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161         fmt::Display::fmt(&**self, f)
162     }
163 }
164 
165 impl<'a, T: ?Sized> Drop for RwLockReadGuard<'a, T> {
drop(&mut self)166     fn drop(&mut self) {
167         self.s.release(1);
168 
169         #[cfg(all(tokio_unstable, feature = "tracing"))]
170         self.resource_span.in_scope(|| {
171             tracing::trace!(
172             target: "runtime::resource::state_update",
173             current_readers = 1,
174             current_readers.op = "sub",
175             )
176         });
177     }
178 }
179