Skip to main content

qubit_lock/lock/
arc_rw_lock.rs

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