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}