Skip to main content

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}