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