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