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