Skip to main content

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