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