qubit_lock/lock/arc_async_rw_lock.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025 - 2026.
4 * Haixing Hu, Qubit Co. Ltd.
5 *
6 * All rights reserved.
7 *
8 ******************************************************************************/
9//! # Asynchronous Read-Write Lock Wrapper
10//!
11//! Provides an Arc-wrapped asynchronous read-write lock for
12//! protecting shared data with multiple concurrent readers or a
13//! single writer in async environments.
14//!
15//! # Author
16//!
17//! Haixing Hu
18use std::sync::Arc;
19
20use tokio::sync::RwLock as AsyncRwLock;
21
22use crate::lock::{
23 AsyncLock,
24 TryLockError,
25};
26
27/// Asynchronous Read-Write Lock Wrapper
28///
29/// Provides an encapsulation of asynchronous read-write lock,
30/// supporting multiple read operations or a single write operation.
31/// Read operations can execute concurrently, while write operations
32/// have exclusive access.
33///
34/// # Features
35///
36/// - Supports multiple concurrent read operations
37/// - Write operations have exclusive access, mutually exclusive with
38/// read operations
39/// - Asynchronously acquires locks, does not block threads
40/// - Thread-safe, supports multi-threaded sharing
41/// - Automatic lock management through RAII ensures proper lock
42/// release
43///
44/// # Use Cases
45///
46/// Suitable for read-heavy scenarios such as caching, configuration
47/// management, etc.
48///
49/// # Usage Example
50///
51/// ```rust
52/// use qubit_lock::lock::{ArcAsyncRwLock, AsyncLock};
53///
54/// let rt = tokio::runtime::Builder::new_current_thread()
55/// .enable_all()
56/// .build()
57/// .unwrap();
58/// rt.block_on(async {
59/// let data = ArcAsyncRwLock::new(String::from("Hello"));
60///
61/// // Multiple read operations can execute concurrently
62/// data.read(|s| {
63/// println!("Read: {}", s);
64/// }).await;
65///
66/// // Write operations have exclusive access
67/// data.write(|s| {
68/// s.push_str(" World!");
69/// println!("Write: {}", s);
70/// }).await;
71/// });
72/// ```
73///
74/// # Author
75///
76/// Haixing Hu
77///
78pub struct ArcAsyncRwLock<T> {
79 /// Shared Tokio read-write lock protecting the wrapped value.
80 inner: Arc<AsyncRwLock<T>>,
81}
82
83impl<T> ArcAsyncRwLock<T> {
84 /// Creates a new asynchronous read-write lock
85 ///
86 /// # Arguments
87 ///
88 /// * `data` - The data to be protected
89 ///
90 /// # Returns
91 ///
92 /// Returns a new `ArcAsyncRwLock` instance
93 ///
94 /// # Example
95 ///
96 /// ```rust
97 /// use qubit_lock::lock::ArcAsyncRwLock;
98 ///
99 /// let rw_lock = ArcAsyncRwLock::new(vec![1, 2, 3]);
100 /// ```
101 #[inline]
102 pub fn new(data: T) -> Self {
103 Self {
104 inner: Arc::new(AsyncRwLock::new(data)),
105 }
106 }
107}
108
109impl<T> AsyncLock<T> for ArcAsyncRwLock<T>
110where
111 T: Send + Sync,
112{
113 /// Acquires the read lock and executes an operation
114 ///
115 /// Asynchronously acquires the read lock, executes the provided
116 /// closure, and then automatically releases the lock. Multiple
117 /// read operations can execute concurrently.
118 ///
119 /// # Arguments
120 ///
121 /// * `f` - The closure to be executed while holding the read
122 /// lock, can only read data
123 ///
124 /// # Returns
125 ///
126 /// Returns a future that resolves to the result of executing
127 /// the closure
128 ///
129 /// # Example
130 ///
131 /// ```rust
132 /// use qubit_lock::lock::{ArcAsyncRwLock, AsyncLock};
133 ///
134 /// let rt = tokio::runtime::Builder::new_current_thread()
135 /// .enable_all()
136 /// .build()
137 /// .unwrap();
138 /// rt.block_on(async {
139 /// let data = ArcAsyncRwLock::new(vec![1, 2, 3]);
140 ///
141 /// let length = data.read(|v| v.len()).await;
142 /// println!("Vector length: {}", length);
143 /// });
144 /// ```
145 #[inline]
146 async fn read<R, F>(&self, f: F) -> R
147 where
148 F: FnOnce(&T) -> R + Send,
149 R: Send,
150 {
151 let guard = self.inner.read().await;
152 f(&*guard)
153 }
154
155 /// Acquires the write lock and executes an operation
156 ///
157 /// Asynchronously acquires the write lock, executes the provided
158 /// closure, and then automatically releases the lock. Write
159 /// operations have exclusive access, mutually exclusive with
160 /// read operations.
161 ///
162 /// # Arguments
163 ///
164 /// * `f` - The closure to be executed while holding the write
165 /// lock, can modify data
166 ///
167 /// # Returns
168 ///
169 /// Returns a future that resolves to the result of executing
170 /// the closure
171 ///
172 /// # Example
173 ///
174 /// ```rust
175 /// use qubit_lock::lock::{ArcAsyncRwLock, AsyncLock};
176 ///
177 /// let rt = tokio::runtime::Builder::new_current_thread()
178 /// .enable_all()
179 /// .build()
180 /// .unwrap();
181 /// rt.block_on(async {
182 /// let data = ArcAsyncRwLock::new(vec![1, 2, 3]);
183 ///
184 /// data.write(|v| {
185 /// v.push(4);
186 /// println!("Added element, new length: {}", v.len());
187 /// }).await;
188 /// });
189 /// ```
190 #[inline]
191 async fn write<R, F>(&self, f: F) -> R
192 where
193 F: FnOnce(&mut T) -> R + Send,
194 R: Send,
195 {
196 let mut guard = self.inner.write().await;
197 f(&mut *guard)
198 }
199
200 /// Attempts to acquire the read lock without waiting.
201 ///
202 /// # Arguments
203 ///
204 /// * `f` - Closure receiving immutable access when a read lock is
205 /// available.
206 ///
207 /// # Returns
208 ///
209 /// `Ok(result)` if a read lock was acquired, or
210 /// [`TryLockError::WouldBlock`] if the lock was busy.
211 #[inline]
212 fn try_read<R, F>(&self, f: F) -> Result<R, TryLockError>
213 where
214 F: FnOnce(&T) -> R,
215 {
216 self.inner
217 .try_read()
218 .map(|guard| f(&*guard))
219 .map_err(|_| TryLockError::WouldBlock)
220 }
221
222 /// Attempts to acquire the write lock without waiting.
223 ///
224 /// # Arguments
225 ///
226 /// * `f` - Closure receiving mutable access when a write lock is available.
227 ///
228 /// # Returns
229 ///
230 /// `Ok(result)` if a write lock was acquired, or
231 /// [`TryLockError::WouldBlock`] if the lock was busy.
232 #[inline]
233 fn try_write<R, F>(&self, f: F) -> Result<R, TryLockError>
234 where
235 F: FnOnce(&mut T) -> R,
236 {
237 self.inner
238 .try_write()
239 .map(|mut guard| f(&mut *guard))
240 .map_err(|_| TryLockError::WouldBlock)
241 }
242}
243
244impl<T> Clone for ArcAsyncRwLock<T> {
245 /// Clones the asynchronous read-write lock
246 ///
247 /// Creates a new `ArcAsyncRwLock` instance that shares the same
248 /// underlying lock with the original instance. This allows
249 /// multiple tasks to hold references to the same lock
250 /// simultaneously.
251 ///
252 /// # Returns
253 ///
254 /// A new handle sharing the same underlying async read-write lock and
255 /// protected value.
256 #[inline]
257 fn clone(&self) -> Self {
258 Self {
259 inner: self.inner.clone(),
260 }
261 }
262}