maybe_fut/api/sync/
rwlock.rs1mod read_guard;
2mod write_guard;
3
4pub use self::read_guard::RwLockReadGuard;
5pub use self::write_guard::RwLockWriteGuard;
6use crate::maybe_fut_constructor_sync;
7
8#[derive(Debug, Unwrap)]
14#[unwrap_types(
15 std(std::sync::RwLock),
16 tokio(tokio::sync::RwLock),
17 tokio_gated("tokio-sync")
18)]
19pub struct RwLock<T>(RwLockInner<T>)
20where
21 T: Sized;
22
23#[derive(Debug)]
24enum RwLockInner<T: Sized> {
25 Std(std::sync::RwLock<T>),
26 #[cfg(tokio_sync)]
27 #[cfg_attr(docsrs, doc(cfg(feature = "tokio-sync")))]
28 Tokio(tokio::sync::RwLock<T>),
29}
30
31impl<T> From<std::sync::RwLock<T>> for RwLock<T>
32where
33 T: Sized,
34{
35 fn from(rwlock: std::sync::RwLock<T>) -> Self {
36 RwLock(RwLockInner::Std(rwlock))
37 }
38}
39
40#[cfg(tokio_sync)]
41#[cfg_attr(docsrs, doc(cfg(feature = "tokio-sync")))]
42impl<T> From<tokio::sync::RwLock<T>> for RwLock<T> {
43 fn from(rwlock: tokio::sync::RwLock<T>) -> Self {
44 RwLock(RwLockInner::Tokio(rwlock))
45 }
46}
47
48impl<T> RwLock<T>
49where
50 T: Sized,
51{
52 maybe_fut_constructor_sync!(
53 new(t: T) -> Self,
55 std::sync::RwLock::new,
56 tokio::sync::RwLock::new,
57 tokio_sync
58 );
59
60 pub fn clear_poison(&self) {
68 #[allow(irrefutable_let_patterns)]
69 if let RwLockInner::Std(lock) = &self.0 {
70 lock.clear_poison();
71 }
72 }
73
74 pub fn is_poisoned(&self) -> bool {
76 match &self.0 {
77 RwLockInner::Std(lock) => lock.is_poisoned(),
78 #[cfg(tokio_sync)]
79 RwLockInner::Tokio(_) => false, }
81 }
82
83 pub async fn read(
85 &self,
86 ) -> Result<RwLockReadGuard<'_, T>, std::sync::PoisonError<std::sync::RwLockReadGuard<'_, T>>>
87 {
88 match &self.0 {
89 RwLockInner::Std(lock) => Ok(RwLockReadGuard::from(lock.read()?)),
90 #[cfg(tokio_sync)]
91 RwLockInner::Tokio(lock) => Ok(RwLockReadGuard::from(lock.read().await)),
92 }
93 }
94
95 pub async fn try_read(
97 &self,
98 ) -> Result<RwLockReadGuard<'_, T>, std::sync::TryLockError<std::sync::RwLockReadGuard<'_, T>>>
99 {
100 match &self.0 {
101 RwLockInner::Std(lock) => Ok(RwLockReadGuard::from(lock.try_read()?)),
102 #[cfg(tokio_sync)]
103 RwLockInner::Tokio(lock) => Ok(RwLockReadGuard::from(
104 lock.try_read()
105 .map_err(|_| std::sync::TryLockError::WouldBlock)?,
106 )),
107 }
108 }
109
110 pub async fn write(
112 &self,
113 ) -> Result<RwLockWriteGuard<'_, T>, std::sync::PoisonError<std::sync::RwLockWriteGuard<'_, T>>>
114 {
115 match &self.0 {
116 RwLockInner::Std(lock) => Ok(RwLockWriteGuard::from(lock.write()?)),
117 #[cfg(tokio_sync)]
118 RwLockInner::Tokio(lock) => Ok(RwLockWriteGuard::from(lock.write().await)),
119 }
120 }
121
122 pub async fn try_write(
124 &self,
125 ) -> Result<RwLockWriteGuard<'_, T>, std::sync::TryLockError<std::sync::RwLockWriteGuard<'_, T>>>
126 {
127 match &self.0 {
128 RwLockInner::Std(lock) => Ok(RwLockWriteGuard::from(lock.try_write()?)),
129 #[cfg(tokio_sync)]
130 RwLockInner::Tokio(lock) => Ok(RwLockWriteGuard::from(
131 lock.try_write()
132 .map_err(|_| std::sync::TryLockError::WouldBlock)?,
133 )),
134 }
135 }
136}
137
138impl<T> From<T> for RwLock<T> {
139 fn from(t: T) -> Self {
140 RwLock::new(t)
141 }
142}
143
144impl<T> Default for RwLock<T>
145where
146 T: Default,
147{
148 fn default() -> Self {
149 RwLock::new(T::default())
150 }
151}
152
153#[cfg(test)]
154mod test {
155
156 use super::*;
157 use crate::SyncRuntime;
158
159 #[test]
160 fn test_rwlock_default_sync() {
161 let rwlock: RwLock<i32> = RwLock::default();
162 assert!(matches!(rwlock.0, RwLockInner::Std(_)));
163 }
164
165 #[cfg(tokio_sync)]
166 #[tokio::test]
167 async fn test_rwlock_default_tokio() {
168 let rwlock: RwLock<i32> = RwLock::default();
169 assert!(matches!(rwlock.0, RwLockInner::Tokio(_)));
170 }
171
172 #[test]
173 fn test_rwlock_from_sync() {
174 let std_rwlock = std::sync::RwLock::new(42);
175 let rwlock: RwLock<i32> = RwLock::from(std_rwlock);
176 assert!(matches!(rwlock.0, RwLockInner::Std(_)));
177 }
178
179 #[cfg(tokio_sync)]
180 #[tokio::test]
181 async fn test_rwlock_from_tokio() {
182 let tokio_rwlock = tokio::sync::RwLock::new(42);
183 let rwlock: RwLock<i32> = RwLock::from(tokio_rwlock);
184 assert!(matches!(rwlock.0, RwLockInner::Tokio(_)));
185 }
186
187 #[test]
188 fn test_rwlock_new_sync() {
189 let rwlock = RwLock::new(42);
190 assert!(matches!(rwlock.0, RwLockInner::Std(_)));
191 }
192
193 #[cfg(tokio_sync)]
194 #[tokio::test]
195 async fn test_rwlock_new_tokio() {
196 let rwlock = RwLock::new(42);
197 assert!(matches!(rwlock.0, RwLockInner::Tokio(_)));
198 }
199
200 #[test]
201 fn test_rwlock_clear_poison() {
202 let rwlock = RwLock::new(42);
203 assert!(!rwlock.is_poisoned());
204 rwlock.clear_poison();
205 assert!(!rwlock.is_poisoned());
206 }
207
208 #[test]
209 fn test_rwlock_read() {
210 let rwlock = RwLock::new(42);
211 let read_guard = SyncRuntime::block_on(rwlock.read()).unwrap();
212 assert_eq!(*read_guard, 42);
213 }
214
215 #[cfg(tokio_sync)]
216 #[tokio::test]
217 async fn test_rwlock_read_tokio() {
218 let rwlock = RwLock::new(42);
219 let read_guard = rwlock.read().await.unwrap();
220 assert_eq!(*read_guard, 42);
221 }
222
223 #[test]
224 fn test_rwlock_try_read() {
225 let rwlock = RwLock::new(42);
226 let read_guard = SyncRuntime::block_on(rwlock.try_read()).unwrap();
227 assert_eq!(*read_guard, 42);
228 }
229
230 #[cfg(tokio_sync)]
231 #[tokio::test]
232 async fn test_rwlock_try_read_tokio() {
233 let rwlock = RwLock::new(42);
234 let read_guard = rwlock.try_read().await.unwrap();
235 assert_eq!(*read_guard, 42);
236 }
237
238 #[test]
239 fn test_rwlock_write() {
240 let rwlock = RwLock::new(42);
241 let mut write_guard = SyncRuntime::block_on(rwlock.write()).unwrap();
242 *write_guard = 43;
243 assert_eq!(*write_guard, 43);
244
245 drop(write_guard);
247 let read_guard = SyncRuntime::block_on(rwlock.read()).unwrap();
248 assert_eq!(*read_guard, 43);
249 }
250
251 #[cfg(tokio_sync)]
252 #[tokio::test]
253 async fn test_rwlock_write_tokio() {
254 let rwlock = RwLock::new(42);
255 let mut write_guard = rwlock.write().await.unwrap();
256 *write_guard = 43;
257 assert_eq!(*write_guard, 43);
258
259 drop(write_guard);
261 let read_guard = rwlock.read().await.unwrap();
262 assert_eq!(*read_guard, 43);
263 }
264
265 #[test]
266 fn test_rwlock_try_write() {
267 let rwlock = RwLock::new(42);
268 let mut write_guard = SyncRuntime::block_on(rwlock.try_write()).unwrap();
269 *write_guard = 43;
270 assert_eq!(*write_guard, 43);
271
272 drop(write_guard);
274 let read_guard = SyncRuntime::block_on(rwlock.read()).unwrap();
275 assert_eq!(*read_guard, 43);
276 }
277
278 #[cfg(tokio_sync)]
279 #[tokio::test]
280 async fn test_rwlock_try_write_tokio() {
281 let rwlock = RwLock::new(42);
282 let mut write_guard = rwlock.try_write().await.unwrap();
283 *write_guard = 43;
284 assert_eq!(*write_guard, 43);
285
286 drop(write_guard);
288 let read_guard = rwlock.read().await.unwrap();
289 assert_eq!(*read_guard, 43);
290 }
291}