prism3_concurrent/lock.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025.
4 * 3-Prism Co. Ltd.
5 *
6 * All rights reserved.
7 *
8 ******************************************************************************/
9//! # Lock Wrappers
10//!
11//! Provides wrapper functionality for synchronous and asynchronous locks,
12//! for safely accessing shared data in both synchronous and asynchronous environments.
13//!
14//! # Author
15//!
16//! Haixing Hu
17
18use std::sync::{Arc, Mutex, RwLock};
19use tokio::sync::{Mutex as AsyncMutex, RwLock as AsyncRwLock};
20
21/// Synchronous Mutex Wrapper
22///
23/// Provides an encapsulation of synchronous mutex for protecting shared data
24/// in synchronous environments. Supports safe access and modification of shared
25/// data across multiple threads.
26///
27/// # Features
28///
29/// - Synchronously acquires locks, may block threads
30/// - Supports trying to acquire locks (non-blocking)
31/// - Thread-safe, supports multi-threaded sharing
32/// - Automatic lock management through RAII ensures proper lock release
33///
34/// # Usage Example
35///
36/// ```rust,ignore
37/// use prism3_concurrent::ArcMutex;
38/// use std::sync::Arc;
39///
40/// let counter = ArcMutex::new(0);
41/// let counter = Arc::new(counter);
42///
43/// // Synchronously modify data
44/// counter.with_lock(|c| {
45/// *c += 1;
46/// println!("Counter: {}", *c);
47/// });
48///
49/// // Try to acquire lock
50/// if let Some(value) = counter.try_with_lock(|c| *c) {
51/// println!("Current value: {}", value);
52/// }
53/// ```
54///
55/// # Author
56///
57/// Haixing Hu
58///
59pub struct ArcMutex<T> {
60 inner: Arc<Mutex<T>>,
61}
62
63impl<T> ArcMutex<T> {
64 /// Creates a new synchronous mutex lock
65 ///
66 /// # Arguments
67 ///
68 /// * `data` - The data to be protected
69 ///
70 /// # Returns
71 ///
72 /// Returns a new `ArcMutex` instance
73 ///
74 /// # Example
75 ///
76 /// ```rust,ignore
77 /// use prism3_concurrent::ArcMutex;
78 ///
79 /// let lock = ArcMutex::new(42);
80 /// ```
81 pub fn new(data: T) -> Self {
82 Self {
83 inner: Arc::new(Mutex::new(data)),
84 }
85 }
86
87 /// Acquires the lock and executes an operation
88 ///
89 /// Synchronously acquires the lock, executes the provided closure, and then
90 /// automatically releases the lock. This is the recommended usage pattern as it
91 /// ensures proper lock release.
92 ///
93 /// # Arguments
94 ///
95 /// * `f` - The closure to be executed while holding the lock
96 ///
97 /// # Returns
98 ///
99 /// Returns the result of executing the closure
100 ///
101 /// # Example
102 ///
103 /// ```rust,ignore
104 /// use prism3_concurrent::ArcMutex;
105 ///
106 /// let counter = ArcMutex::new(0);
107 ///
108 /// let result = counter.with_lock(|c| {
109 /// *c += 1;
110 /// *c
111 /// });
112 ///
113 /// println!("Counter value: {}", result);
114 /// ```
115 pub fn with_lock<F, R>(&self, f: F) -> R
116 where
117 F: FnOnce(&mut T) -> R,
118 {
119 let mut guard = self.inner.lock().unwrap();
120 f(&mut *guard)
121 }
122
123 /// Attempts to acquire the lock
124 ///
125 /// Attempts to immediately acquire the lock. If the lock is already held by
126 /// another thread, returns `None`. This is a non-blocking operation.
127 ///
128 /// # Arguments
129 ///
130 /// * `f` - The closure to be executed while holding the lock
131 ///
132 /// # Returns
133 ///
134 /// * `Some(R)` - If the lock was successfully acquired and the closure executed
135 /// * `None` - If the lock is already held by another thread
136 ///
137 /// # Example
138 ///
139 /// ```rust,ignore
140 /// use prism3_concurrent::ArcMutex;
141 ///
142 /// let counter = ArcMutex::new(0);
143 ///
144 /// // Try to acquire lock
145 /// if let Some(value) = counter.try_with_lock(|c| *c) {
146 /// println!("Current value: {}", value);
147 /// } else {
148 /// println!("Lock is busy");
149 /// }
150 /// ```
151 pub fn try_with_lock<F, R>(&self, f: F) -> Option<R>
152 where
153 F: FnOnce(&mut T) -> R,
154 {
155 if let Ok(mut guard) = self.inner.try_lock() {
156 Some(f(&mut *guard))
157 } else {
158 None
159 }
160 }
161}
162
163impl<T> Clone for ArcMutex<T> {
164 /// Clones the synchronous mutex
165 ///
166 /// Creates a new `ArcMutex` instance that shares the same underlying lock
167 /// with the original instance. This allows multiple threads to hold references
168 /// to the same lock simultaneously.
169 fn clone(&self) -> Self {
170 Self {
171 inner: Arc::clone(&self.inner),
172 }
173 }
174}
175
176/// Synchronous Read-Write Lock Wrapper
177///
178/// Provides an encapsulation of synchronous read-write lock, supporting multiple
179/// read operations or a single write operation. Read operations can execute
180/// concurrently, while write operations have exclusive access.
181///
182/// # Features
183///
184/// - Supports multiple concurrent read operations
185/// - Write operations have exclusive access, mutually exclusive with read operations
186/// - Synchronously acquires locks, may block threads
187/// - Thread-safe, supports multi-threaded sharing
188/// - Automatic lock management through RAII ensures proper lock release
189///
190/// # Use Cases
191///
192/// Suitable for read-heavy scenarios such as caching, configuration management, etc.
193///
194/// # Usage Example
195///
196/// ```rust,ignore
197/// use prism3_concurrent::ArcRwLock;
198/// use std::sync::Arc;
199///
200/// let data = ArcRwLock::new(String::from("Hello"));
201/// let data = Arc::new(data);
202///
203/// // Multiple read operations can execute concurrently
204/// data.with_read_lock(|s| {
205/// println!("Read: {}", s);
206/// });
207///
208/// // Write operations have exclusive access
209/// data.with_write_lock(|s| {
210/// s.push_str(" World!");
211/// println!("Write: {}", s);
212/// });
213/// ```
214///
215/// # Author
216///
217/// Haixing Hu
218///
219pub struct ArcRwLock<T> {
220 inner: Arc<RwLock<T>>,
221}
222
223impl<T> ArcRwLock<T> {
224 /// Creates a new synchronous read-write lock
225 ///
226 /// # Arguments
227 ///
228 /// * `data` - The data to be protected
229 ///
230 /// # Returns
231 ///
232 /// Returns a new `ArcRwLock` instance
233 ///
234 /// # Example
235 ///
236 /// ```rust,ignore
237 /// use prism3_concurrent::ArcRwLock;
238 ///
239 /// let rw_lock = ArcRwLock::new(vec![1, 2, 3]);
240 /// ```
241 pub fn new(data: T) -> Self {
242 Self {
243 inner: Arc::new(RwLock::new(data)),
244 }
245 }
246
247 /// Acquires the read lock and executes an operation
248 ///
249 /// Synchronously acquires the read lock, executes the provided closure, and then
250 /// automatically releases the lock. Multiple read operations can execute concurrently.
251 ///
252 /// # Arguments
253 ///
254 /// * `f` - The closure to be executed while holding the read lock, can only read data
255 ///
256 /// # Returns
257 ///
258 /// Returns the result of executing the closure
259 ///
260 /// # Example
261 ///
262 /// ```rust,ignore
263 /// use prism3_concurrent::ArcRwLock;
264 ///
265 /// let data = ArcRwLock::new(vec![1, 2, 3]);
266 ///
267 /// let length = data.with_read_lock(|v| v.len());
268 /// println!("Vector length: {}", length);
269 /// ```
270 pub fn with_read_lock<F, R>(&self, f: F) -> R
271 where
272 F: FnOnce(&T) -> R,
273 {
274 let guard = self.inner.read().unwrap();
275 f(&*guard)
276 }
277
278 /// Acquires the write lock and executes an operation
279 ///
280 /// Synchronously acquires the write lock, executes the provided closure, and then
281 /// automatically releases the lock. Write operations have exclusive access, mutually
282 /// exclusive with read operations.
283 ///
284 /// # Arguments
285 ///
286 /// * `f` - The closure to be executed while holding the write lock, can modify data
287 ///
288 /// # Returns
289 ///
290 /// Returns the result of executing the closure
291 ///
292 /// # Example
293 ///
294 /// ```rust,ignore
295 /// use prism3_concurrent::ArcRwLock;
296 ///
297 /// let data = ArcRwLock::new(vec![1, 2, 3]);
298 ///
299 /// data.with_write_lock(|v| {
300 /// v.push(4);
301 /// println!("Added element, new length: {}", v.len());
302 /// });
303 /// ```
304 pub fn with_write_lock<F, R>(&self, f: F) -> R
305 where
306 F: FnOnce(&mut T) -> R,
307 {
308 let mut guard = self.inner.write().unwrap();
309 f(&mut *guard)
310 }
311}
312
313impl<T> Clone for ArcRwLock<T> {
314 /// Clones the synchronous read-write lock
315 ///
316 /// Creates a new `ArcRwLock` instance that shares the same underlying lock
317 /// with the original instance. This allows multiple threads to hold references
318 /// to the same lock simultaneously.
319 fn clone(&self) -> Self {
320 Self {
321 inner: Arc::clone(&self.inner),
322 }
323 }
324}
325
326/// Asynchronous Mutex Wrapper
327///
328/// Provides an encapsulation of asynchronous mutex for protecting shared data
329/// in asynchronous environments. Supports safe access and modification of shared
330/// data across multiple asynchronous tasks.
331///
332/// # Features
333///
334/// - Asynchronously acquires locks, does not block threads
335/// - Supports trying to acquire locks (non-blocking)
336/// - Thread-safe, supports multi-threaded sharing
337/// - Automatic lock management through RAII ensures proper lock release
338///
339/// # Usage Example
340///
341/// ```rust,ignore
342/// use prism3_concurrent::ArcAsyncMutex;
343/// use std::sync::Arc;
344///
345/// #[tokio::main]
346/// async fn main() {
347/// let counter = ArcAsyncMutex::new(0);
348/// let counter = Arc::new(counter);
349///
350/// // Asynchronously modify data
351/// counter.with_lock(|c| {
352/// *c += 1;
353/// println!("Counter: {}", *c);
354/// }).await;
355///
356/// // Try to acquire lock
357/// if let Some(value) = counter.try_with_lock(|c| *c) {
358/// println!("Current value: {}", value);
359/// }
360/// }
361/// ```
362///
363/// # Author
364///
365/// Haixing Hu
366///
367pub struct ArcAsyncMutex<T> {
368 inner: Arc<AsyncMutex<T>>,
369}
370
371impl<T> ArcAsyncMutex<T> {
372 /// Creates a new asynchronous mutex lock
373 ///
374 /// # Arguments
375 ///
376 /// * `data` - The data to be protected
377 ///
378 /// # Returns
379 ///
380 /// Returns a new `ArcAsyncMutex` instance
381 ///
382 /// # Example
383 ///
384 /// ```rust,ignore
385 /// use prism3_concurrent::ArcAsyncMutex;
386 ///
387 /// let lock = ArcAsyncMutex::new(42);
388 /// ```
389 pub fn new(data: T) -> Self {
390 Self {
391 inner: Arc::new(AsyncMutex::new(data)),
392 }
393 }
394
395 /// Acquires the lock and executes an operation
396 ///
397 /// Asynchronously acquires the lock, executes the provided closure, and then
398 /// automatically releases the lock. This is the recommended usage pattern as it
399 /// ensures proper lock release.
400 ///
401 /// # Arguments
402 ///
403 /// * `f` - The closure to be executed while holding the lock
404 ///
405 /// # Returns
406 ///
407 /// Returns the result of executing the closure
408 ///
409 /// # Example
410 ///
411 /// ```rust,ignore
412 /// use prism3_concurrent::ArcAsyncMutex;
413 ///
414 /// #[tokio::main]
415 /// async fn main() {
416 /// let counter = ArcAsyncMutex::new(0);
417 ///
418 /// let result = counter.with_lock(|c| {
419 /// *c += 1;
420 /// *c
421 /// }).await;
422 ///
423 /// println!("Counter value: {}", result);
424 /// }
425 /// ```
426 pub async fn with_lock<F, R>(&self, f: F) -> R
427 where
428 F: FnOnce(&mut T) -> R,
429 {
430 let mut guard = self.inner.lock().await;
431 f(&mut *guard)
432 }
433
434 /// Attempts to acquire the lock
435 ///
436 /// Attempts to immediately acquire the lock. If the lock is already held by
437 /// another task, returns `None`. This is a non-blocking operation.
438 ///
439 /// # Arguments
440 ///
441 /// * `f` - The closure to be executed while holding the lock
442 ///
443 /// # Returns
444 ///
445 /// * `Some(R)` - If the lock was successfully acquired and the closure executed
446 /// * `None` - If the lock is already held by another task
447 ///
448 /// # Example
449 ///
450 /// ```rust,ignore
451 /// use prism3_concurrent::ArcAsyncMutex;
452 ///
453 /// let counter = ArcAsyncMutex::new(0);
454 ///
455 /// // Try to acquire lock
456 /// if let Some(value) = counter.try_with_lock(|c| *c) {
457 /// println!("Current value: {}", value);
458 /// } else {
459 /// println!("Lock is busy");
460 /// }
461 /// ```
462 pub fn try_with_lock<F, R>(&self, f: F) -> Option<R>
463 where
464 F: FnOnce(&mut T) -> R,
465 {
466 if let Ok(mut guard) = self.inner.try_lock() {
467 Some(f(&mut *guard))
468 } else {
469 None
470 }
471 }
472}
473
474impl<T> Clone for ArcAsyncMutex<T> {
475 /// Clones the asynchronous mutex
476 ///
477 /// Creates a new `ArcAsyncMutex` instance that shares the same underlying lock
478 /// with the original instance. This allows multiple tasks to hold references
479 /// to the same lock simultaneously.
480 fn clone(&self) -> Self {
481 Self {
482 inner: Arc::clone(&self.inner),
483 }
484 }
485}
486
487/// Asynchronous Read-Write Lock Wrapper
488///
489/// Provides an encapsulation of asynchronous read-write lock, supporting multiple
490/// read operations or a single write operation. Read operations can execute
491/// concurrently, while write operations have exclusive access.
492///
493/// # Features
494///
495/// - Supports multiple concurrent read operations
496/// - Write operations have exclusive access, mutually exclusive with read operations
497/// - Asynchronously acquires locks, does not block threads
498/// - Thread-safe, supports multi-threaded sharing
499/// - Automatic lock management through RAII ensures proper lock release
500///
501/// # Use Cases
502///
503/// Suitable for read-heavy scenarios such as caching, configuration management, etc.
504///
505/// # Usage Example
506///
507/// ```rust,ignore
508/// use prism3_concurrent::ArcAsyncRwLock;
509/// use std::sync::Arc;
510///
511/// #[tokio::main]
512/// async fn main() {
513/// let data = ArcAsyncRwLock::new(String::from("Hello"));
514/// let data = Arc::new(data);
515///
516/// // Multiple read operations can execute concurrently
517/// data.with_read_lock(|s| {
518/// println!("Read: {}", s);
519/// }).await;
520///
521/// // Write operations have exclusive access
522/// data.with_write_lock(|s| {
523/// s.push_str(" World!");
524/// println!("Write: {}", s);
525/// }).await;
526/// }
527/// ```
528///
529/// # Author
530///
531/// Haixing Hu
532///
533pub struct ArcAsyncRwLock<T> {
534 inner: Arc<AsyncRwLock<T>>,
535}
536
537impl<T> ArcAsyncRwLock<T> {
538 /// Creates a new asynchronous read-write lock
539 ///
540 /// # Arguments
541 ///
542 /// * `data` - The data to be protected
543 ///
544 /// # Returns
545 ///
546 /// Returns a new `ArcAsyncRwLock` instance
547 ///
548 /// # Example
549 ///
550 /// ```rust,ignore
551 /// use prism3_concurrent::ArcAsyncRwLock;
552 ///
553 /// let rw_lock = ArcAsyncRwLock::new(vec![1, 2, 3]);
554 /// ```
555 pub fn new(data: T) -> Self {
556 Self {
557 inner: Arc::new(AsyncRwLock::new(data)),
558 }
559 }
560
561 /// Acquires the read lock and executes an operation
562 ///
563 /// Asynchronously acquires the read lock, executes the provided closure, and then
564 /// automatically releases the lock. Multiple read operations can execute concurrently.
565 ///
566 /// # Arguments
567 ///
568 /// * `f` - The closure to be executed while holding the read lock, can only read data
569 ///
570 /// # Returns
571 ///
572 /// Returns the result of executing the closure
573 ///
574 /// # Example
575 ///
576 /// ```rust,ignore
577 /// use prism3_concurrent::ArcAsyncRwLock;
578 ///
579 /// #[tokio::main]
580 /// async fn main() {
581 /// let data = ArcAsyncRwLock::new(vec![1, 2, 3]);
582 ///
583 /// let length = data.with_read_lock(|v| v.len()).await;
584 /// println!("Vector length: {}", length);
585 /// }
586 /// ```
587 pub async fn with_read_lock<F, R>(&self, f: F) -> R
588 where
589 F: FnOnce(&T) -> R,
590 {
591 let guard = self.inner.read().await;
592 f(&*guard)
593 }
594
595 /// Acquires the write lock and executes an operation
596 ///
597 /// Asynchronously acquires the write lock, executes the provided closure, and then
598 /// automatically releases the lock. Write operations have exclusive access, mutually
599 /// exclusive with read operations.
600 ///
601 /// # Arguments
602 ///
603 /// * `f` - The closure to be executed while holding the write lock, can modify data
604 ///
605 /// # Returns
606 ///
607 /// Returns the result of executing the closure
608 ///
609 /// # Example
610 ///
611 /// ```rust,ignore
612 /// use prism3_concurrent::ArcAsyncRwLock;
613 ///
614 /// #[tokio::main]
615 /// async fn main() {
616 /// let data = ArcAsyncRwLock::new(vec![1, 2, 3]);
617 ///
618 /// data.with_write_lock(|v| {
619 /// v.push(4);
620 /// println!("Added element, new length: {}", v.len());
621 /// }).await;
622 /// }
623 /// ```
624 pub async fn with_write_lock<F, R>(&self, f: F) -> R
625 where
626 F: FnOnce(&mut T) -> R,
627 {
628 let mut guard = self.inner.write().await;
629 f(&mut *guard)
630 }
631}
632
633impl<T> Clone for ArcAsyncRwLock<T> {
634 /// Clones the asynchronous read-write lock
635 ///
636 /// Creates a new `ArcAsyncRwLock` instance that shares the same underlying lock
637 /// with the original instance. This allows multiple tasks to hold references
638 /// to the same lock simultaneously.
639 fn clone(&self) -> Self {
640 Self {
641 inner: Arc::clone(&self.inner),
642 }
643 }
644}