elevator_core/stop.rs
1//! Stop identifiers and configuration.
2
3use crate::entity::EntityId;
4use serde::{Deserialize, Serialize};
5
6/// Numeric identifier for a stop along the shaft.
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
8pub struct StopId(pub u32);
9
10/// A reference to a stop by either its config-time [`StopId`] or its
11/// runtime [`EntityId`].
12///
13/// Methods on [`Simulation`](crate::sim::Simulation) that take a stop
14/// accept `impl Into<StopRef>`, so callers can pass either type directly.
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
16pub enum StopRef {
17 /// Config-time identifier.
18 ById(StopId),
19 /// Runtime entity identifier.
20 ByEntity(EntityId),
21}
22
23impl From<StopId> for StopRef {
24 fn from(id: StopId) -> Self {
25 Self::ById(id)
26 }
27}
28
29impl From<EntityId> for StopRef {
30 fn from(id: EntityId) -> Self {
31 Self::ByEntity(id)
32 }
33}
34
35impl std::fmt::Display for StopId {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 write!(f, "StopId({})", self.0)
38 }
39}
40
41/// A stop at an arbitrary position along the elevator shaft.
42#[derive(Debug, Clone, Serialize, Deserialize)]
43pub struct StopConfig {
44 /// The unique identifier for this stop.
45 pub id: StopId,
46 /// Human-readable name for this stop.
47 pub name: String,
48 /// Absolute position along the shaft axis (distance units from origin).
49 pub position: f64,
50}
51
52impl StopConfig {
53 /// Build a `Vec<StopConfig>` from a compact `(name, position)` slice.
54 ///
55 /// `StopId`s are assigned sequentially starting at 0. Useful for demos,
56 /// tests, and any sim whose stops don't need hand-picked identifiers.
57 ///
58 /// # Example
59 ///
60 /// ```
61 /// use elevator_core::stop::StopConfig;
62 ///
63 /// let stops = StopConfig::linear(&[
64 /// ("Ground", 0.0),
65 /// ("Floor 2", 4.0),
66 /// ("Floor 3", 8.0),
67 /// ]);
68 /// assert_eq!(stops.len(), 3);
69 /// assert_eq!(stops[0].name, "Ground");
70 /// assert_eq!(stops[2].position, 8.0);
71 /// ```
72 #[must_use]
73 pub fn linear(stops: &[(&str, f64)]) -> Vec<Self> {
74 stops
75 .iter()
76 .enumerate()
77 .map(|(i, (name, position))| Self {
78 id: StopId(u32::try_from(i).unwrap_or(u32::MAX)),
79 name: (*name).to_owned(),
80 position: *position,
81 })
82 .collect()
83 }
84}