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}