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