Skip to main content

objects/
sync.rs

1// SPDX-License-Identifier: Apache-2.0
2//! Synchronization helpers shared across Heddle crates.
3
4use std::sync::{Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard};
5
6/// Extension methods for mutexes that should panic when poisoned.
7pub trait LockExt {
8    /// Guard returned by [`LockExt::lock_or_poisoned`].
9    type Guard<'a>
10    where
11        Self: 'a;
12
13    /// Lock the mutex, preserving the existing panic-on-poison behavior.
14    fn lock_or_poisoned(&self) -> Self::Guard<'_>;
15}
16
17impl<T: ?Sized> LockExt for Mutex<T> {
18    type Guard<'a>
19        = MutexGuard<'a, T>
20    where
21        Self: 'a;
22
23    #[allow(clippy::expect_used, clippy::unwrap_used)]
24    fn lock_or_poisoned(&self) -> Self::Guard<'_> {
25        self.lock()
26            .expect("invariant: lock not poisoned (a holder panicked)")
27    }
28}
29
30/// Extension methods for read-write locks that should panic when poisoned.
31pub trait RwLockExt {
32    /// Guard returned by [`RwLockExt::read_or_poisoned`].
33    type ReadGuard<'a>
34    where
35        Self: 'a;
36
37    /// Guard returned by [`RwLockExt::write_or_poisoned`].
38    type WriteGuard<'a>
39    where
40        Self: 'a;
41
42    /// Acquire a read guard, preserving the existing panic-on-poison behavior.
43    fn read_or_poisoned(&self) -> Self::ReadGuard<'_>;
44
45    /// Acquire a write guard, preserving the existing panic-on-poison behavior.
46    fn write_or_poisoned(&self) -> Self::WriteGuard<'_>;
47}
48
49impl<T: ?Sized> RwLockExt for RwLock<T> {
50    type ReadGuard<'a>
51        = RwLockReadGuard<'a, T>
52    where
53        Self: 'a;
54
55    type WriteGuard<'a>
56        = RwLockWriteGuard<'a, T>
57    where
58        Self: 'a;
59
60    #[allow(clippy::expect_used, clippy::unwrap_used)]
61    fn read_or_poisoned(&self) -> Self::ReadGuard<'_> {
62        self.read()
63            .expect("invariant: lock not poisoned (a holder panicked)")
64    }
65
66    #[allow(clippy::expect_used, clippy::unwrap_used)]
67    fn write_or_poisoned(&self) -> Self::WriteGuard<'_> {
68        self.write()
69            .expect("invariant: lock not poisoned (a holder panicked)")
70    }
71}