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}