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 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 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}