quick_cache/
rw_lock.rs

1use std::ops::{Deref, DerefMut};
2
3#[cfg(feature = "parking_lot")]
4type InnerRwLock<T> = parking_lot::RwLock<T>;
5#[cfg(not(feature = "parking_lot"))]
6type InnerRwLock<T> = std::sync::RwLock<T>;
7
8#[cfg(feature = "parking_lot")]
9type InnerRwLockReadGuard<'rwlock, T> = parking_lot::RwLockReadGuard<'rwlock, T>;
10#[cfg(not(feature = "parking_lot"))]
11type InnerRwLockReadGuard<'rwlock, T> = std::sync::RwLockReadGuard<'rwlock, T>;
12
13#[cfg(feature = "parking_lot")]
14type InnerRwLockWriteGuard<'rwlock, T> = parking_lot::RwLockWriteGuard<'rwlock, T>;
15#[cfg(not(feature = "parking_lot"))]
16type InnerRwLockWriteGuard<'rwlock, T> = std::sync::RwLockWriteGuard<'rwlock, T>;
17
18/// A reader-writer lock.
19///
20/// This type of lock allows a number of readers or at most one writer at any
21/// point in time. The write portion of this lock typically allows modification
22/// of the underlying data (exclusive access) and the read portion of this lock
23/// typically allows for read-only access (shared access).
24///
25/// In comparison, a [`Mutex`] does not distinguish between readers or writers
26/// that acquire the lock, therefore blocking any threads waiting for the lock to
27/// become available. An `RwLock` will allow any number of readers to acquire the
28/// lock as long as a writer is not holding the lock.
29///
30/// The type parameter `T` represents the data that this lock protects. It is
31/// required that `T` satisfies [`Send`] to be shared across threads and
32/// [`Sync`] to allow concurrent access through readers. The RAII guards
33/// returned from the locking methods implement [`Deref`] (and [`DerefMut`]
34/// for the `write` methods) to allow access to the content of the lock.
35///
36/// # Poisoning
37///
38/// An `RwLock` might become poisoned on a panic. Note, however, that an `RwLock`
39/// may only be poisoned if a panic occurs while it is locked exclusively (write
40/// mode). If a panic occurs in any reader, then the lock will not be poisoned.
41#[derive(Default, Debug)]
42#[repr(transparent)]
43pub struct RwLock<T: ?Sized>(InnerRwLock<T>);
44
45/// RAII structure used to release the shared read access of a lock when dropped.
46#[repr(transparent)]
47#[must_use = "if unused the RwLock will immediately unlock"]
48pub struct RwLockReadGuard<'rwlock, T: ?Sized>(InnerRwLockReadGuard<'rwlock, T>);
49
50/// RAII structure used to release the exclusive write access of a lock when dropped.
51#[repr(transparent)]
52#[must_use = "if unused the RwLock will immediately unlock"]
53pub struct RwLockWriteGuard<'rwlock, T: ?Sized>(InnerRwLockWriteGuard<'rwlock, T>);
54
55impl<T> RwLock<T> {
56    /// Creates a new instance of an `RwLock<T>` which is unlocked.
57    pub const fn new(t: T) -> Self {
58        Self(InnerRwLock::new(t))
59    }
60}
61
62impl<T: ?Sized> RwLock<T> {
63    /// Locks this `RwLock` with shared read access, blocking the current thread
64    /// until it can be acquired.
65    ///
66    /// The calling thread will be blocked until there are no more writers which
67    /// hold the lock. There may be other readers currently inside the lock when
68    /// this method returns. This method does not provide any guarantees with
69    /// respect to the ordering of whether contentious readers or writers will
70    /// acquire the lock first.
71    ///
72    /// Returns an RAII guard which will release this thread's shared access
73    /// once it is dropped.
74    ///
75    /// # Panics
76    ///
77    /// This function might panic when called if the lock is already held by the
78    /// current thread, or if the `RwLock` is poisoned. An `RwLock` might be
79    /// poisoned whenever a writer panics while holding an exclusive lock.
80    /// Implementations are not required to implement poisoning.
81    #[inline]
82    pub fn read(&self) -> RwLockReadGuard<'_, T> {
83        RwLockReadGuard({
84            #[cfg(feature = "parking_lot")]
85            {
86                self.0.read()
87            }
88            #[cfg(not(feature = "parking_lot"))]
89            self.0.read().unwrap()
90        })
91    }
92
93    /// Locks this `RwLock` with exclusive write access, blocking the current
94    /// thread until it can be acquired.
95    ///
96    /// This function will not return while other writers or other readers
97    /// currently have access to the lock.
98    ///
99    /// Returns an RAII guard which will drop the write access of this `RwLock`
100    /// when dropped.
101    ///
102    /// # Panics
103    ///
104    /// This function might panic when called if the lock is already held by the
105    /// current thread, or if the `RwLock` is poisoned. An `RwLock` might be
106    /// poisoned whenever a writer panics while holding an exclusive lock.
107    /// Implementations are not required to implement poisoning.
108    #[inline]
109    pub fn write(&self) -> RwLockWriteGuard<'_, T> {
110        RwLockWriteGuard({
111            #[cfg(feature = "parking_lot")]
112            {
113                self.0.write()
114            }
115            #[cfg(not(feature = "parking_lot"))]
116            self.0.write().unwrap()
117        })
118    }
119}
120
121impl<T: ?Sized> Deref for RwLockReadGuard<'_, T> {
122    type Target = T;
123
124    fn deref(&self) -> &Self::Target {
125        &self.0
126    }
127}
128
129impl<T: ?Sized> Deref for RwLockWriteGuard<'_, T> {
130    type Target = T;
131
132    fn deref(&self) -> &Self::Target {
133        &self.0
134    }
135}
136
137impl<T: ?Sized> DerefMut for RwLockWriteGuard<'_, T> {
138    fn deref_mut(&mut self) -> &mut Self::Target {
139        &mut self.0
140    }
141}