Skip to main content

qubit_lock/lock/
arc_async_mutex.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026.
4 *    Haixing Hu, Qubit Co. Ltd.
5 *
6 *    All rights reserved.
7 *
8 ******************************************************************************/
9//! # Asynchronous Mutex Wrapper
10//!
11//! Provides an Arc-wrapped asynchronous mutex for protecting shared
12//! data in async environments without blocking threads.
13//!
14//! # Author
15//!
16//! Haixing Hu
17use std::sync::Arc;
18
19use tokio::sync::Mutex as AsyncMutex;
20
21use crate::lock::{
22    AsyncLock,
23    TryLockError,
24};
25
26/// Asynchronous Mutex Wrapper
27///
28/// Provides an encapsulation of asynchronous mutex for protecting
29/// shared data in asynchronous environments. Supports safe access
30/// and modification of shared data across multiple asynchronous
31/// tasks.
32///
33/// # Features
34///
35/// - Asynchronously acquires locks, does not 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///
41/// # Usage Example
42///
43/// ```rust
44/// use qubit_lock::lock::{ArcAsyncMutex, AsyncLock};
45///
46/// let rt = tokio::runtime::Builder::new_current_thread()
47///     .enable_all()
48///     .build()
49///     .unwrap();
50/// rt.block_on(async {
51///     let counter = ArcAsyncMutex::new(0);
52///
53///     // Asynchronously modify data
54///     counter.write(|c| {
55///         *c += 1;
56///         println!("Counter: {}", *c);
57///     }).await;
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///
66/// # Author
67///
68/// Haixing Hu
69///
70pub struct ArcAsyncMutex<T> {
71    /// Shared Tokio mutex protecting the wrapped value.
72    inner: Arc<AsyncMutex<T>>,
73}
74
75impl<T> ArcAsyncMutex<T> {
76    /// Creates a new asynchronous mutex lock
77    ///
78    /// # Arguments
79    ///
80    /// * `data` - The data to be protected
81    ///
82    /// # Returns
83    ///
84    /// Returns a new `ArcAsyncMutex` instance
85    ///
86    /// # Example
87    ///
88    /// ```rust
89    /// use qubit_lock::lock::ArcAsyncMutex;
90    ///
91    /// let lock = ArcAsyncMutex::new(42);
92    /// ```
93    #[inline]
94    pub fn new(data: T) -> Self {
95        Self {
96            inner: Arc::new(AsyncMutex::new(data)),
97        }
98    }
99}
100
101impl<T> AsyncLock<T> for ArcAsyncMutex<T>
102where
103    T: Send,
104{
105    /// Acquires the mutex and executes a read-only operation.
106    ///
107    /// # Arguments
108    ///
109    /// * `f` - Closure receiving immutable access to the protected value.
110    ///
111    /// # Returns
112    ///
113    /// A future resolving to the closure result.
114    #[inline]
115    async fn read<R, F>(&self, f: F) -> R
116    where
117        F: FnOnce(&T) -> R + Send,
118        R: Send,
119    {
120        let guard = self.inner.lock().await;
121        f(&*guard)
122    }
123
124    /// Acquires the mutex and executes a mutable operation.
125    ///
126    /// # Arguments
127    ///
128    /// * `f` - Closure receiving mutable access to the protected value.
129    ///
130    /// # Returns
131    ///
132    /// A future resolving to the closure result.
133    #[inline]
134    async fn write<R, F>(&self, f: F) -> R
135    where
136        F: FnOnce(&mut T) -> R + Send,
137        R: Send,
138    {
139        let mut guard = self.inner.lock().await;
140        f(&mut *guard)
141    }
142
143    /// Attempts to acquire the mutex for a read-only operation without waiting.
144    ///
145    /// # Arguments
146    ///
147    /// * `f` - Closure receiving immutable access when the mutex is available.
148    ///
149    /// # Returns
150    ///
151    /// `Ok(result)` if the mutex was acquired, or
152    /// [`TryLockError::WouldBlock`] if it was busy.
153    #[inline]
154    fn try_read<R, F>(&self, f: F) -> Result<R, TryLockError>
155    where
156        F: FnOnce(&T) -> R,
157    {
158        self.inner
159            .try_lock()
160            .map(|guard| f(&*guard))
161            .map_err(|_| TryLockError::WouldBlock)
162    }
163
164    /// Attempts to acquire the mutex for a mutable operation without waiting.
165    ///
166    /// # Arguments
167    ///
168    /// * `f` - Closure receiving mutable access when the mutex is available.
169    ///
170    /// # Returns
171    ///
172    /// `Ok(result)` if the mutex was acquired, or
173    /// [`TryLockError::WouldBlock`] if it was busy.
174    #[inline]
175    fn try_write<R, F>(&self, f: F) -> Result<R, TryLockError>
176    where
177        F: FnOnce(&mut T) -> R,
178    {
179        self.inner
180            .try_lock()
181            .map(|mut guard| f(&mut *guard))
182            .map_err(|_| TryLockError::WouldBlock)
183    }
184}
185
186impl<T> Clone for ArcAsyncMutex<T> {
187    /// Clones the asynchronous mutex
188    ///
189    /// Creates a new `ArcAsyncMutex` instance that shares the same
190    /// underlying lock with the original instance. This allows
191    /// multiple tasks to hold references to the same lock
192    /// simultaneously.
193    ///
194    /// # Returns
195    ///
196    /// A new handle sharing the same underlying async mutex and protected
197    /// value.
198    #[inline]
199    fn clone(&self) -> Self {
200        Self {
201            inner: self.inner.clone(),
202        }
203    }
204}