elevator_core/components/service_mode.rs
1//! Service mode component for elevator operational modes.
2
3use serde::{Deserialize, Serialize};
4
5/// Operational service mode for an elevator, orthogonal to [`ElevatorPhase`](super::ElevatorPhase).
6///
7/// Normal is the default. Modes modify how simulation phases behave without
8/// replacing `ElevatorPhase` — an elevator in any service mode may occupy
9/// any phase (`Idle`, `MovingToStop`, `Repositioning`, etc.). `Independent`
10/// elevators are excluded from automatic dispatch and repositioning, so in
11/// practice they only move under direct API control.
12#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
13#[non_exhaustive]
14pub enum ServiceMode {
15 /// Normal operation: dispatch assigns stops, doors auto-cycle.
16 #[default]
17 Normal,
18 /// Independent mode: elevator is excluded from dispatch and repositioning.
19 /// Consumer controls movement via direct API calls.
20 Independent,
21 /// Inspection mode: reduced speed, doors hold open indefinitely.
22 /// Speed is reduced by [`Elevator::inspection_speed_factor`](super::Elevator::inspection_speed_factor).
23 Inspection,
24 /// Manual mode: elevator is driven by direct velocity commands from the
25 /// game (see
26 /// [`Simulation::set_target_velocity`](crate::sim::Simulation::set_target_velocity)
27 /// and [`Simulation::emergency_stop`](crate::sim::Simulation::emergency_stop)).
28 /// Excluded from dispatch and repositioning; doors follow the manual
29 /// door-control API. Can stop at any position — the elevator is not
30 /// required to align with a configured stop.
31 Manual,
32 /// Out of service: the elevator is shut down. Excluded from dispatch
33 /// and repositioning; auto-boarding is disabled. In-flight trips
34 /// complete and doors cycle normally, but no riders board or exit.
35 /// Once idle the car is fully inert.
36 ///
37 /// Unlike [`Simulation::disable`](crate::sim::Simulation::disable),
38 /// the entity remains visible in queries and is not skipped by
39 /// iteration — games can render an "out of order" indicator.
40 OutOfService,
41}
42
43impl ServiceMode {
44 /// `true` if elevators in this mode are skipped by the automatic
45 /// dispatch and repositioning phases.
46 ///
47 /// Returns `true` for [`Independent`](Self::Independent),
48 /// [`Manual`](Self::Manual), [`Inspection`](Self::Inspection), and
49 /// [`OutOfService`](Self::OutOfService). Independent and Manual hand
50 /// movement over to the consumer; Inspection is technician-controlled;
51 /// `OutOfService` is fully inert.
52 #[must_use]
53 pub const fn is_dispatch_excluded(self) -> bool {
54 matches!(
55 self,
56 Self::Independent | Self::Manual | Self::Inspection | Self::OutOfService
57 )
58 }
59
60 /// `true` if the loading phase should automatically board and exit
61 /// riders at open doors.
62 ///
63 /// Only [`Normal`](Self::Normal) allows auto-loading. All other
64 /// modes hand rider management to the consumer or are operationally
65 /// unsuitable for passenger service.
66 #[must_use]
67 pub const fn allows_auto_loading(self) -> bool {
68 matches!(self, Self::Normal)
69 }
70}
71
72impl std::fmt::Display for ServiceMode {
73 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74 match self {
75 Self::Normal => write!(f, "Normal"),
76 Self::Independent => write!(f, "Independent"),
77 Self::Inspection => write!(f, "Inspection"),
78 Self::Manual => write!(f, "Manual"),
79 Self::OutOfService => write!(f, "OutOfService"),
80 }
81 }
82}