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