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}