hojicha_runtime/
safe_mutex.rs1use log::warn;
8use std::ops::{Deref, DerefMut};
9use std::sync::{Arc, Mutex, MutexGuard, PoisonError};
10
11pub struct SafeMutex<T> {
13 inner: Mutex<T>,
14}
15
16impl<T> SafeMutex<T> {
17 pub fn new(value: T) -> Self {
19 Self {
20 inner: Mutex::new(value),
21 }
22 }
23
24 pub fn lock(&self) -> SafeGuard<'_, T> {
26 match self.inner.lock() {
27 Ok(guard) => SafeGuard {
28 guard: Ok(guard),
29 recovered: false,
30 },
31 Err(poisoned) => {
32 warn!("Mutex was poisoned, recovering...");
33 let guard = poisoned.into_inner();
34 SafeGuard {
35 guard: Ok(guard),
36 recovered: true,
37 }
38 }
39 }
40 }
41
42 pub fn try_lock(&self) -> Option<SafeGuard<'_, T>> {
44 match self.inner.try_lock() {
45 Ok(guard) => Some(SafeGuard {
46 guard: Ok(guard),
47 recovered: false,
48 }),
49 Err(std::sync::TryLockError::Poisoned(poisoned)) => {
50 warn!("Mutex was poisoned during try_lock, recovering...");
51 let guard = poisoned.into_inner();
52 Some(SafeGuard {
53 guard: Ok(guard),
54 recovered: true,
55 })
56 }
57 Err(std::sync::TryLockError::WouldBlock) => None,
58 }
59 }
60}
61
62pub struct SafeGuard<'a, T> {
64 guard: Result<MutexGuard<'a, T>, PoisonError<MutexGuard<'a, T>>>,
65 recovered: bool,
66}
67
68impl<'a, T> SafeGuard<'a, T> {
69 pub fn was_recovered(&self) -> bool {
71 self.recovered
72 }
73}
74
75impl<'a, T> Deref for SafeGuard<'a, T> {
76 type Target = T;
77
78 fn deref(&self) -> &Self::Target {
79 match &self.guard {
80 Ok(guard) => guard.deref(),
81 Err(poisoned) => poisoned.get_ref(),
82 }
83 }
84}
85
86impl<'a, T> DerefMut for SafeGuard<'a, T> {
87 fn deref_mut(&mut self) -> &mut Self::Target {
88 match &mut self.guard {
89 Ok(guard) => guard.deref_mut(),
90 Err(poisoned) => poisoned.get_mut(),
91 }
92 }
93}
94
95pub type SafeArcMutex<T> = Arc<SafeMutex<T>>;
97
98pub fn safe_arc_mutex<T>(value: T) -> SafeArcMutex<T> {
100 Arc::new(SafeMutex::new(value))
101}