qubit_lock/lock/arc_std_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//! # Synchronous Standard Mutex Wrapper
11//!
12//! Provides an Arc-wrapped synchronous mutex using std::sync::Mutex
13//! for protecting shared data in multi-threaded environments.
14//!
15
16use std::ops::Deref;
17use std::sync::{
18 Arc,
19 Mutex,
20};
21
22use crate::lock::{
23 Lock,
24 TryLockError,
25};
26
27/// Synchronous Standard Mutex Wrapper
28///
29/// Provides an encapsulation of synchronous mutex using std::sync::Mutex
30/// for protecting shared data in synchronous environments. Supports safe
31/// access and modification of shared data across multiple threads.
32///
33/// # Features
34///
35/// - Synchronously acquires locks, may 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/// - Implements [`Deref`] and [`AsRef`] to expose the underlying
41/// [`std::sync::Mutex`] API when guard-based access is needed
42///
43/// # Usage Example
44///
45/// ```rust
46/// use qubit_lock::lock::{ArcStdMutex, Lock};
47///
48/// let counter = ArcStdMutex::new(0);
49///
50/// // Synchronously modify data
51/// counter.write(|c| {
52/// *c += 1;
53/// println!("Counter: {}", *c);
54/// });
55///
56/// // Try to acquire lock
57/// if let Ok(value) = counter.try_read(|c| *c) {
58/// println!("Current value: {}", value);
59/// }
60/// ```
61///
62///
63pub struct ArcStdMutex<T> {
64 /// Shared standard mutex protecting the wrapped value.
65 inner: Arc<Mutex<T>>,
66}
67
68impl<T> ArcStdMutex<T> {
69 /// Creates a new synchronous mutex lock
70 ///
71 /// # Arguments
72 ///
73 /// * `data` - The data to be protected
74 ///
75 /// # Returns
76 ///
77 /// Returns a new `ArcStdMutex` instance
78 ///
79 /// # Example
80 ///
81 /// ```rust
82 /// use qubit_lock::lock::ArcStdMutex;
83 ///
84 /// let lock = ArcStdMutex::new(42);
85 /// ```
86 #[inline]
87 pub fn new(data: T) -> Self {
88 Self {
89 inner: Arc::new(Mutex::new(data)),
90 }
91 }
92}
93
94impl<T> AsRef<Mutex<T>> for ArcStdMutex<T> {
95 /// Returns a reference to the underlying standard mutex.
96 ///
97 /// This is useful when callers need guard-based APIs such as
98 /// [`Mutex::lock`] or [`Mutex::try_lock`] instead of the closure-based
99 /// [`Lock`] methods.
100 #[inline]
101 fn as_ref(&self) -> &Mutex<T> {
102 self.inner.as_ref()
103 }
104}
105
106impl<T> Deref for ArcStdMutex<T> {
107 type Target = Mutex<T>;
108
109 /// Dereferences this wrapper to the underlying standard mutex.
110 ///
111 /// Method-call dereferencing lets callers use native mutex APIs directly,
112 /// while the wrapper continues to provide the [`Lock`] trait methods.
113 #[inline]
114 fn deref(&self) -> &Self::Target {
115 self.inner.as_ref()
116 }
117}
118
119impl<T> Lock<T> for ArcStdMutex<T> {
120 /// Acquires a read lock and executes an operation
121 ///
122 /// For ArcStdMutex, this acquires the same exclusive lock as write
123 /// operations, but provides immutable access to the data. This
124 /// ensures thread safety while allowing read-only operations.
125 ///
126 /// # Arguments
127 ///
128 /// * `f` - The closure to be executed while holding the read lock
129 ///
130 /// # Returns
131 ///
132 /// Returns the result of executing the closure
133 ///
134 /// # Panics
135 ///
136 /// Panics if the underlying standard mutex is poisoned.
137 ///
138 /// # Example
139 ///
140 /// ```rust
141 /// use qubit_lock::lock::{ArcStdMutex, Lock};
142 ///
143 /// let counter = ArcStdMutex::new(42);
144 ///
145 /// let value = counter.read(|c| *c);
146 /// println!("Current value: {}", value);
147 /// ```
148 #[inline]
149 fn read<R, F>(&self, f: F) -> R
150 where
151 F: FnOnce(&T) -> R,
152 {
153 let guard = self.inner.lock().unwrap();
154 f(&*guard)
155 }
156
157 /// Acquires a write lock and executes an operation
158 ///
159 /// Synchronously acquires the exclusive lock, executes the provided
160 /// closure with mutable access, and then automatically releases
161 /// the lock. This is the recommended usage pattern for modifications.
162 ///
163 /// # Arguments
164 ///
165 /// * `f` - The closure to be executed while holding the write lock
166 ///
167 /// # Returns
168 ///
169 /// Returns the result of executing the closure
170 ///
171 /// # Panics
172 ///
173 /// Panics if the underlying standard mutex is poisoned.
174 ///
175 /// # Example
176 ///
177 /// ```rust
178 /// use qubit_lock::lock::{ArcStdMutex, Lock};
179 ///
180 /// let counter = ArcStdMutex::new(0);
181 ///
182 /// let result = counter.write(|c| {
183 /// *c += 1;
184 /// *c
185 /// });
186 ///
187 /// println!("Counter value: {}", result);
188 /// ```
189 #[inline]
190 fn write<R, F>(&self, f: F) -> R
191 where
192 F: FnOnce(&mut T) -> R,
193 {
194 let mut guard = self.inner.lock().unwrap();
195 f(&mut *guard)
196 }
197
198 /// Attempts to acquire a read lock without blocking
199 ///
200 /// Attempts to immediately acquire the read lock. If the lock is
201 /// unavailable, returns a detailed error. This is a non-blocking operation.
202 ///
203 /// # Arguments
204 ///
205 /// * `f` - The closure to be executed while holding the read lock
206 ///
207 /// # Returns
208 ///
209 /// * `Ok(R)` - If the lock was successfully acquired and the closure executed
210 /// * `Err(TryLockError::WouldBlock)` - If the lock is already held by another thread
211 /// * `Err(TryLockError::Poisoned)` - If the lock is poisoned
212 ///
213 /// # Example
214 ///
215 /// ```rust
216 /// use qubit_lock::lock::{ArcStdMutex, Lock};
217 ///
218 /// let counter = ArcStdMutex::new(42);
219 ///
220 /// if let Ok(value) = counter.try_read(|c| *c) {
221 /// println!("Current value: {}", value);
222 /// } else {
223 /// println!("Lock is unavailable");
224 /// }
225 /// ```
226 #[inline]
227 fn try_read<R, F>(&self, f: F) -> Result<R, TryLockError>
228 where
229 F: FnOnce(&T) -> R,
230 {
231 match self.inner.try_lock() {
232 Ok(guard) => Ok(f(&*guard)),
233 Err(std::sync::TryLockError::WouldBlock) => Err(TryLockError::WouldBlock),
234 Err(std::sync::TryLockError::Poisoned(_)) => Err(TryLockError::Poisoned),
235 }
236 }
237
238 /// Attempts to acquire a write lock without blocking
239 ///
240 /// Attempts to immediately acquire the write lock. If the lock is
241 /// unavailable, returns a detailed error. This is a non-blocking operation.
242 ///
243 /// # Arguments
244 ///
245 /// * `f` - The closure to be executed while holding the write lock
246 ///
247 /// # Returns
248 ///
249 /// * `Ok(R)` - If the lock was successfully acquired and the closure executed
250 /// * `Err(TryLockError::WouldBlock)` - If the lock is already held by another thread
251 /// * `Err(TryLockError::Poisoned)` - If the lock is poisoned
252 ///
253 /// # Example
254 ///
255 /// ```rust
256 /// use qubit_lock::lock::{ArcStdMutex, Lock};
257 ///
258 /// let counter = ArcStdMutex::new(0);
259 ///
260 /// if let Ok(result) = counter.try_write(|c| {
261 /// *c += 1;
262 /// *c
263 /// }) {
264 /// println!("New value: {}", result);
265 /// } else {
266 /// println!("Lock is unavailable");
267 /// }
268 /// ```
269 #[inline]
270 fn try_write<R, F>(&self, f: F) -> Result<R, TryLockError>
271 where
272 F: FnOnce(&mut T) -> R,
273 {
274 match self.inner.try_lock() {
275 Ok(mut guard) => Ok(f(&mut *guard)),
276 Err(std::sync::TryLockError::WouldBlock) => Err(TryLockError::WouldBlock),
277 Err(std::sync::TryLockError::Poisoned(_)) => Err(TryLockError::Poisoned),
278 }
279 }
280}
281
282impl<T> Clone for ArcStdMutex<T> {
283 /// Clones the synchronous mutex
284 ///
285 /// Creates a new `ArcStdMutex` instance that shares the same
286 /// underlying lock with the original instance. This allows
287 /// multiple threads to hold references to the same lock
288 /// simultaneously.
289 ///
290 /// # Returns
291 ///
292 /// A new handle sharing the same underlying mutex and protected value.
293 #[inline]
294 fn clone(&self) -> Self {
295 Self {
296 inner: self.inner.clone(),
297 }
298 }
299}