tokio/sync/rwlock/
owned_read_guard.rs

1use crate::sync::rwlock::RwLock;
2use std::marker::PhantomData;
3use std::sync::Arc;
4use 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]
15pub 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.
26struct 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
33impl<T: ?Sized, U: ?Sized> OwnedRwLockReadGuard<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]
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]
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    /// ```
164    pub fn rwlock(this: &Self) -> &Arc<RwLock<T>> {
165        &this.lock
166    }
167}
168
169impl<T: ?Sized, U: ?Sized> ops::Deref for OwnedRwLockReadGuard<T, U> {
170    type Target = U;
171
172    fn deref(&self) -> &U {
173        unsafe { &*self.data }
174    }
175}
176
177impl<T: ?Sized, U: ?Sized> fmt::Debug for OwnedRwLockReadGuard<T, U>
178where
179    U: fmt::Debug,
180{
181    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182        fmt::Debug::fmt(&**self, f)
183    }
184}
185
186impl<T: ?Sized, U: ?Sized> fmt::Display for OwnedRwLockReadGuard<T, U>
187where
188    U: fmt::Display,
189{
190    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
191        fmt::Display::fmt(&**self, f)
192    }
193}
194
195impl<T: ?Sized, U: ?Sized> Drop for OwnedRwLockReadGuard<T, U> {
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}