Skip to main content

qubit_lock/lock/
arc_async_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//! # Asynchronous Mutex Wrapper
11//!
12//! Provides an Arc-wrapped asynchronous mutex for protecting shared
13//! data in async environments without blocking threads.
14//!
15use std::{
16    ops::Deref,
17    sync::Arc,
18};
19
20use tokio::sync::Mutex as AsyncMutex;
21
22use crate::lock::{
23    AsyncLock,
24    TryLockError,
25};
26
27/// Asynchronous Mutex Wrapper
28///
29/// Provides an encapsulation of asynchronous mutex for protecting
30/// shared data in asynchronous environments. Supports safe access
31/// and modification of shared data across multiple asynchronous
32/// tasks.
33///
34/// # Features
35///
36/// - Asynchronously acquires locks, does not 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/// - Implements [`AsyncLock`] when the protected value is `Send`
42/// - Implements [`Deref`] and [`AsRef`] to expose the underlying
43///   [`tokio::sync::Mutex`] API when guard-based access is needed
44///
45/// # Usage Example
46///
47/// ```rust
48/// use qubit_lock::{ArcAsyncMutex, AsyncLock};
49///
50/// let rt = tokio::runtime::Builder::new_current_thread()
51///     .enable_all()
52///     .build()
53///     .unwrap();
54/// rt.block_on(async {
55///     let counter = ArcAsyncMutex::new(0);
56///
57///     // Asynchronously modify data
58///     counter.write(|c| {
59///         *c += 1;
60///         println!("Counter: {}", *c);
61///     }).await;
62///
63///     // Try to acquire lock
64///     if let Ok(value) = counter.try_read(|c| *c) {
65///         println!("Current value: {}", value);
66///     }
67/// });
68/// ```
69///
70///
71pub struct ArcAsyncMutex<T> {
72    /// Shared Tokio mutex protecting the wrapped value.
73    inner: Arc<AsyncMutex<T>>,
74}
75
76impl<T> ArcAsyncMutex<T> {
77    /// Creates a new asynchronous mutex lock
78    ///
79    /// # Arguments
80    ///
81    /// * `data` - The data to be protected
82    ///
83    /// # Returns
84    ///
85    /// Returns a new `ArcAsyncMutex` instance
86    ///
87    /// # Example
88    ///
89    /// ```rust
90    /// use qubit_lock::ArcAsyncMutex;
91    ///
92    /// let lock = ArcAsyncMutex::new(42);
93    /// ```
94    #[inline]
95    pub fn new(data: T) -> Self {
96        Self {
97            inner: Arc::new(AsyncMutex::new(data)),
98        }
99    }
100}
101
102impl<T> AsRef<AsyncMutex<T>> for ArcAsyncMutex<T> {
103    /// Returns a reference to the underlying Tokio mutex.
104    ///
105    /// This is useful when callers need guard-based APIs such as
106    /// [`AsyncMutex::lock`] or [`AsyncMutex::try_lock`] instead of the
107    /// closure-based [`AsyncLock`] methods.
108    #[inline]
109    fn as_ref(&self) -> &AsyncMutex<T> {
110        self.inner.as_ref()
111    }
112}
113
114impl<T> Deref for ArcAsyncMutex<T> {
115    type Target = AsyncMutex<T>;
116
117    /// Dereferences this wrapper to the underlying Tokio mutex.
118    ///
119    /// Method-call dereferencing lets callers use native async mutex APIs
120    /// directly, while the wrapper continues to provide the [`AsyncLock`] trait
121    /// methods.
122    #[inline]
123    fn deref(&self) -> &Self::Target {
124        self.inner.as_ref()
125    }
126}
127
128impl<T> AsyncLock<T> for ArcAsyncMutex<T>
129where
130    T: Send,
131{
132    /// Acquires the mutex and executes a read-only operation.
133    ///
134    /// # Arguments
135    ///
136    /// * `f` - Closure receiving immutable access to the protected value.
137    ///
138    /// # Returns
139    ///
140    /// A future resolving to the closure result.
141    #[inline]
142    async fn read<R, F>(&self, f: F) -> R
143    where
144        F: FnOnce(&T) -> R + Send,
145        R: Send,
146    {
147        let guard = self.inner.lock().await;
148        f(&*guard)
149    }
150
151    /// Acquires the mutex and executes a mutable operation.
152    ///
153    /// # Arguments
154    ///
155    /// * `f` - Closure receiving mutable access to the protected value.
156    ///
157    /// # Returns
158    ///
159    /// A future resolving to the closure result.
160    #[inline]
161    async fn write<R, F>(&self, f: F) -> R
162    where
163        F: FnOnce(&mut T) -> R + Send,
164        R: Send,
165    {
166        let mut guard = self.inner.lock().await;
167        f(&mut *guard)
168    }
169
170    /// Attempts to acquire the mutex for a read-only operation without waiting.
171    ///
172    /// # Arguments
173    ///
174    /// * `f` - Closure receiving immutable access when the mutex is available.
175    ///
176    /// # Returns
177    ///
178    /// `Ok(result)` if the mutex was acquired, or
179    /// [`TryLockError::WouldBlock`] if it was busy.
180    #[inline]
181    fn try_read<R, F>(&self, f: F) -> Result<R, TryLockError>
182    where
183        F: FnOnce(&T) -> R,
184    {
185        self.inner
186            .try_lock()
187            .map(|guard| f(&*guard))
188            .map_err(|_| TryLockError::WouldBlock)
189    }
190
191    /// Attempts to acquire the mutex for a mutable operation without waiting.
192    ///
193    /// # Arguments
194    ///
195    /// * `f` - Closure receiving mutable access when the mutex is available.
196    ///
197    /// # Returns
198    ///
199    /// `Ok(result)` if the mutex was acquired, or
200    /// [`TryLockError::WouldBlock`] if it was busy.
201    #[inline]
202    fn try_write<R, F>(&self, f: F) -> Result<R, TryLockError>
203    where
204        F: FnOnce(&mut T) -> R,
205    {
206        self.inner
207            .try_lock()
208            .map(|mut guard| f(&mut *guard))
209            .map_err(|_| TryLockError::WouldBlock)
210    }
211}
212
213impl<T> From<T> for ArcAsyncMutex<T> {
214    /// Creates an Arc-wrapped Tokio mutex from a value.
215    ///
216    /// # Arguments
217    ///
218    /// * `value` - The value to protect.
219    ///
220    /// # Returns
221    ///
222    /// A new [`ArcAsyncMutex`] protecting `value`.
223    #[inline]
224    fn from(value: T) -> Self {
225        Self::new(value)
226    }
227}
228
229impl<T: Default> Default for ArcAsyncMutex<T> {
230    /// Creates an Arc-wrapped Tokio mutex containing `T::default()`.
231    ///
232    /// # Returns
233    ///
234    /// A new [`ArcAsyncMutex`] protecting the default value for `T`.
235    #[inline]
236    fn default() -> Self {
237        Self::new(T::default())
238    }
239}
240
241impl<T> Clone for ArcAsyncMutex<T> {
242    /// Clones the asynchronous mutex
243    ///
244    /// Creates a new `ArcAsyncMutex` instance that shares the same
245    /// underlying lock with the original instance. This allows
246    /// multiple tasks to hold references to the same lock
247    /// simultaneously.
248    ///
249    /// # Returns
250    ///
251    /// A new handle sharing the same underlying async mutex and protected
252    /// value.
253    #[inline]
254    fn clone(&self) -> Self {
255        Self {
256            inner: self.inner.clone(),
257        }
258    }
259}