Skip to main content

qubit_lock/lock/
arc_mutex.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026.
4 *    Haixing Hu, Qubit Co. Ltd.
5 *
6 *    All rights reserved.
7 *
8 ******************************************************************************/
9
10//! # Synchronous Mutex Wrapper (Parking Lot)
11//!
12//! Provides an Arc-wrapped synchronous mutex using parking_lot::Mutex
13//! for protecting shared data in multi-threaded environments.
14//!
15//! # Author
16//!
17//! Haixing Hu
18
19use std::sync::Arc;
20
21use parking_lot::Mutex;
22
23use crate::lock::{
24    Lock,
25    TryLockError,
26};
27
28/// Synchronous Mutex Wrapper (Parking Lot)
29///
30/// Provides an encapsulation of synchronous mutex using parking_lot::Mutex
31/// for protecting shared data in synchronous environments. Supports safe
32/// access and modification of shared data across multiple threads.
33/// Compared to std::sync::Mutex, parking_lot::Mutex provides better
34/// performance and more ergonomic API.
35///
36/// # Features
37///
38/// - Synchronously acquires locks, may block threads
39/// - Supports trying to acquire locks (non-blocking)
40/// - Thread-safe, supports multi-threaded sharing
41/// - Automatic lock management through RAII ensures proper lock
42///   release
43/// - Better performance compared to std::sync::Mutex
44/// - More ergonomic API with no unwrap() calls
45///
46/// # Usage Example
47///
48/// ```rust
49/// use qubit_lock::lock::{ArcMutex, Lock};
50///
51/// let counter = ArcMutex::new(0);
52///
53/// // Synchronously modify data
54/// counter.write(|c| {
55///     *c += 1;
56///     println!("Counter: {}", *c);
57/// });
58///
59/// // Try to acquire lock
60/// if let Ok(value) = counter.try_read(|c| *c) {
61///     println!("Current value: {}", value);
62/// }
63/// ```
64///
65/// # Author
66///
67/// Haixing Hu
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> Lock<T> for ArcMutex<T> {
101    /// Acquires a read lock and executes an operation
102    ///
103    /// For ArcMutex, this acquires the same exclusive lock as write
104    /// operations, but provides immutable access to the data. This
105    /// ensures thread safety while allowing read-only operations.
106    ///
107    /// # Arguments
108    ///
109    /// * `f` - The closure to be executed while holding the read lock
110    ///
111    /// # Returns
112    ///
113    /// Returns the result of executing the closure
114    ///
115    /// # Example
116    ///
117    /// ```rust
118    /// use qubit_lock::lock::{ArcMutex, Lock};
119    ///
120    /// let counter = ArcMutex::new(42);
121    ///
122    /// let value = counter.read(|c| *c);
123    /// println!("Current value: {}", value);
124    /// ```
125    #[inline]
126    fn read<R, F>(&self, f: F) -> R
127    where
128        F: FnOnce(&T) -> R,
129    {
130        let guard = self.inner.lock();
131        f(&*guard)
132    }
133
134    /// Acquires a write lock and executes an operation
135    ///
136    /// Synchronously acquires the exclusive lock, executes the provided
137    /// closure with mutable access, and then automatically releases
138    /// the lock. This is the recommended usage pattern for modifications.
139    ///
140    /// # Arguments
141    ///
142    /// * `f` - The closure to be executed while holding the write lock
143    ///
144    /// # Returns
145    ///
146    /// Returns the result of executing the closure
147    ///
148    /// # Example
149    ///
150    /// ```rust
151    /// use qubit_lock::lock::{ArcMutex, Lock};
152    ///
153    /// let counter = ArcMutex::new(0);
154    ///
155    /// let result = counter.write(|c| {
156    ///     *c += 1;
157    ///     *c
158    /// });
159    ///
160    /// println!("Counter value: {}", result);
161    /// ```
162    #[inline]
163    fn write<R, F>(&self, f: F) -> R
164    where
165        F: FnOnce(&mut T) -> R,
166    {
167        let mut guard = self.inner.lock();
168        f(&mut *guard)
169    }
170
171    /// Attempts to acquire a read lock without blocking
172    ///
173    /// Attempts to immediately acquire the read lock. If the lock is
174    /// unavailable, returns a detailed error. This is a non-blocking operation.
175    ///
176    /// # Arguments
177    ///
178    /// * `f` - The closure to be executed while holding the read lock
179    ///
180    /// # Returns
181    ///
182    /// * `Ok(R)` - If the lock was successfully acquired and the closure executed
183    /// * `Err(TryLockError::WouldBlock)` - If the lock is already held by another thread
184    ///
185    /// # Example
186    ///
187    /// ```rust
188    /// use qubit_lock::lock::{ArcMutex, Lock};
189    ///
190    /// let counter = ArcMutex::new(42);
191    ///
192    /// if let Ok(value) = counter.try_read(|c| *c) {
193    ///     println!("Current value: {}", value);
194    /// } else {
195    ///     println!("Lock is unavailable");
196    /// }
197    /// ```
198    #[inline]
199    fn try_read<R, F>(&self, f: F) -> Result<R, TryLockError>
200    where
201        F: FnOnce(&T) -> R,
202    {
203        self.inner
204            .try_lock()
205            .map(|guard| f(&*guard))
206            .ok_or(TryLockError::WouldBlock)
207    }
208
209    /// Attempts to acquire a write lock without blocking
210    ///
211    /// Attempts to immediately acquire the write lock. If the lock is
212    /// unavailable, returns a detailed error. This is a non-blocking operation.
213    ///
214    /// # Arguments
215    ///
216    /// * `f` - The closure to be executed while holding the write lock
217    ///
218    /// # Returns
219    ///
220    /// * `Ok(R)` - If the lock was successfully acquired and the closure executed
221    /// * `Err(TryLockError::WouldBlock)` - If the lock is already held by another thread
222    ///
223    /// # Example
224    ///
225    /// ```rust
226    /// use qubit_lock::lock::{ArcMutex, Lock};
227    ///
228    /// let counter = ArcMutex::new(0);
229    ///
230    /// if let Ok(result) = counter.try_write(|c| {
231    ///     *c += 1;
232    ///     *c
233    /// }) {
234    ///     println!("New value: {}", result);
235    /// } else {
236    ///     println!("Lock is unavailable");
237    /// }
238    /// ```
239    #[inline]
240    fn try_write<R, F>(&self, f: F) -> Result<R, TryLockError>
241    where
242        F: FnOnce(&mut T) -> R,
243    {
244        self.inner
245            .try_lock()
246            .map(|mut guard| f(&mut *guard))
247            .ok_or(TryLockError::WouldBlock)
248    }
249}
250
251impl<T> Clone for ArcMutex<T> {
252    /// Clones the synchronous mutex
253    ///
254    /// Creates a new `ArcMutex` instance that shares the same
255    /// underlying lock with the original instance. This allows
256    /// multiple threads to hold references to the same lock
257    /// simultaneously.
258    ///
259    /// # Returns
260    ///
261    /// A new handle sharing the same underlying mutex and protected value.
262    #[inline]
263    fn clone(&self) -> Self {
264        Self {
265            inner: self.inner.clone(),
266        }
267    }
268}