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}