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