templar_common/
guard.rs

1use std::marker::PhantomData;
2use std::ops::{Deref, DerefMut};
3
4pub trait GuardSpec<T> {
5    type State;
6    type Error;
7    type Idle: GuardSpec<T, Error = Self::Error>;
8
9    /// # Errors
10    /// Returns `Self::Error` if the target is not in the expected state.
11    fn validate(target: &T, op_id: Option<u64>) -> Result<&Self::State, Self::Error>;
12    fn set_state(target: &mut T, state: Self::State);
13    fn into_idle(target: &mut T);
14}
15
16pub struct Guard<'a, T, S: GuardSpec<T>> {
17    target: &'a mut T,
18    _marker: PhantomData<S>,
19}
20
21impl<'a, T, S: GuardSpec<T>> Guard<'a, T, S> {
22    /// # Errors
23    /// Returns `S::Error` if the target is not in the expected state.
24    pub fn expect(target: &'a mut T, op_id: Option<u64>) -> Result<Self, S::Error> {
25        let _ = S::validate(target, op_id)?;
26        Ok(Self {
27            target,
28            _marker: PhantomData,
29        })
30    }
31
32    pub fn state(&self) -> &S::State {
33        S::validate(self.target, None)
34            .unwrap_or_else(|_| crate::panic_with_message("validated state"))
35    }
36
37    #[must_use]
38    pub fn replace_state(self, state: S::State) -> Self {
39        S::set_state(self.target, state);
40        Self {
41            target: self.target,
42            _marker: PhantomData,
43        }
44    }
45
46    pub fn into_idle(self) -> Guard<'a, T, S::Idle> {
47        S::into_idle(self.target);
48        Guard {
49            target: self.target,
50            _marker: PhantomData,
51        }
52    }
53
54    pub fn into_inner(self) -> &'a mut T {
55        self.target
56    }
57
58    pub fn contract(&mut self) -> &mut T {
59        self.target
60    }
61}
62
63impl<T, S: GuardSpec<T>> Deref for Guard<'_, T, S> {
64    type Target = T;
65
66    fn deref(&self) -> &Self::Target {
67        self.target
68    }
69}
70
71impl<T, S: GuardSpec<T>> DerefMut for Guard<'_, T, S> {
72    fn deref_mut(&mut self) -> &mut Self::Target {
73        self.target
74    }
75}
76
77#[must_use = "drops immediately if not bound"]
78pub struct OnDrop<F: FnOnce()> {
79    f: Option<F>,
80}
81
82impl<F: FnOnce()> OnDrop<F> {
83    #[inline]
84    pub fn new(f: F) -> Self {
85        Self { f: Some(f) }
86    }
87
88    #[inline]
89    pub fn disarm(mut self) {
90        self.f = None;
91    }
92}
93
94impl<F: FnOnce()> Drop for OnDrop<F> {
95    fn drop(&mut self) {
96        if let Some(f) = self.f.take() {
97            let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(f));
98        }
99    }
100}
101
102#[inline]
103pub fn defer<F: FnOnce()>(f: F) -> OnDrop<F> {
104    OnDrop::new(f)
105}