|
1 |
| -//! Reference-counted async lock. |
| 1 | +//! Async locking primitives. |
2 | 2 | //!
|
3 |
| -//! The [`Lock`] type is similar to [`std::sync::Mutex`], except locking is an async operation. |
| 3 | +//! This crate provides two primitives: |
4 | 4 | //!
|
5 |
| -//! Note that [`Lock`] by itself acts like an [`Arc`] in the sense that cloning it returns just |
6 |
| -//! another reference to the same lock. |
7 |
| -//! |
8 |
| -//! Furthermore, [`LockGuard`] is not tied to [`Lock`] by a lifetime, so you can keep guards for |
9 |
| -//! as long as you want. This is useful when you want to spawn a task and move a guard into its |
10 |
| -//! future. |
11 |
| -//! |
12 |
| -//! The locking mechanism uses eventual fairness to ensure locking will be fair on average without |
13 |
| -//! sacrificing performance. This is done by forcing a fair lock whenever a lock operation is |
14 |
| -//! starved for longer than 0.5 milliseconds. |
15 |
| -//! |
16 |
| -//! # Examples |
17 |
| -//! |
18 |
| -//! ``` |
19 |
| -//! # smol::run(async { |
20 |
| -//! use async_lock::Lock; |
21 |
| -//! use smol::Task; |
22 |
| -//! |
23 |
| -//! let lock = Lock::new(0); |
24 |
| -//! let mut tasks = vec![]; |
25 |
| -//! |
26 |
| -//! for _ in 0..10 { |
27 |
| -//! let lock = lock.clone(); |
28 |
| -//! tasks.push(Task::spawn(async move { *lock.lock().await += 1 })); |
29 |
| -//! } |
30 |
| -//! |
31 |
| -//! for task in tasks { |
32 |
| -//! task.await; |
33 |
| -//! } |
34 |
| -//! assert_eq!(*lock.lock().await, 10); |
35 |
| -//! # }) |
36 |
| -//! ``` |
| 5 | +//! * [`Mutex`] - a mutual exclusion lock. |
| 6 | +//! * [`RwLock`] - a reader-writer lock, allowing any number of readers or a single writer. |
37 | 7 |
|
38 | 8 | #![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
|
39 | 9 |
|
40 |
| -use std::cell::UnsafeCell; |
41 |
| -use std::fmt; |
42 |
| -use std::mem; |
43 |
| -use std::ops::{Deref, DerefMut}; |
44 |
| -use std::sync::Arc; |
45 |
| - |
46 |
| -use async_mutex::{Mutex, MutexGuard}; |
47 |
| - |
48 |
| -/// An async lock. |
49 |
| -pub struct Lock<T>(Arc<Inner<T>>); |
50 |
| - |
51 |
| -unsafe impl<T: Send> Send for Lock<T> {} |
52 |
| -unsafe impl<T: Send> Sync for Lock<T> {} |
53 |
| - |
54 |
| -impl<T> Clone for Lock<T> { |
55 |
| - fn clone(&self) -> Lock<T> { |
56 |
| - Lock(self.0.clone()) |
57 |
| - } |
58 |
| -} |
59 |
| - |
60 |
| -/// Data inside [`Lock`]. |
61 |
| -struct Inner<T> { |
62 |
| - /// The inner mutex. |
63 |
| - mutex: Mutex<()>, |
64 |
| - |
65 |
| - /// The value inside the lock. |
66 |
| - data: UnsafeCell<T>, |
67 |
| -} |
68 |
| - |
69 |
| -unsafe impl<T: Send> Send for Inner<T> {} |
70 |
| -unsafe impl<T: Send> Sync for Inner<T> {} |
71 |
| - |
72 |
| -impl<T> Lock<T> { |
73 |
| - /// Creates a new async lock. |
74 |
| - /// |
75 |
| - /// # Examples |
76 |
| - /// |
77 |
| - /// ``` |
78 |
| - /// use async_lock::Lock; |
79 |
| - /// |
80 |
| - /// let lock = Lock::new(0); |
81 |
| - /// ``` |
82 |
| - pub fn new(data: T) -> Lock<T> { |
83 |
| - Lock(Arc::new(Inner { |
84 |
| - mutex: Mutex::new(()), |
85 |
| - data: UnsafeCell::new(data), |
86 |
| - })) |
87 |
| - } |
88 |
| - |
89 |
| - /// Acquires the lock. |
90 |
| - /// |
91 |
| - /// Returns a guard that releases the lock when dropped. |
92 |
| - /// |
93 |
| - /// # Examples |
94 |
| - /// |
95 |
| - /// ``` |
96 |
| - /// # smol::block_on(async { |
97 |
| - /// use async_lock::Lock; |
98 |
| - /// |
99 |
| - /// let lock = Lock::new(10); |
100 |
| - /// let guard = lock.lock().await; |
101 |
| - /// assert_eq!(*guard, 10); |
102 |
| - /// # }) |
103 |
| - /// ``` |
104 |
| - #[inline] |
105 |
| - pub async fn lock(&self) -> LockGuard<T> { |
106 |
| - LockGuard::new(self.clone(), self.0.mutex.lock().await) |
107 |
| - } |
108 |
| - |
109 |
| - /// Attempts to acquire the lock. |
110 |
| - /// |
111 |
| - /// If the lock could not be acquired at this time, then [`None`] is returned. Otherwise, a |
112 |
| - /// guard is returned that releases the lock when dropped. |
113 |
| - /// |
114 |
| - /// # Examples |
115 |
| - /// |
116 |
| - /// ``` |
117 |
| - /// use async_lock::Lock; |
118 |
| - /// |
119 |
| - /// let lock = Lock::new(10); |
120 |
| - /// if let Some(guard) = lock.try_lock() { |
121 |
| - /// assert_eq!(*guard, 10); |
122 |
| - /// } |
123 |
| - /// # ; |
124 |
| - /// ``` |
125 |
| - #[inline] |
126 |
| - pub fn try_lock(&self) -> Option<LockGuard<T>> { |
127 |
| - self.0 |
128 |
| - .mutex |
129 |
| - .try_lock() |
130 |
| - .map(|guard| LockGuard::new(self.clone(), guard)) |
131 |
| - } |
132 |
| -} |
133 |
| - |
134 |
| -impl<T: fmt::Debug> fmt::Debug for Lock<T> { |
135 |
| - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
136 |
| - struct Locked; |
137 |
| - impl fmt::Debug for Locked { |
138 |
| - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
139 |
| - f.write_str("<locked>") |
140 |
| - } |
141 |
| - } |
142 |
| - |
143 |
| - match self.try_lock() { |
144 |
| - None => f.debug_struct("Lock").field("data", &Locked).finish(), |
145 |
| - Some(guard) => f.debug_struct("Lock").field("data", &&*guard).finish(), |
146 |
| - } |
147 |
| - } |
148 |
| -} |
149 |
| - |
150 |
| -impl<T> From<T> for Lock<T> { |
151 |
| - fn from(val: T) -> Lock<T> { |
152 |
| - Lock::new(val) |
153 |
| - } |
154 |
| -} |
155 |
| - |
156 |
| -impl<T: Default> Default for Lock<T> { |
157 |
| - fn default() -> Lock<T> { |
158 |
| - Lock::new(Default::default()) |
159 |
| - } |
160 |
| -} |
161 |
| - |
162 |
| -/// A guard that releases the lock when dropped. |
163 |
| -pub struct LockGuard<T>(Lock<T>, MutexGuard<'static, ()>); |
164 |
| - |
165 |
| -unsafe impl<T: Send> Send for LockGuard<T> {} |
166 |
| -unsafe impl<T: Sync> Sync for LockGuard<T> {} |
167 |
| - |
168 |
| -impl<T> LockGuard<T> { |
169 |
| - fn new(lock: Lock<T>, inner: MutexGuard<'_, ()>) -> LockGuard<T> { |
170 |
| - let inner = unsafe { mem::transmute::<MutexGuard<'_, ()>, MutexGuard<'static, ()>>(inner) }; |
171 |
| - LockGuard(lock, inner) |
172 |
| - } |
173 |
| - |
174 |
| - /// Returns a reference to the lock a guard came from. |
175 |
| - /// |
176 |
| - /// # Examples |
177 |
| - /// |
178 |
| - /// ``` |
179 |
| - /// # smol::block_on(async { |
180 |
| - /// use async_lock::{Lock, LockGuard}; |
181 |
| - /// |
182 |
| - /// let lock = Lock::new(10i32); |
183 |
| - /// let guard = lock.lock().await; |
184 |
| - /// dbg!(LockGuard::source(&guard)); |
185 |
| - /// # }) |
186 |
| - /// ``` |
187 |
| - pub fn source(guard: &LockGuard<T>) -> &Lock<T> { |
188 |
| - &guard.0 |
189 |
| - } |
190 |
| -} |
191 |
| - |
192 |
| -impl<T: fmt::Debug> fmt::Debug for LockGuard<T> { |
193 |
| - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
194 |
| - fmt::Debug::fmt(&**self, f) |
195 |
| - } |
196 |
| -} |
197 |
| - |
198 |
| -impl<T: fmt::Display> fmt::Display for LockGuard<T> { |
199 |
| - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
200 |
| - (**self).fmt(f) |
201 |
| - } |
202 |
| -} |
203 |
| - |
204 |
| -impl<T> Deref for LockGuard<T> { |
205 |
| - type Target = T; |
206 |
| - |
207 |
| - fn deref(&self) -> &T { |
208 |
| - unsafe { &*(self.0).0.data.get() } |
209 |
| - } |
210 |
| -} |
211 |
| - |
212 |
| -impl<T> DerefMut for LockGuard<T> { |
213 |
| - fn deref_mut(&mut self) -> &mut T { |
214 |
| - unsafe { &mut *(self.0).0.data.get() } |
215 |
| - } |
216 |
| -} |
217 |
| - |
218 |
| -/// Calls a function when dropped. |
219 |
| -struct CallOnDrop<F: Fn()>(F); |
220 |
| - |
221 |
| -impl<F: Fn()> Drop for CallOnDrop<F> { |
222 |
| - fn drop(&mut self) { |
223 |
| - (self.0)(); |
224 |
| - } |
225 |
| -} |
| 10 | +#[doc(inline)] |
| 11 | +pub use { |
| 12 | + async_mutex::{Mutex, MutexGuard}, |
| 13 | + async_rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}, |
| 14 | +}; |
0 commit comments