qubit_lock/lock/arc_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
11//! # Synchronous Mutex Wrapper (Parking Lot)
12//!
13//! Provides an Arc-wrapped synchronous mutex using parking_lot::Mutex
14//! for protecting shared data in multi-threaded environments.
15//!
16
17use std::sync::Arc;
18
19use parking_lot::Mutex;
20
21use crate::lock::{
22 Lock,
23 TryLockError,
24};
25
26/// Synchronous Mutex Wrapper (Parking Lot)
27///
28/// Provides an encapsulation of synchronous mutex using parking_lot::Mutex
29/// for protecting shared data in synchronous environments. Supports safe
30/// access and modification of shared data across multiple threads.
31/// Compared to std::sync::Mutex, parking_lot::Mutex provides better
32/// performance and more ergonomic API.
33///
34/// # Features
35///
36/// - Synchronously acquires locks, may 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/// - Better performance compared to std::sync::Mutex
42/// - More ergonomic API with no unwrap() calls
43///
44/// # Usage Example
45///
46/// ```rust
47/// use qubit_lock::lock::{ArcMutex, Lock};
48///
49/// let counter = ArcMutex::new(0);
50///
51/// // Synchronously modify data
52/// counter.write(|c| {
53/// *c += 1;
54/// println!("Counter: {}", *c);
55/// });
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///
64pub struct ArcMutex<T> {
65 /// Shared parking_lot mutex protecting the wrapped value.
66 inner: Arc<Mutex<T>>,
67}
68
69impl<T> ArcMutex<T> {
70 /// Creates a new synchronous mutex lock
71 ///
72 /// # Arguments
73 ///
74 /// * `data` - The data to be protected
75 ///
76 /// # Returns
77 ///
78 /// Returns a new `ArcMutex` instance
79 ///
80 /// # Example
81 ///
82 /// ```rust
83 /// use qubit_lock::lock::ArcMutex;
84 ///
85 /// let lock = ArcMutex::new(42);
86 /// ```
87 #[inline]
88 pub fn new(data: T) -> Self {
89 Self {
90 inner: Arc::new(Mutex::new(data)),
91 }
92 }
93}
94
95impl<T> Lock<T> for ArcMutex<T> {
96 /// Acquires a read lock and executes an operation
97 ///
98 /// For ArcMutex, this acquires the same exclusive lock as write
99 /// operations, but provides immutable access to the data. This
100 /// ensures thread safety while allowing read-only operations.
101 ///
102 /// # Arguments
103 ///
104 /// * `f` - The closure to be executed while holding the read lock
105 ///
106 /// # Returns
107 ///
108 /// Returns the result of executing the closure
109 ///
110 /// # Example
111 ///
112 /// ```rust
113 /// use qubit_lock::lock::{ArcMutex, Lock};
114 ///
115 /// let counter = ArcMutex::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();
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 /// # Example
144 ///
145 /// ```rust
146 /// use qubit_lock::lock::{ArcMutex, Lock};
147 ///
148 /// let counter = ArcMutex::new(0);
149 ///
150 /// let result = counter.write(|c| {
151 /// *c += 1;
152 /// *c
153 /// });
154 ///
155 /// println!("Counter value: {}", result);
156 /// ```
157 #[inline]
158 fn write<R, F>(&self, f: F) -> R
159 where
160 F: FnOnce(&mut T) -> R,
161 {
162 let mut guard = self.inner.lock();
163 f(&mut *guard)
164 }
165
166 /// Attempts to acquire a read lock without blocking
167 ///
168 /// Attempts to immediately acquire the read lock. If the lock is
169 /// unavailable, returns a detailed error. This is a non-blocking operation.
170 ///
171 /// # Arguments
172 ///
173 /// * `f` - The closure to be executed while holding the read lock
174 ///
175 /// # Returns
176 ///
177 /// * `Ok(R)` - If the lock was successfully acquired and the closure executed
178 /// * `Err(TryLockError::WouldBlock)` - If the lock is already held by another thread
179 ///
180 /// # Example
181 ///
182 /// ```rust
183 /// use qubit_lock::lock::{ArcMutex, Lock};
184 ///
185 /// let counter = ArcMutex::new(42);
186 ///
187 /// if let Ok(value) = counter.try_read(|c| *c) {
188 /// println!("Current value: {}", value);
189 /// } else {
190 /// println!("Lock is unavailable");
191 /// }
192 /// ```
193 #[inline]
194 fn try_read<R, F>(&self, f: F) -> Result<R, TryLockError>
195 where
196 F: FnOnce(&T) -> R,
197 {
198 self.inner
199 .try_lock()
200 .map(|guard| f(&*guard))
201 .ok_or(TryLockError::WouldBlock)
202 }
203
204 /// Attempts to acquire a write lock without blocking
205 ///
206 /// Attempts to immediately acquire the write lock. If the lock is
207 /// unavailable, returns a detailed error. This is a non-blocking operation.
208 ///
209 /// # Arguments
210 ///
211 /// * `f` - The closure to be executed while holding the write lock
212 ///
213 /// # Returns
214 ///
215 /// * `Ok(R)` - If the lock was successfully acquired and the closure executed
216 /// * `Err(TryLockError::WouldBlock)` - If the lock is already held by another thread
217 ///
218 /// # Example
219 ///
220 /// ```rust
221 /// use qubit_lock::lock::{ArcMutex, Lock};
222 ///
223 /// let counter = ArcMutex::new(0);
224 ///
225 /// if let Ok(result) = counter.try_write(|c| {
226 /// *c += 1;
227 /// *c
228 /// }) {
229 /// println!("New value: {}", result);
230 /// } else {
231 /// println!("Lock is unavailable");
232 /// }
233 /// ```
234 #[inline]
235 fn try_write<R, F>(&self, f: F) -> Result<R, TryLockError>
236 where
237 F: FnOnce(&mut T) -> R,
238 {
239 self.inner
240 .try_lock()
241 .map(|mut guard| f(&mut *guard))
242 .ok_or(TryLockError::WouldBlock)
243 }
244}
245
246impl<T> Clone for ArcMutex<T> {
247 /// Clones the synchronous mutex
248 ///
249 /// Creates a new `ArcMutex` instance that shares the same
250 /// underlying lock with the original instance. This allows
251 /// multiple threads to hold references to the same lock
252 /// simultaneously.
253 ///
254 /// # Returns
255 ///
256 /// A new handle sharing the same underlying mutex and protected value.
257 #[inline]
258 fn clone(&self) -> Self {
259 Self {
260 inner: self.inner.clone(),
261 }
262 }
263}