Skip to main content

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}