1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! Door open/close finite-state machine.
use serde::{Deserialize, Serialize};
/// State machine for elevator doors.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[non_exhaustive]
pub enum DoorState {
/// Doors are fully closed.
Closed,
/// Doors are in the process of opening.
Opening {
/// Ticks left in the opening transition.
ticks_remaining: u32,
/// How many ticks the door stays open once fully opened.
open_duration: u32,
/// How many ticks the closing transition takes.
close_duration: u32,
},
/// Doors are fully open and holding.
Open {
/// Ticks left before the doors begin closing.
ticks_remaining: u32,
/// How many ticks the closing transition takes.
close_duration: u32,
},
/// Doors are in the process of closing.
Closing {
/// Ticks left in the closing transition.
ticks_remaining: u32,
},
}
/// Transition emitted when the door state changes phase.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[non_exhaustive]
pub enum DoorTransition {
/// No phase change occurred this tick.
None,
/// Doors just finished opening and are now fully open.
FinishedOpening,
/// Doors just finished holding open and are about to close.
FinishedOpen,
/// Doors just finished closing and are now fully closed.
FinishedClosing,
}
impl std::fmt::Display for DoorState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Closed => write!(f, "Closed"),
Self::Opening {
ticks_remaining, ..
} => write!(f, "Opening({ticks_remaining})"),
Self::Open {
ticks_remaining, ..
} => write!(f, "Open({ticks_remaining})"),
Self::Closing { ticks_remaining } => write!(f, "Closing({ticks_remaining})"),
}
}
}
impl DoorState {
/// Returns `true` if the doors are fully open.
#[must_use]
pub const fn is_open(&self) -> bool {
matches!(self, Self::Open { .. })
}
/// Returns `true` if the doors are fully closed.
#[must_use]
pub const fn is_closed(&self) -> bool {
matches!(self, Self::Closed)
}
/// Begin opening the door.
#[must_use]
pub const fn request_open(transition_ticks: u32, open_ticks: u32) -> Self {
Self::Opening {
ticks_remaining: transition_ticks,
open_duration: open_ticks,
close_duration: transition_ticks,
}
}
/// Advance the door state by one tick. Returns the transition that occurred.
pub const fn tick(&mut self) -> DoorTransition {
match self {
Self::Closed => DoorTransition::None,
Self::Opening {
ticks_remaining,
open_duration,
close_duration,
} => {
if *ticks_remaining <= 1 {
let od = *open_duration;
let cd = *close_duration;
*self = Self::Open {
ticks_remaining: od,
close_duration: cd,
};
DoorTransition::FinishedOpening
} else {
*ticks_remaining -= 1;
DoorTransition::None
}
}
Self::Open {
ticks_remaining,
close_duration,
} => {
if *ticks_remaining <= 1 {
let cd = *close_duration;
*self = Self::Closing {
ticks_remaining: cd,
};
DoorTransition::FinishedOpen
} else {
*ticks_remaining -= 1;
DoorTransition::None
}
}
Self::Closing { ticks_remaining } => {
if *ticks_remaining <= 1 {
*self = Self::Closed;
DoorTransition::FinishedClosing
} else {
*ticks_remaining -= 1;
DoorTransition::None
}
}
}
}
}