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}