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