Skip to main content

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}