Skip to main content

mermaid_cli/utils/
mutex_ext.rs

1use std::sync::{Arc, Mutex};
2use tracing::warn;
3
4/// Extension trait for Mutex to provide safe lock operations
5pub trait MutexExt<T> {
6    /// Lock the mutex, recovering from poison errors
7    /// This is safer than unwrap() as it handles poisoned mutexes gracefully
8    fn lock_safe(&self) -> T
9    where
10        T: Clone;
11
12    /// Lock the mutex for mutation, recovering from poison errors
13    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                // Mutex was poisoned due to a panic in another thread
22                // We can still access the data, but we log the issue
23                warn!("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                // Mutex was poisoned, but we can still get the guard
34                warn!("Mutex was poisoned, recovering guard");
35                poisoned.into_inner()
36            },
37        }
38    }
39}
40
41/// Safe lock for Arc<Mutex<T>> - standalone function since we can't impl on Arc
42pub 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            warn!("Arc<Mutex> was poisoned, recovering guard");
47            poisoned.into_inner()
48        },
49    }
50}