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}