qubit_lock/lock/arc_mutex.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
11//! # Synchronous Mutex Wrapper (Parking Lot)
12//!
13//! Provides an Arc-wrapped synchronous mutex using parking_lot::Mutex
14//! for protecting shared data in multi-threaded environments.
15//!
16
17use std::{
18 ops::Deref,
19 sync::Arc,
20};
21
22use parking_lot::Mutex;
23
24use crate::lock::{
25 Lock,
26 TryLockError,
27};
28
29/// Synchronous Mutex Wrapper (Parking Lot)
30///
31/// Provides an encapsulation of synchronous mutex using parking_lot::Mutex
32/// for protecting shared data in synchronous environments. Supports safe
33/// access and modification of shared data across multiple threads.
34/// Compared to std::sync::Mutex, parking_lot::Mutex provides better
35/// performance and more ergonomic API.
36///
37/// # Features
38///
39/// - Synchronously acquires locks, may block threads
40/// - Supports trying to acquire locks (non-blocking)
41/// - Thread-safe, supports multi-threaded sharing
42/// - Automatic lock management through RAII ensures proper lock
43/// release
44/// - Better performance compared to std::sync::Mutex
45/// - More ergonomic API with no unwrap() calls
46/// - Implements [`Deref`] and [`AsRef`] to expose the underlying
47/// [`parking_lot::Mutex`] API when guard-based access is needed
48///
49/// # Usage Example
50///
51/// ```rust
52/// use qubit_lock::lock::{ArcMutex, Lock};
53///
54/// let counter = ArcMutex::new(0);
55///
56/// // Synchronously modify data
57/// counter.write(|c| {
58/// *c += 1;
59/// println!("Counter: {}", *c);
60/// });
61///
62/// // Try to acquire lock
63/// if let Ok(value) = counter.try_read(|c| *c) {
64/// println!("Current value: {}", value);
65/// }
66/// ```
67///
68///
69pub struct ArcMutex<T> {
70 /// Shared parking_lot mutex protecting the wrapped value.
71 inner: Arc<Mutex<T>>,
72}
73
74impl<T> ArcMutex<T> {
75 /// Creates a new synchronous mutex lock
76 ///
77 /// # Arguments
78 ///
79 /// * `data` - The data to be protected
80 ///
81 /// # Returns
82 ///
83 /// Returns a new `ArcMutex` instance
84 ///
85 /// # Example
86 ///
87 /// ```rust
88 /// use qubit_lock::lock::ArcMutex;
89 ///
90 /// let lock = ArcMutex::new(42);
91 /// ```
92 #[inline]
93 pub fn new(data: T) -> Self {
94 Self {
95 inner: Arc::new(Mutex::new(data)),
96 }
97 }
98}
99
100impl<T> AsRef<Mutex<T>> for ArcMutex<T> {
101 /// Returns a reference to the underlying parking_lot mutex.
102 ///
103 /// This is useful when callers need guard-based APIs such as
104 /// [`Mutex::lock`] or [`Mutex::try_lock`] instead of the closure-based
105 /// [`Lock`] methods.
106 #[inline]
107 fn as_ref(&self) -> &Mutex<T> {
108 self.inner.as_ref()
109 }
110}
111
112impl<T> Deref for ArcMutex<T> {
113 type Target = Mutex<T>;
114
115 /// Dereferences this wrapper to the underlying parking_lot mutex.
116 ///
117 /// Method-call dereferencing lets callers use native mutex APIs directly,
118 /// while the wrapper continues to provide the [`Lock`] trait methods.
119 #[inline]
120 fn deref(&self) -> &Self::Target {
121 self.inner.as_ref()
122 }
123}
124
125impl<T> Lock<T> for ArcMutex<T> {
126 /// Acquires a read lock and executes an operation
127 ///
128 /// For ArcMutex, this acquires the same exclusive lock as write
129 /// operations, but provides immutable access to the data. This
130 /// ensures thread safety while allowing read-only operations.
131 ///
132 /// # Arguments
133 ///
134 /// * `f` - The closure to be executed while holding the read lock
135 ///
136 /// # Returns
137 ///
138 /// Returns the result of executing the closure
139 ///
140 /// # Example
141 ///
142 /// ```rust
143 /// use qubit_lock::lock::{ArcMutex, Lock};
144 ///
145 /// let counter = ArcMutex::new(42);
146 ///
147 /// let value = counter.read(|c| *c);
148 /// println!("Current value: {}", value);
149 /// ```
150 #[inline]
151 fn read<R, F>(&self, f: F) -> R
152 where
153 F: FnOnce(&T) -> R,
154 {
155 let guard = self.inner.lock();
156 f(&*guard)
157 }
158
159 /// Acquires a write lock and executes an operation
160 ///
161 /// Synchronously acquires the exclusive lock, executes the provided
162 /// closure with mutable access, and then automatically releases
163 /// the lock. This is the recommended usage pattern for modifications.
164 ///
165 /// # Arguments
166 ///
167 /// * `f` - The closure to be executed while holding the write lock
168 ///
169 /// # Returns
170 ///
171 /// Returns the result of executing the closure
172 ///
173 /// # Example
174 ///
175 /// ```rust
176 /// use qubit_lock::lock::{ArcMutex, Lock};
177 ///
178 /// let counter = ArcMutex::new(0);
179 ///
180 /// let result = counter.write(|c| {
181 /// *c += 1;
182 /// *c
183 /// });
184 ///
185 /// println!("Counter value: {}", result);
186 /// ```
187 #[inline]
188 fn write<R, F>(&self, f: F) -> R
189 where
190 F: FnOnce(&mut T) -> R,
191 {
192 let mut guard = self.inner.lock();
193 f(&mut *guard)
194 }
195
196 /// Attempts to acquire a read lock without blocking
197 ///
198 /// Attempts to immediately acquire the read lock. If the lock is
199 /// unavailable, returns a detailed error. This is a non-blocking operation.
200 ///
201 /// # Arguments
202 ///
203 /// * `f` - The closure to be executed while holding the read lock
204 ///
205 /// # Returns
206 ///
207 /// * `Ok(R)` - If the lock was successfully acquired and the closure executed
208 /// * `Err(TryLockError::WouldBlock)` - If the lock is already held by another thread
209 ///
210 /// # Example
211 ///
212 /// ```rust
213 /// use qubit_lock::lock::{ArcMutex, Lock};
214 ///
215 /// let counter = ArcMutex::new(42);
216 ///
217 /// if let Ok(value) = counter.try_read(|c| *c) {
218 /// println!("Current value: {}", value);
219 /// } else {
220 /// println!("Lock is unavailable");
221 /// }
222 /// ```
223 #[inline]
224 fn try_read<R, F>(&self, f: F) -> Result<R, TryLockError>
225 where
226 F: FnOnce(&T) -> R,
227 {
228 self.inner
229 .try_lock()
230 .map(|guard| f(&*guard))
231 .ok_or(TryLockError::WouldBlock)
232 }
233
234 /// Attempts to acquire a write lock without blocking
235 ///
236 /// Attempts to immediately acquire the write lock. If the lock is
237 /// unavailable, returns a detailed error. This is a non-blocking operation.
238 ///
239 /// # Arguments
240 ///
241 /// * `f` - The closure to be executed while holding the write lock
242 ///
243 /// # Returns
244 ///
245 /// * `Ok(R)` - If the lock was successfully acquired and the closure executed
246 /// * `Err(TryLockError::WouldBlock)` - If the lock is already held by another thread
247 ///
248 /// # Example
249 ///
250 /// ```rust
251 /// use qubit_lock::lock::{ArcMutex, Lock};
252 ///
253 /// let counter = ArcMutex::new(0);
254 ///
255 /// if let Ok(result) = counter.try_write(|c| {
256 /// *c += 1;
257 /// *c
258 /// }) {
259 /// println!("New value: {}", result);
260 /// } else {
261 /// println!("Lock is unavailable");
262 /// }
263 /// ```
264 #[inline]
265 fn try_write<R, F>(&self, f: F) -> Result<R, TryLockError>
266 where
267 F: FnOnce(&mut T) -> R,
268 {
269 self.inner
270 .try_lock()
271 .map(|mut guard| f(&mut *guard))
272 .ok_or(TryLockError::WouldBlock)
273 }
274}
275
276impl<T> Clone for ArcMutex<T> {
277 /// Clones the synchronous mutex
278 ///
279 /// Creates a new `ArcMutex` instance that shares the same
280 /// underlying lock with the original instance. This allows
281 /// multiple threads to hold references to the same lock
282 /// simultaneously.
283 ///
284 /// # Returns
285 ///
286 /// A new handle sharing the same underlying mutex and protected value.
287 #[inline]
288 fn clone(&self) -> Self {
289 Self {
290 inner: self.inner.clone(),
291 }
292 }
293}