Skip to main content

qubit_lock/lock/
arc_rw_lock.rs

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