elevator_core/
host_label.rs1#![allow(unreachable_patterns)]
19use crate::components::{CallDirection, Direction, ElevatorPhase, ServiceMode};
26
27#[must_use]
33pub const fn elevator_phase(phase: ElevatorPhase) -> &'static str {
34 match phase {
35 ElevatorPhase::Idle => "idle",
36 ElevatorPhase::MovingToStop(_) => "moving",
37 ElevatorPhase::Repositioning(_) => "repositioning",
38 ElevatorPhase::DoorOpening => "door-opening",
39 ElevatorPhase::Loading => "loading",
40 ElevatorPhase::DoorClosing => "door-closing",
41 ElevatorPhase::Stopped => "stopped",
42 _ => "unknown",
43 }
44}
45
46#[must_use]
52pub const fn service_mode(mode: ServiceMode) -> &'static str {
53 match mode {
54 ServiceMode::Normal => "normal",
55 ServiceMode::Independent => "independent",
56 ServiceMode::Inspection => "inspection",
57 ServiceMode::Manual => "manual",
58 ServiceMode::OutOfService | _ => "out-of-service",
59 }
60}
61
62#[must_use]
65pub fn parse_service_mode(label: &str) -> Option<ServiceMode> {
66 match label {
67 "normal" => Some(ServiceMode::Normal),
68 "independent" => Some(ServiceMode::Independent),
69 "inspection" => Some(ServiceMode::Inspection),
70 "manual" => Some(ServiceMode::Manual),
71 "out-of-service" => Some(ServiceMode::OutOfService),
72 _ => None,
73 }
74}
75
76#[must_use]
81pub const fn direction(dir: Direction) -> &'static str {
82 match dir {
83 Direction::Up => "up",
84 Direction::Down => "down",
85 Direction::Either | _ => "either",
86 }
87}
88
89pub fn parse_call_direction(label: &str) -> Result<CallDirection, String> {
99 match label {
100 "up" => Ok(CallDirection::Up),
101 "down" => Ok(CallDirection::Down),
102 other => Err(format!("direction must be 'up' or 'down', got {other:?}")),
103 }
104}
105
106#[cfg(test)]
107#[allow(clippy::expect_used)]
108mod tests {
109 use super::*;
110
111 #[test]
112 fn elevator_phase_label_covers_every_variant() {
113 assert_eq!(elevator_phase(ElevatorPhase::Idle), "idle");
118 assert_eq!(
119 elevator_phase(ElevatorPhase::MovingToStop(
120 crate::entity::EntityId::default()
121 )),
122 "moving"
123 );
124 assert_eq!(
125 elevator_phase(ElevatorPhase::Repositioning(
126 crate::entity::EntityId::default()
127 )),
128 "repositioning"
129 );
130 assert_eq!(elevator_phase(ElevatorPhase::DoorOpening), "door-opening");
131 assert_eq!(elevator_phase(ElevatorPhase::Loading), "loading");
132 assert_eq!(elevator_phase(ElevatorPhase::DoorClosing), "door-closing");
133 assert_eq!(elevator_phase(ElevatorPhase::Stopped), "stopped");
134 }
135
136 #[test]
137 fn service_mode_round_trips() {
138 for mode in [
139 ServiceMode::Normal,
140 ServiceMode::Independent,
141 ServiceMode::Inspection,
142 ServiceMode::Manual,
143 ServiceMode::OutOfService,
144 ] {
145 let label = service_mode(mode);
146 assert_eq!(
147 parse_service_mode(label),
148 Some(mode),
149 "round-trip failed for {mode:?} via label {label:?}",
150 );
151 }
152 }
153
154 #[test]
155 fn parse_service_mode_rejects_unknown() {
156 assert_eq!(parse_service_mode(""), None);
157 assert_eq!(parse_service_mode("Normal"), None); assert_eq!(parse_service_mode("offline"), None);
159 }
160
161 #[test]
162 fn direction_label_strings() {
163 assert_eq!(direction(Direction::Up), "up");
164 assert_eq!(direction(Direction::Down), "down");
165 assert_eq!(direction(Direction::Either), "either");
166 }
167
168 #[test]
169 fn parse_call_direction_accepts_only_up_and_down() {
170 assert_eq!(parse_call_direction("up").expect("ok"), CallDirection::Up);
171 assert_eq!(
172 parse_call_direction("down").expect("ok"),
173 CallDirection::Down
174 );
175 assert!(parse_call_direction("either").is_err());
176 assert!(parse_call_direction("UP").is_err());
177 assert!(parse_call_direction("").is_err());
178 }
179}