1use super::{lock, shutdown, startup, CoordinateError, Subject};
2
3enum GuardDropMode {
4 Stop,
5 Destroy,
6}
7
8pub struct Guard<SUBJECT>
14where
15 SUBJECT: Subject,
16{
17 mode: GuardDropMode,
18 lock: Option<lock::LockedFileShared>,
19 subject: SUBJECT,
20}
21
22impl<T> Guard<T>
23where
24 T: Subject,
25{
26 pub fn startup<L: Into<lock::UnlockedFile>>(
28 lock: L,
29 subject: T,
30 options: T::Options<'_>,
31 ) -> Result<Self, CoordinateError<T::Error>> {
32 let lock = startup(lock.into(), &subject, options)?;
33 Ok(Self { mode: GuardDropMode::Stop, lock: lock.into(), subject })
34 }
35}
36
37impl<T> Guard<T>
38where
39 T: Subject,
40{
41 #[must_use]
43 pub fn and_stop(mut self) -> Self {
44 self.mode = GuardDropMode::Stop;
45 self
46 }
47
48 #[must_use]
50 pub fn and_destroy(mut self) -> Self {
51 self.mode = GuardDropMode::Destroy;
52 self
53 }
54}
55
56impl<T> std::ops::Deref for Guard<T>
57where
58 T: Subject,
59{
60 type Target = T;
61
62 fn deref(&self) -> &Self::Target {
63 &self.subject
64 }
65}
66
67impl<T> Drop for Guard<T>
68where
69 T: Subject,
70{
71 fn drop(&mut self) {
72 if let Some(lock) = self.lock.take() {
73 let result = match &self.mode {
74 GuardDropMode::Stop => shutdown::<T, _, _>(lock, || self.subject.stop()),
75 GuardDropMode::Destroy => shutdown::<T, _, _>(lock, || self.subject.destroy()),
76 };
77 match (&self.mode, result) {
78 (GuardDropMode::Stop, Ok(_)) => (),
79 (GuardDropMode::Stop, Err(err)) => {
80 log::error!("Error stopping subject: {err}");
81 }
82 (GuardDropMode::Destroy, Ok(_)) => (),
83 (GuardDropMode::Destroy, Err(err)) => {
84 log::error!("Error destroying subject: {err}");
85 }
86 }
87 }
88 }
89}