guardian/lib.rs
1//! Guardian provides owned mutex guards for refcounted mutexes.
2//!
3//! Normally, lock guards (be it for `Mutex` or `RwLock`) are bound to the lifetime of the borrow
4//! of the underlying lock. Specifically, the function signatures all resemble:
5//! `fn lock<'a>(&'a self) -> Guard<'a>`.
6//!
7//! If the mutex is refcounted using an `Rc` or an `Arc`, it is not necessary for the guard to be
8//! scoped in this way -- it could instead carry with it a ref to the mutex in question, which
9//! allows the guard to be held for as long as is necessary. This is particularly useful for
10//! writing iterators where it is advantageous to hold a read lock for the duration of the
11//! iteration.
12//!
13//! # Poisoning
14//!
15//! When taking a lock using a guardian, similarly to when taking an `RwLock` or `Mutex`, the
16//! result may be poisoned on panics. The poison is propagated from that of the underlying `lock()`
17//! method, so for `RwLock`s, the same rule applies for when a lock may be poisioned.
18
19use std::ops::Deref;
20use std::ops::DerefMut;
21use std::rc;
22use std::sync;
23
24// ATTENTION READERS:
25// Most of the code looks identical for Arc vs Rc, for RwLockRead vs RwLockWrite, and for Mutex vs
26// RwLock. If you change anything for one type, be sure to also make the same changes to the other
27// variants below.
28//
29// Each structure holds the guard in an Option to ensure that we drop the guard before we drop the
30// handle, as dropping the guard will access the handle.
31
32// ****************************************************************************
33// The basic wrapper types
34// ****************************************************************************
35
36/// RAII structure used to release the shared read access of a lock when dropped.
37/// Keeps a handle to an `Arc` so that the lock is not dropped until the guard is.
38///
39/// The data protected by the mutex can be access through this guard via its `Deref` and `DerefMut`
40/// implementations.
41pub struct ArcRwLockReadGuardian<T: ?Sized + 'static> {
42 _handle: sync::Arc<sync::RwLock<T>>,
43 inner: Option<sync::RwLockReadGuard<'static, T>>,
44}
45
46/// RAII structure used to release the exclusive write access of a lock when dropped.
47/// Keeps a handle to an `Arc` so that the lock is not dropped until the guard is.
48///
49/// The data protected by the mutex can be access through this guard via its `Deref` and `DerefMut`
50/// implementations.
51pub struct ArcRwLockWriteGuardian<T: ?Sized + 'static> {
52 _handle: sync::Arc<sync::RwLock<T>>,
53 inner: Option<sync::RwLockWriteGuard<'static, T>>,
54}
55
56/// An RAII implementation of a "scoped lock" of a mutex. When this structure is dropped (falls out
57/// of scope), the lock will be unlocked. Keeps a handle to an `Arc` so that the lock is not
58/// dropped until the guard is.
59///
60/// The data protected by the mutex can be access through this guard via its `Deref` and `DerefMut`
61/// implementations.
62pub struct ArcMutexGuardian<T: ?Sized + 'static> {
63 _handle: sync::Arc<sync::Mutex<T>>,
64 inner: Option<sync::MutexGuard<'static, T>>,
65}
66
67/// RAII structure used to release the shared read access of a lock when dropped.
68/// Keeps a handle to an `Rc` so that the lock is not dropped until the guard is.
69///
70/// The data protected by the mutex can be access through this guard via its `Deref` and `DerefMut`
71/// implementations.
72pub struct RcRwLockReadGuardian<T: ?Sized + 'static> {
73 _handle: rc::Rc<sync::RwLock<T>>,
74 inner: Option<sync::RwLockReadGuard<'static, T>>,
75}
76
77/// RAII structure used to release the exclusive write access of a lock when dropped.
78/// Keeps a handle to an `Rc` so that the lock is not dropped until the guard is.
79///
80/// The data protected by the mutex can be access through this guard via its `Deref` and `DerefMut`
81/// implementations.
82pub struct RcRwLockWriteGuardian<T: ?Sized + 'static> {
83 _handle: rc::Rc<sync::RwLock<T>>,
84 inner: Option<sync::RwLockWriteGuard<'static, T>>,
85}
86
87/// An RAII implementation of a "scoped lock" of a mutex. When this structure is dropped (falls out
88/// of scope), the lock will be unlocked. Keeps a handle to an `Rc` so that the lock is not
89/// dropped until the guard is.
90///
91/// The data protected by the mutex can be access through this guard via its `Deref` and `DerefMut`
92/// implementations.
93pub struct RcMutexGuardian<T: ?Sized + 'static> {
94 _handle: rc::Rc<sync::Mutex<T>>,
95 inner: Option<sync::MutexGuard<'static, T>>,
96}
97
98// ****************************************************************************
99// Traits: Deref
100// ****************************************************************************
101
102impl<T: ?Sized> Deref for ArcRwLockReadGuardian<T> {
103 type Target = T;
104 fn deref(&self) -> &Self::Target {
105 self.inner.as_ref().expect("inner is None only in drop")
106 }
107}
108
109impl<T: ?Sized> Deref for ArcRwLockWriteGuardian<T> {
110 type Target = T;
111 fn deref(&self) -> &Self::Target {
112 self.inner.as_ref().expect("inner is None only in drop")
113 }
114}
115
116impl<T: ?Sized> Deref for ArcMutexGuardian<T> {
117 type Target = T;
118 fn deref(&self) -> &Self::Target {
119 self.inner.as_ref().expect("inner is None only in drop")
120 }
121}
122
123impl<T: ?Sized> Deref for RcRwLockReadGuardian<T> {
124 type Target = T;
125 fn deref(&self) -> &Self::Target {
126 self.inner.as_ref().expect("inner is None only in drop")
127 }
128}
129
130impl<T: ?Sized> Deref for RcRwLockWriteGuardian<T> {
131 type Target = T;
132 fn deref(&self) -> &Self::Target {
133 self.inner.as_ref().expect("inner is None only in drop")
134 }
135}
136
137impl<T: ?Sized> Deref for RcMutexGuardian<T> {
138 type Target = T;
139 fn deref(&self) -> &Self::Target {
140 self.inner.as_ref().expect("inner is None only in drop")
141 }
142}
143
144// ****************************************************************************
145// Traits: DerefMut
146// ****************************************************************************
147
148impl<T: ?Sized> DerefMut for ArcRwLockWriteGuardian<T> {
149 fn deref_mut(&mut self) -> &mut T {
150 self.inner.as_mut().expect("inner is None only in drop")
151 }
152}
153
154impl<T: ?Sized> DerefMut for RcRwLockWriteGuardian<T> {
155 fn deref_mut(&mut self) -> &mut T {
156 self.inner.as_mut().expect("inner is None only in drop")
157 }
158}
159
160impl<T: ?Sized> DerefMut for ArcMutexGuardian<T> {
161 fn deref_mut(&mut self) -> &mut T {
162 self.inner.as_mut().expect("inner is None only in drop")
163 }
164}
165
166impl<T: ?Sized> DerefMut for RcMutexGuardian<T> {
167 fn deref_mut(&mut self) -> &mut T {
168 self.inner.as_mut().expect("inner is None only in drop")
169 }
170}
171
172// ****************************************************************************
173// Traits: From
174// ****************************************************************************
175
176impl<T: ?Sized> From<sync::Arc<sync::RwLock<T>>> for ArcRwLockReadGuardian<T> {
177 fn from(handle: sync::Arc<sync::RwLock<T>>) -> Self {
178 ArcRwLockReadGuardian::take(handle).unwrap()
179 }
180}
181
182impl<T: ?Sized> From<sync::Arc<sync::RwLock<T>>> for ArcRwLockWriteGuardian<T> {
183 fn from(handle: sync::Arc<sync::RwLock<T>>) -> Self {
184 ArcRwLockWriteGuardian::take(handle).unwrap()
185 }
186}
187
188impl<T: ?Sized> From<sync::Arc<sync::Mutex<T>>> for ArcMutexGuardian<T> {
189 fn from(handle: sync::Arc<sync::Mutex<T>>) -> Self {
190 ArcMutexGuardian::take(handle).unwrap()
191 }
192}
193
194impl<T: ?Sized> From<rc::Rc<sync::RwLock<T>>> for RcRwLockReadGuardian<T> {
195 fn from(handle: rc::Rc<sync::RwLock<T>>) -> Self {
196 RcRwLockReadGuardian::take(handle).unwrap()
197 }
198}
199
200impl<T: ?Sized> From<rc::Rc<sync::RwLock<T>>> for RcRwLockWriteGuardian<T> {
201 fn from(handle: rc::Rc<sync::RwLock<T>>) -> Self {
202 RcRwLockWriteGuardian::take(handle).unwrap()
203 }
204}
205
206impl<T: ?Sized> From<rc::Rc<sync::Mutex<T>>> for RcMutexGuardian<T> {
207 fn from(handle: rc::Rc<sync::Mutex<T>>) -> Self {
208 RcMutexGuardian::take(handle).unwrap()
209 }
210}
211
212/// Turn any reference to a 'static one.
213unsafe fn make_static<T: ?Sized>(r: &T) -> &'static T {
214 &*(r as *const T)
215}
216
217// ****************************************************************************
218// macros
219// ****************************************************************************
220
221macro_rules! take {
222 ( $handle: ident, $guard:ty, $guardian:ident, $lfunc:ident ) => {{
223 // We want to express that it's safe to keep the read guard around for as long as the
224 // Arc/Rc is around. Unfortunately, we can't say this directly with lifetimes, because
225 // we have to move the Arc/Rc below, which Rust doesn't know allows the borrow to
226 // continue. We therefore make a temporary 'static reference to the handle to get
227 // a 'static Guard, and ensure that any borrows we expose are bounded
228 // by the lifetime of the guardian (which also holds the Arc/Rc).
229 let lock: sync::LockResult<$guard> = unsafe { make_static(&$handle).$lfunc() };
230
231 match lock {
232 Ok(guard) => Ok($guardian {
233 _handle: $handle,
234 inner: Some(guard),
235 }),
236 Err(guard) => Err(sync::PoisonError::new($guardian {
237 _handle: $handle,
238 inner: Some(guard.into_inner()),
239 })),
240 }
241 }};
242}
243
244macro_rules! try_take {
245 ( $handle: ident, $guard:ty, $guardian:ident, $lfunc:ident ) => {{
246 use std::sync::TryLockError::{Poisoned, WouldBlock};
247
248 // Safe following the same reasoning as in take!.
249 let lock: sync::TryLockResult<$guard> = unsafe { make_static(&$handle).$lfunc() };
250
251 match lock {
252 Ok(guard) => Some(Ok($guardian {
253 _handle: $handle,
254 inner: Some(guard),
255 })),
256 Err(WouldBlock) => None,
257 Err(Poisoned(guard)) => Some(Err(sync::PoisonError::new($guardian {
258 _handle: $handle,
259 inner: Some(guard.into_inner()),
260 }))),
261 }
262 }};
263}
264
265// ****************************************************************************
266// impl
267// ****************************************************************************
268
269impl<T: ?Sized> ArcRwLockReadGuardian<T> {
270 /// Locks the given rwlock with shared read access, blocking the current thread until it can be
271 /// acquired.
272 ///
273 /// The calling thread will be blocked until there are no more writers which hold the lock.
274 /// There may be other readers currently inside the lock when this method returns. This method
275 /// does not provide any guarantees with respect to the ordering of whether contentious readers
276 /// or writers will acquire the lock first.
277 ///
278 /// Returns an RAII guardian which will release this thread's shared access once it is dropped.
279 /// The guardian also holds a strong reference to the lock's `Arc`, which is dropped when the
280 /// guard is.
281 pub fn take(handle: sync::Arc<sync::RwLock<T>>) -> sync::LockResult<ArcRwLockReadGuardian<T>> {
282 take!(
283 handle,
284 sync::RwLockReadGuard<'static, T>,
285 ArcRwLockReadGuardian,
286 read
287 )
288 }
289
290 /// Attempts to acquire this rwlock with shared read access.
291 ///
292 /// If the access could not be granted at this time, then `None` is returned.
293 /// Otherwise, an RAII guard is returned which will release the shared access when it is dropped.
294 /// The guardian also holds a strong reference to the lock's `Arc`, which is dropped when the
295 /// guard is.
296 ///
297 /// This function does not block.
298 ///
299 /// This function does not provide any guarantees with respect to the ordering of whether contentious readers or writers will acquire the lock first.
300 pub fn try_take(
301 handle: sync::Arc<sync::RwLock<T>>,
302 ) -> Option<sync::LockResult<ArcRwLockReadGuardian<T>>> {
303 try_take!(
304 handle,
305 sync::RwLockReadGuard<'static, T>,
306 ArcRwLockReadGuardian,
307 try_read
308 )
309 }
310}
311
312impl<T: ?Sized> ArcRwLockWriteGuardian<T> {
313 /// Locks this rwlock with exclusive write access, blocking the current thread until it can be
314 /// acquired.
315 ///
316 /// This function will not return while other writers or other readers currently have access to
317 /// the lock.
318 ///
319 /// Returns an RAII guard which will drop the write access of this rwlock when dropped.
320 /// The guardian also holds a strong reference to the lock's `Arc`, which is dropped when the
321 /// guard is.
322 ///
323 /// # Errors
324 ///
325 /// This function will return an error if the `RwLock` is poisoned. An `RwLock` is poisoned
326 /// whenever a writer panics while holding an exclusive lock. An error will be returned when
327 /// the lock is acquired.
328 pub fn take(handle: sync::Arc<sync::RwLock<T>>) -> sync::LockResult<ArcRwLockWriteGuardian<T>> {
329 take!(
330 handle,
331 sync::RwLockWriteGuard<'static, T>,
332 ArcRwLockWriteGuardian,
333 write
334 )
335 }
336
337 /// Attempts to lock this rwlock with exclusive write access.
338 ///
339 /// If the access could not be granted at this time, then `None` is returned.
340 /// Otherwise, an RAII guard is returned, which will drop the write access of this rwlock when dropped.
341 /// The guardian also holds a strong reference to the lock's `Arc`, which is dropped when the
342 /// guard is.
343 ///
344 /// This function does not block.
345 ///
346 /// This function does not provide any guarantees with respect to the ordering of whether contentious readers or writers will acquire the lock first.
347 pub fn try_take(
348 handle: sync::Arc<sync::RwLock<T>>,
349 ) -> Option<sync::LockResult<ArcRwLockWriteGuardian<T>>> {
350 try_take!(
351 handle,
352 sync::RwLockWriteGuard<'static, T>,
353 ArcRwLockWriteGuardian,
354 try_write
355 )
356 }
357}
358
359impl<T: ?Sized> ArcMutexGuardian<T> {
360 /// Acquires a mutex, blocking the current thread until it is able to do so.
361 ///
362 /// This function will block the local thread until it is available to acquire the mutex. Upon
363 /// returning, the thread is the only thread with the mutex held. An RAII guardian is returned
364 /// to allow scoped unlock of the lock. When the guard goes out of scope, the mutex will be
365 /// unlocked. The guardian also holds a strong reference to the lock's `Arc`, which is dropped
366 /// when the guard is.
367 ///
368 /// # Errors
369 ///
370 /// If another user of this mutex panicked while holding the mutex, then this call will return
371 /// an error once the mutex is acquired.
372 pub fn take(handle: sync::Arc<sync::Mutex<T>>) -> sync::LockResult<ArcMutexGuardian<T>> {
373 take!(handle, sync::MutexGuard<'static, T>, ArcMutexGuardian, lock)
374 }
375
376 /// Attempts to acquire this lock.
377 ///
378 /// If the lock could not be acquired at this time, then `None` is returned.
379 /// Otherwise, an RAII guard is returned. The lock will be unlocked when the guard is dropped.
380 /// The guardian also holds a strong reference to the lock's `Arc`, which is dropped
381 /// when the guard is.
382 ///
383 /// This function does not block.
384 pub fn try_take(
385 handle: sync::Arc<sync::Mutex<T>>,
386 ) -> Option<sync::LockResult<ArcMutexGuardian<T>>> {
387 try_take!(
388 handle,
389 sync::MutexGuard<'static, T>,
390 ArcMutexGuardian,
391 try_lock
392 )
393 }
394}
395
396// And this is all the same as above, but with s/Arc/Rc/
397
398impl<T: ?Sized> RcRwLockReadGuardian<T> {
399 /// Locks the given rwlock with shared read access, blocking the current thread until it can be
400 /// acquired.
401 ///
402 /// The calling thread will be blocked until there are no more writers which hold the lock.
403 /// There may be other readers currently inside the lock when this method returns. This method
404 /// does not provide any guarantees with respect to the ordering of whether contentious readers
405 /// or writers will acquire the lock first.
406 ///
407 /// Returns an RAII guardian which will release this thread's shared access once it is dropped.
408 /// The guardian also holds a strong reference to the lock's `Rc`, which is dropped when the
409 /// guard is.
410 pub fn take(handle: rc::Rc<sync::RwLock<T>>) -> sync::LockResult<RcRwLockReadGuardian<T>> {
411 take!(
412 handle,
413 sync::RwLockReadGuard<'static, T>,
414 RcRwLockReadGuardian,
415 read
416 )
417 }
418
419 /// Attempts to acquire this rwlock with shared read access.
420 ///
421 /// If the access could not be granted at this time, then `None` is returned.
422 /// Otherwise, an RAII guard is returned which will release the shared access when it is dropped.
423 /// The guardian also holds a strong reference to the lock's `Rc`, which is dropped when the
424 /// guard is.
425 ///
426 /// This function does not block.
427 ///
428 /// This function does not provide any guarantees with respect to the ordering of whether contentious readers or writers will acquire the lock first.
429 pub fn try_take(
430 handle: rc::Rc<sync::RwLock<T>>,
431 ) -> Option<sync::LockResult<RcRwLockReadGuardian<T>>> {
432 try_take!(
433 handle,
434 sync::RwLockReadGuard<'static, T>,
435 RcRwLockReadGuardian,
436 try_read
437 )
438 }
439}
440
441impl<T: ?Sized> RcRwLockWriteGuardian<T> {
442 /// Locks this rwlock with exclusive write access, blocking the current thread until it can be
443 /// acquired.
444 ///
445 /// This function will not return while other writers or other readers currently have access to
446 /// the lock.
447 ///
448 /// Returns an RAII guard which will drop the write access of this rwlock when dropped.
449 /// The guardian also holds a strong reference to the lock's `Rc`, which is dropped when the
450 /// guard is.
451 ///
452 /// # Errors
453 ///
454 /// This function will return an error if the `RwLock` is poisoned. An `RwLock` is poisoned
455 /// whenever a writer panics while holding an exclusive lock. An error will be returned when
456 /// the lock is acquired.
457 pub fn take(handle: rc::Rc<sync::RwLock<T>>) -> sync::LockResult<RcRwLockWriteGuardian<T>> {
458 take!(
459 handle,
460 sync::RwLockWriteGuard<'static, T>,
461 RcRwLockWriteGuardian,
462 write
463 )
464 }
465
466 /// Attempts to lock this rwlock with exclusive write access.
467 ///
468 /// If the access could not be granted at this time, then `None` is returned.
469 /// Otherwise, an RAII guard is returned, which will drop the write access of this rwlock when dropped.
470 /// The guardian also holds a strong reference to the lock's `Rc`, which is dropped when the
471 /// guard is.
472 ///
473 /// This function does not block.
474 ///
475 /// This function does not provide any guarantees with respect to the ordering of whether contentious readers or writers will acquire the lock first.
476 pub fn try_take(
477 handle: rc::Rc<sync::RwLock<T>>,
478 ) -> Option<sync::LockResult<RcRwLockWriteGuardian<T>>> {
479 try_take!(
480 handle,
481 sync::RwLockWriteGuard<'static, T>,
482 RcRwLockWriteGuardian,
483 try_write
484 )
485 }
486}
487
488impl<T: ?Sized> RcMutexGuardian<T> {
489 /// Acquires a mutex, blocking the current thread until it is able to do so.
490 ///
491 /// This function will block the local thread until it is available to acquire the mutex. Upon
492 /// returning, the thread is the only thread with the mutex held. An RAII guardian is returned
493 /// to allow scoped unlock of the lock. When the guard goes out of scope, the mutex will be
494 /// unlocked. The guardian also holds a strong reference to the lock's `Rc`, which is dropped
495 /// when the guard is.
496 ///
497 /// # Errors
498 ///
499 /// If another user of this mutex panicked while holding the mutex, then this call will return
500 /// an error once the mutex is acquired.
501 pub fn take(handle: rc::Rc<sync::Mutex<T>>) -> sync::LockResult<RcMutexGuardian<T>> {
502 take!(handle, sync::MutexGuard<'static, T>, RcMutexGuardian, lock)
503 }
504
505 /// Attempts to acquire this lock.
506 ///
507 /// If the lock could not be acquired at this time, then `None` is returned.
508 /// Otherwise, an RAII guard is returned. The lock will be unlocked when the guard is dropped.
509 /// The guardian also holds a strong reference to the lock's `Rc`, which is dropped
510 /// when the guard is.
511 ///
512 /// This function does not block.
513 pub fn try_take(
514 handle: rc::Rc<sync::Mutex<T>>,
515 ) -> Option<sync::LockResult<RcMutexGuardian<T>>> {
516 try_take!(
517 handle,
518 sync::MutexGuard<'static, T>,
519 RcMutexGuardian,
520 try_lock
521 )
522 }
523}
524
525// ****************************************************************************
526// Drop
527// ****************************************************************************
528
529impl<T: ?Sized> Drop for ArcRwLockReadGuardian<T> {
530 fn drop(&mut self) {
531 self.inner.take();
532 }
533}
534
535impl<T: ?Sized> Drop for ArcRwLockWriteGuardian<T> {
536 fn drop(&mut self) {
537 self.inner.take();
538 }
539}
540
541impl<T: ?Sized> Drop for ArcMutexGuardian<T> {
542 fn drop(&mut self) {
543 self.inner.take();
544 }
545}
546
547impl<T: ?Sized> Drop for RcRwLockReadGuardian<T> {
548 fn drop(&mut self) {
549 self.inner.take();
550 }
551}
552
553impl<T: ?Sized> Drop for RcRwLockWriteGuardian<T> {
554 fn drop(&mut self) {
555 self.inner.take();
556 }
557}
558
559impl<T: ?Sized> Drop for RcMutexGuardian<T> {
560 fn drop(&mut self) {
561 self.inner.take();
562 }
563}
564
565// ****************************************************************************
566// And finally all the tests
567// ****************************************************************************
568
569#[cfg(test)]
570mod tests {
571 use super::*;
572 use std::rc;
573 use std::sync;
574
575 #[test]
576 fn arc_rw_read() {
577 let base = sync::Arc::new(sync::RwLock::new(true));
578
579 // the use of scopes below is necessary so that we can drop base at the end.
580 // otherwise, all the x1's (i.e., base.read()) would hold on to borrows.
581 // this is part of the problem that Guardian is trying to solve.
582
583 let x2 = {
584 let x1 = base.read().unwrap();
585 let x2 = ArcRwLockReadGuardian::take(base.clone()).unwrap();
586
587 // guardian dereferences correctly
588 assert_eq!(&*x1, &*x2);
589
590 // guardian holds read lock
591 drop(x1);
592 assert!(base.try_write().is_err(), "guardian holds read lock");
593
594 x2
595 };
596
597 {
598 // guardian can be moved
599 let x1 = base.read().unwrap();
600 let x2_ = x2;
601 assert_eq!(&*x1, &*x2_);
602
603 // moving guardian does not release lock
604 drop(x1);
605 assert!(base.try_write().is_err(), "guardian still holds read lock");
606
607 // dropping guardian drops read lock
608 drop(x2_);
609 assert!(base.try_write().is_ok(), "guardian drops read lock");
610 }
611
612 // guardian works even after all other Arcs have been dropped
613 let x = ArcRwLockReadGuardian::take(base).unwrap();
614 assert_eq!(&*x, &true);
615 }
616
617 #[test]
618 fn arc_rw_write() {
619 let base = sync::Arc::new(sync::RwLock::new(true));
620
621 let mut x = ArcRwLockWriteGuardian::take(base.clone()).unwrap();
622
623 // guardian dereferences correctly
624 assert_eq!(&*x, &true);
625
626 // guardian can write
627 *x = false;
628 assert_eq!(&*x, &false);
629
630 // guardian holds write lock
631 assert!(base.try_read().is_err(), "guardian holds write lock");
632
633 // guardian can be moved
634 let x_ = x;
635 assert_eq!(&*x_, &false);
636
637 // moving guardian does not release lock
638 assert!(base.try_read().is_err(), "guardian still holds write lock");
639
640 // dropping guardian drops write lock
641 drop(x_);
642 assert!(base.try_read().is_ok(), "guardian drops write lock");
643
644 // guardian works even after all other Arcs have been dropped
645 let x = ArcRwLockWriteGuardian::take(base).unwrap();
646 assert_eq!(&*x, &false);
647 }
648
649 #[test]
650 fn arc_rw_try() {
651 let base = sync::Arc::new(sync::RwLock::new(true));
652
653 let mut x = ArcRwLockWriteGuardian::try_take(base.clone())
654 .unwrap()
655 .unwrap();
656
657 // guardian dereferences correctly
658 assert_eq!(&*x, &true);
659
660 // guardian can write
661 *x = false;
662 assert_eq!(&*x, &false);
663
664 // guardian holds write lock
665 assert!(base.try_read().is_err(), "guardian holds write lock");
666
667 // guardian can be moved
668 let x_ = x;
669 assert_eq!(&*x_, &false);
670
671 // moving guardian does not release lock
672 assert!(base.try_read().is_err(), "guardian still holds write lock");
673
674 // try_take returns None if it would block
675 assert!(ArcRwLockWriteGuardian::try_take(base.clone()).is_none());
676
677 assert!(ArcRwLockReadGuardian::try_take(base.clone()).is_none());
678
679 // dropping guardian drops write lock
680 drop(x_);
681 assert!(base.try_read().is_ok(), "guardian drops write lock");
682
683 // guardian works even after all other Arcs have been dropped
684 let x = ArcRwLockWriteGuardian::take(base).unwrap();
685 assert_eq!(&*x, &false);
686 }
687
688 #[test]
689 fn arc_mu() {
690 let base = sync::Arc::new(sync::Mutex::new(true));
691
692 let mut x = ArcMutexGuardian::take(base.clone()).unwrap();
693
694 // guardian dereferences correctly
695 assert_eq!(&*x, &true);
696
697 // guardian can write
698 *x = false;
699 assert_eq!(&*x, &false);
700
701 // guardian holds lock
702 assert!(base.try_lock().is_err(), "guardian holds lock");
703
704 // guardian can be moved
705 let x_ = x;
706 assert_eq!(&*x_, &false);
707
708 // moving guardian does not release lock
709 assert!(base.try_lock().is_err(), "guardian still holds lock");
710
711 // dropping guardian drops lock
712 drop(x_);
713 assert!(base.try_lock().is_ok(), "guardian drops lock");
714
715 // guardian works even after all other Arcs have been dropped
716 let x = ArcMutexGuardian::take(base).unwrap();
717 assert_eq!(&*x, &false);
718 }
719
720 #[test]
721 fn arc_mu_try() {
722 let base = sync::Arc::new(sync::Mutex::new(true));
723
724 let mut x = ArcMutexGuardian::try_take(base.clone()).unwrap().unwrap();
725
726 // guardian dereferences correctly
727 assert_eq!(&*x, &true);
728
729 // guardian can write
730 *x = false;
731 assert_eq!(&*x, &false);
732
733 // guardian holds lock
734 assert!(base.try_lock().is_err(), "guardian holds lock");
735
736 // guardian can be moved
737 let x_ = x;
738 assert_eq!(&*x_, &false);
739
740 // moving guardian does not release lock
741 assert!(base.try_lock().is_err(), "guardian still holds lock");
742
743 // try_take returns None if it would block
744 assert!(ArcMutexGuardian::try_take(base.clone()).is_none());
745
746 // dropping guardian drops lock
747 drop(x_);
748 assert!(base.try_lock().is_ok(), "guardian drops lock");
749
750 // guardian works even after all other Arcs have been dropped
751 let x = ArcMutexGuardian::take(base).unwrap();
752 assert_eq!(&*x, &false);
753 }
754
755 #[test]
756 fn rc_rw_read() {
757 let base = rc::Rc::new(sync::RwLock::new(true));
758
759 // the use of scopes below is necessary so that we can drop base at the end.
760 // otherwise, all the x1's (i.e., base.read()) would hold on to borrows.
761 // this is part of the problem that Guardian is trying to solve.
762
763 let x2 = {
764 let x1 = base.read().unwrap();
765 let x2 = RcRwLockReadGuardian::take(base.clone()).unwrap();
766
767 // guardian dereferences correctly
768 assert_eq!(&*x1, &*x2);
769
770 // guardian holds read lock
771 drop(x1);
772 assert!(base.try_write().is_err(), "guardian holds read lock");
773
774 x2
775 };
776
777 {
778 // guardian can be moved
779 let x1 = base.read().unwrap();
780 let x2_ = x2;
781 assert_eq!(&*x1, &*x2_);
782
783 // moving guardian does not release lock
784 drop(x1);
785 assert!(base.try_write().is_err(), "guardian still holds read lock");
786
787 // dropping guardian drops read lock
788 drop(x2_);
789 assert!(base.try_write().is_ok(), "guardian drops read lock");
790 }
791
792 // guardian works even after all other Rcs have been dropped
793 let x = RcRwLockReadGuardian::take(base).unwrap();
794 assert_eq!(&*x, &true);
795 }
796
797 #[test]
798 fn rc_rw_write() {
799 let base = rc::Rc::new(sync::RwLock::new(true));
800
801 let mut x = RcRwLockWriteGuardian::take(base.clone()).unwrap();
802
803 // guardian dereferences correctly
804 assert_eq!(&*x, &true);
805
806 // guardian can write
807 *x = false;
808 assert_eq!(&*x, &false);
809
810 // guardian holds write lock
811 assert!(base.try_read().is_err(), "guardian holds write lock");
812
813 // guardian can be moved
814 let x_ = x;
815 assert_eq!(&*x_, &false);
816
817 // moving guardian does not release lock
818 assert!(base.try_read().is_err(), "guardian still holds write lock");
819
820 // dropping guardian drops write lock
821 drop(x_);
822 assert!(base.try_read().is_ok(), "guardian drops write lock");
823
824 // guardian works even after all other Rcs have been dropped
825 let x = RcRwLockWriteGuardian::take(base).unwrap();
826 assert_eq!(&*x, &false);
827 }
828
829 #[test]
830 fn rc_rw_try() {
831 let base = rc::Rc::new(sync::RwLock::new(true));
832
833 let mut x = RcRwLockWriteGuardian::try_take(base.clone())
834 .unwrap()
835 .unwrap();
836
837 // guardian dereferences correctly
838 assert_eq!(&*x, &true);
839
840 // guardian can write
841 *x = false;
842 assert_eq!(&*x, &false);
843
844 // guardian holds write lock
845 assert!(base.try_read().is_err(), "guardian holds write lock");
846
847 // guardian can be moved
848 let x_ = x;
849 assert_eq!(&*x_, &false);
850
851 // moving guardian does not release lock
852 assert!(base.try_read().is_err(), "guardian still holds write lock");
853
854 // try_take returns None if it would block
855 assert!(RcRwLockWriteGuardian::try_take(base.clone()).is_none());
856
857 assert!(RcRwLockReadGuardian::try_take(base.clone()).is_none());
858
859 // dropping guardian drops write lock
860 drop(x_);
861 assert!(base.try_read().is_ok(), "guardian drops write lock");
862
863 // guardian works even after all other Rcs have been dropped
864 let x = RcRwLockWriteGuardian::take(base).unwrap();
865 assert_eq!(&*x, &false);
866 }
867
868 #[test]
869 fn rc_mu() {
870 let base = rc::Rc::new(sync::Mutex::new(true));
871
872 let mut x = RcMutexGuardian::take(base.clone()).unwrap();
873
874 // guardian dereferences correctly
875 assert_eq!(&*x, &true);
876
877 // guardian can write
878 *x = false;
879 assert_eq!(&*x, &false);
880
881 // guardian holds lock
882 assert!(base.try_lock().is_err(), "guardian holds lock");
883
884 // guardian can be moved
885 let x_ = x;
886 assert_eq!(&*x_, &false);
887
888 // moving guardian does not release lock
889 assert!(base.try_lock().is_err(), "guardian still holds lock");
890
891 // dropping guardian drops lock
892 drop(x_);
893 assert!(base.try_lock().is_ok(), "guardian drops lock");
894
895 // guardian works even after all other Rcs have been dropped
896 let x = RcMutexGuardian::take(base).unwrap();
897 assert_eq!(&*x, &false);
898 }
899
900 #[test]
901 fn rc_mu_try() {
902 let base = rc::Rc::new(sync::Mutex::new(true));
903
904 let mut x = RcMutexGuardian::take(base.clone()).unwrap();
905
906 // guardian dereferences correctly
907 assert_eq!(&*x, &true);
908
909 // guardian can write
910 *x = false;
911 assert_eq!(&*x, &false);
912
913 // guardian holds lock
914 assert!(base.try_lock().is_err(), "guardian holds lock");
915
916 // guardian can be moved
917 let x_ = x;
918 assert_eq!(&*x_, &false);
919
920 // moving guardian does not release lock
921 assert!(base.try_lock().is_err(), "guardian still holds lock");
922
923 // try_take returns None if it would block
924 assert!(RcMutexGuardian::try_take(base.clone()).is_none());
925
926 // dropping guardian drops lock
927 drop(x_);
928 assert!(base.try_lock().is_ok(), "guardian drops lock");
929
930 // guardian works even after all other Rcs have been dropped
931 let x = RcMutexGuardian::take(base).unwrap();
932 assert_eq!(&*x, &false);
933 }
934}