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 parking_lot 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::Arc;
18
19use parking_lot::RwLock;
20
21use crate::lock::{
22 Lock,
23 TryLockError,
24};
25
26/// Parking-lot read-write lock wrapper.
27///
28/// Provides an Arc-wrapped [`parking_lot::RwLock`] for synchronous shared state.
29/// Read operations can execute concurrently, while write operations have
30/// exclusive access.
31///
32/// # Features
33///
34/// - Supports multiple concurrent read operations
35/// - Write operations have exclusive access, mutually exclusive with
36/// read operations
37/// - Synchronously acquires locks, may block threads
38/// - Thread-safe, supports multi-threaded sharing
39/// - Automatic lock management through RAII ensures proper lock
40/// release
41/// - Does not use lock poisoning; panic while holding the lock does not make
42/// future acquisitions fail
43/// - Implements [`Deref`] and [`AsRef`] to expose the underlying
44/// [`parking_lot::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::{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 parking_lot 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::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 parking_lot 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 parking_lot 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 /// # Example
147 ///
148 /// ```rust
149 /// use qubit_lock::{ArcRwLock, Lock};
150 ///
151 /// let data = ArcRwLock::new(vec![1, 2, 3]);
152 ///
153 /// let length = data.read(|v| v.len());
154 /// println!("Vector length: {}", length);
155 /// ```
156 #[inline]
157 fn read<R, F>(&self, f: F) -> R
158 where
159 F: FnOnce(&T) -> R,
160 {
161 let guard = self.inner.read();
162 f(&*guard)
163 }
164
165 /// Acquires a write lock and executes an operation
166 ///
167 /// Synchronously acquires the write lock, executes the provided
168 /// closure, and then automatically releases the lock. Write
169 /// operations have exclusive access, mutually exclusive with
170 /// read operations.
171 ///
172 /// # Arguments
173 ///
174 /// * `f` - The closure to be executed while holding the write
175 /// lock, can modify data
176 ///
177 /// # Returns
178 ///
179 /// Returns the result of executing the closure
180 ///
181 /// # Example
182 ///
183 /// ```rust
184 /// use qubit_lock::{ArcRwLock, Lock};
185 ///
186 /// let data = ArcRwLock::new(vec![1, 2, 3]);
187 ///
188 /// data.write(|v| {
189 /// v.push(4);
190 /// println!("Added element, new length: {}", v.len());
191 /// });
192 /// ```
193 #[inline]
194 fn write<R, F>(&self, f: F) -> R
195 where
196 F: FnOnce(&mut T) -> R,
197 {
198 let mut guard = self.inner.write();
199 f(&mut *guard)
200 }
201
202 /// Attempts to acquire a read lock without blocking
203 ///
204 /// Attempts to immediately acquire the read lock. If the lock is
205 /// unavailable, returns a detailed error. This is a non-blocking operation.
206 ///
207 /// # Arguments
208 ///
209 /// * `f` - The closure to be executed while holding the read lock
210 ///
211 /// # Returns
212 ///
213 /// * `Ok(R)` - If the lock was successfully acquired and the closure executed
214 /// * `Err(TryLockError::WouldBlock)` - If the lock is currently held in write mode
215 ///
216 /// # Example
217 ///
218 /// ```rust
219 /// use qubit_lock::{ArcRwLock, Lock};
220 ///
221 /// let data = ArcRwLock::new(vec![1, 2, 3]);
222 ///
223 /// if let Ok(length) = data.try_read(|v| v.len()) {
224 /// println!("Vector length: {}", length);
225 /// } else {
226 /// println!("Lock is unavailable");
227 /// }
228 /// ```
229 #[inline]
230 fn try_read<R, F>(&self, f: F) -> Result<R, TryLockError>
231 where
232 F: FnOnce(&T) -> R,
233 {
234 self.inner
235 .try_read()
236 .map(|guard| f(&*guard))
237 .ok_or(TryLockError::WouldBlock)
238 }
239
240 /// Attempts to acquire a write lock without blocking
241 ///
242 /// Attempts to immediately acquire the write lock. If the lock is
243 /// unavailable, returns a detailed error. This is a non-blocking operation.
244 ///
245 /// # Arguments
246 ///
247 /// * `f` - The closure to be executed while holding the write lock
248 ///
249 /// # Returns
250 ///
251 /// * `Ok(R)` - If the lock was successfully acquired and the closure executed
252 /// * `Err(TryLockError::WouldBlock)` - If the lock is unavailable
253 ///
254 /// # Example
255 ///
256 /// ```rust
257 /// use qubit_lock::{ArcRwLock, Lock};
258 ///
259 /// let data = ArcRwLock::new(vec![1, 2, 3]);
260 ///
261 /// if let Ok(new_length) = data.try_write(|v| {
262 /// v.push(4);
263 /// v.len()
264 /// }) {
265 /// println!("New length: {}", new_length);
266 /// } else {
267 /// println!("Lock is unavailable");
268 /// }
269 /// ```
270 #[inline]
271 fn try_write<R, F>(&self, f: F) -> Result<R, TryLockError>
272 where
273 F: FnOnce(&mut T) -> R,
274 {
275 self.inner
276 .try_write()
277 .map(|mut guard| f(&mut *guard))
278 .ok_or(TryLockError::WouldBlock)
279 }
280}
281
282impl<T> From<T> for ArcRwLock<T> {
283 /// Creates an Arc-wrapped parking_lot read-write lock from a value.
284 ///
285 /// # Arguments
286 ///
287 /// * `value` - The value to protect.
288 ///
289 /// # Returns
290 ///
291 /// A new [`ArcRwLock`] protecting `value`.
292 #[inline]
293 fn from(value: T) -> Self {
294 Self::new(value)
295 }
296}
297
298impl<T: Default> Default for ArcRwLock<T> {
299 /// Creates an Arc-wrapped parking_lot read-write lock containing
300 /// `T::default()`.
301 ///
302 /// # Returns
303 ///
304 /// A new [`ArcRwLock`] protecting the default value for `T`.
305 #[inline]
306 fn default() -> Self {
307 Self::new(T::default())
308 }
309}
310
311impl<T> Clone for ArcRwLock<T> {
312 /// Clones the synchronous read-write lock
313 ///
314 /// Creates a new `ArcRwLock` instance that shares the same
315 /// underlying lock with the original instance. This allows
316 /// multiple threads to hold references to the same lock
317 /// simultaneously.
318 ///
319 /// # Returns
320 ///
321 /// A new handle sharing the same underlying read-write lock and protected
322 /// value.
323 #[inline]
324 fn clone(&self) -> Self {
325 Self {
326 inner: self.inner.clone(),
327 }
328 }
329}