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