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