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