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