mermaid_cli/utils/
mutex_ext.rs1use std::sync::{Arc, Mutex};
2use tokio::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
3
4pub trait MutexExt<T> {
6 fn lock_safe(&self) -> T
9 where
10 T: Clone;
11
12 fn lock_mut_safe(&self) -> std::sync::MutexGuard<'_, T>;
14}
15
16impl<T: Clone> MutexExt<T> for Mutex<T> {
17 fn lock_safe(&self) -> T {
18 match self.lock() {
19 Ok(guard) => guard.clone(),
20 Err(poisoned) => {
21 eprintln!("[WARNING] Mutex was poisoned, recovering data");
24 poisoned.into_inner().clone()
25 },
26 }
27 }
28
29 fn lock_mut_safe(&self) -> std::sync::MutexGuard<'_, T> {
30 match self.lock() {
31 Ok(guard) => guard,
32 Err(poisoned) => {
33 eprintln!("[WARNING] Mutex was poisoned, recovering guard");
35 poisoned.into_inner()
36 },
37 }
38 }
39}
40
41pub fn lock_arc_mutex_safe<T>(mutex: &Arc<Mutex<T>>) -> std::sync::MutexGuard<'_, T> {
43 match mutex.lock() {
44 Ok(guard) => guard,
45 Err(poisoned) => {
46 eprintln!("[WARNING] Arc<Mutex> was poisoned, recovering guard");
47 poisoned.into_inner()
48 },
49 }
50}
51
52#[macro_export]
54macro_rules! lock_or_panic {
55 ($mutex:expr, $msg:expr) => {
56 $mutex.lock().unwrap_or_else(|e| {
57 panic!("{}: mutex poisoned: {}", $msg, e);
58 })
59 };
60}
61
62#[allow(dead_code)]
65pub trait RwLockExt<T> {
66 async fn read_safe<'a>(&'a self) -> RwLockReadGuard<'a, T>
68 where
69 T: 'a;
70
71 async fn write_safe<'a>(&'a self) -> RwLockWriteGuard<'a, T>
73 where
74 T: 'a;
75}
76
77impl<T> RwLockExt<T> for RwLock<T> {
78 async fn read_safe<'a>(&'a self) -> RwLockReadGuard<'a, T>
79 where
80 T: 'a,
81 {
82 self.read().await
83 }
84
85 async fn write_safe<'a>(&'a self) -> RwLockWriteGuard<'a, T>
86 where
87 T: 'a,
88 {
89 self.write().await
90 }
91}
92
93impl<T> RwLockExt<T> for Arc<RwLock<T>> {
95 async fn read_safe<'a>(&'a self) -> RwLockReadGuard<'a, T>
96 where
97 T: 'a,
98 {
99 self.read().await
100 }
101
102 async fn write_safe<'a>(&'a self) -> RwLockWriteGuard<'a, T>
103 where
104 T: 'a,
105 {
106 self.write().await
107 }
108}