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}