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 [`Deref`] and [`AsRef`] to expose the underlying
42///   [`tokio::sync::Mutex`] API when guard-based access is needed
43///
44/// # Usage Example
45///
46/// ```rust
47/// use qubit_lock::lock::{ArcAsyncMutex, AsyncLock};
48///
49/// let rt = tokio::runtime::Builder::new_current_thread()
50///     .enable_all()
51///     .build()
52///     .unwrap();
53/// rt.block_on(async {
54///     let counter = ArcAsyncMutex::new(0);
55///
56///     // Asynchronously modify data
57///     counter.write(|c| {
58///         *c += 1;
59///         println!("Counter: {}", *c);
60///     }).await;
61///
62///     // Try to acquire lock
63///     if let Ok(value) = counter.try_read(|c| *c) {
64///         println!("Current value: {}", value);
65///     }
66/// });
67/// ```
68///
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> AsRef<AsyncMutex<T>> for ArcAsyncMutex<T> {
102    /// Returns a reference to the underlying Tokio mutex.
103    ///
104    /// This is useful when callers need guard-based APIs such as
105    /// [`AsyncMutex::lock`] or [`AsyncMutex::try_lock`] instead of the
106    /// closure-based [`AsyncLock`] methods.
107    #[inline]
108    fn as_ref(&self) -> &AsyncMutex<T> {
109        self.inner.as_ref()
110    }
111}
112
113impl<T> Deref for ArcAsyncMutex<T> {
114    type Target = AsyncMutex<T>;
115
116    /// Dereferences this wrapper to the underlying Tokio mutex.
117    ///
118    /// Method-call dereferencing lets callers use native async mutex APIs
119    /// directly, while the wrapper continues to provide the [`AsyncLock`] trait
120    /// methods.
121    #[inline]
122    fn deref(&self) -> &Self::Target {
123        self.inner.as_ref()
124    }
125}
126
127impl<T> AsyncLock<T> for ArcAsyncMutex<T>
128where
129    T: Send,
130{
131    /// Acquires the mutex and executes a read-only operation.
132    ///
133    /// # Arguments
134    ///
135    /// * `f` - Closure receiving immutable access to the protected value.
136    ///
137    /// # Returns
138    ///
139    /// A future resolving to the closure result.
140    #[inline]
141    async fn read<R, F>(&self, f: F) -> R
142    where
143        F: FnOnce(&T) -> R + Send,
144        R: Send,
145    {
146        let guard = self.inner.lock().await;
147        f(&*guard)
148    }
149
150    /// Acquires the mutex and executes a mutable operation.
151    ///
152    /// # Arguments
153    ///
154    /// * `f` - Closure receiving mutable access to the protected value.
155    ///
156    /// # Returns
157    ///
158    /// A future resolving to the closure result.
159    #[inline]
160    async fn write<R, F>(&self, f: F) -> R
161    where
162        F: FnOnce(&mut T) -> R + Send,
163        R: Send,
164    {
165        let mut guard = self.inner.lock().await;
166        f(&mut *guard)
167    }
168
169    /// Attempts to acquire the mutex for a read-only operation without waiting.
170    ///
171    /// # Arguments
172    ///
173    /// * `f` - Closure receiving immutable access when the mutex is available.
174    ///
175    /// # Returns
176    ///
177    /// `Ok(result)` if the mutex was acquired, or
178    /// [`TryLockError::WouldBlock`] if it was busy.
179    #[inline]
180    fn try_read<R, F>(&self, f: F) -> Result<R, TryLockError>
181    where
182        F: FnOnce(&T) -> R,
183    {
184        self.inner
185            .try_lock()
186            .map(|guard| f(&*guard))
187            .map_err(|_| TryLockError::WouldBlock)
188    }
189
190    /// Attempts to acquire the mutex for a mutable operation without waiting.
191    ///
192    /// # Arguments
193    ///
194    /// * `f` - Closure receiving mutable access when the mutex is available.
195    ///
196    /// # Returns
197    ///
198    /// `Ok(result)` if the mutex was acquired, or
199    /// [`TryLockError::WouldBlock`] if it was busy.
200    #[inline]
201    fn try_write<R, F>(&self, f: F) -> Result<R, TryLockError>
202    where
203        F: FnOnce(&mut T) -> R,
204    {
205        self.inner
206            .try_lock()
207            .map(|mut guard| f(&mut *guard))
208            .map_err(|_| TryLockError::WouldBlock)
209    }
210}
211
212impl<T> Clone for ArcAsyncMutex<T> {
213    /// Clones the asynchronous mutex
214    ///
215    /// Creates a new `ArcAsyncMutex` instance that shares the same
216    /// underlying lock with the original instance. This allows
217    /// multiple tasks to hold references to the same lock
218    /// simultaneously.
219    ///
220    /// # Returns
221    ///
222    /// A new handle sharing the same underlying async mutex and protected
223    /// value.
224    #[inline]
225    fn clone(&self) -> Self {
226        Self {
227            inner: self.inner.clone(),
228        }
229    }
230}