Skip to main content

elevator_core/components/
route.rs

1//! Multi-leg route planning for riders.
2
3use serde::{Deserialize, Serialize};
4
5use crate::entity::EntityId;
6use crate::ids::GroupId;
7
8/// How to travel between two stops.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
10#[non_exhaustive]
11pub enum TransportMode {
12    /// Use any elevator in the given dispatch group.
13    #[serde(alias = "Elevator")]
14    Group(GroupId),
15    /// Use a specific line (pinned routing).
16    Line(EntityId),
17    /// Walk between adjacent stops.
18    Walk,
19}
20
21/// One segment of a multi-leg route.
22#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct RouteLeg {
24    /// Origin stop entity.
25    pub from: EntityId,
26    /// Destination stop entity.
27    pub to: EntityId,
28    /// Transport mode for this leg.
29    pub via: TransportMode,
30}
31
32/// A rider's full route, possibly spanning multiple elevator groups.
33#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct Route {
35    /// Ordered legs of the route.
36    pub legs: Vec<RouteLeg>,
37    /// Index into `legs` for the leg currently being traversed.
38    pub current_leg: usize,
39}
40
41impl Route {
42    /// Create a direct single-leg route via one elevator group.
43    #[must_use]
44    pub fn direct(from: EntityId, to: EntityId, group: GroupId) -> Self {
45        Self {
46            legs: vec![RouteLeg {
47                from,
48                to,
49                via: TransportMode::Group(group),
50            }],
51            current_leg: 0,
52        }
53    }
54
55    /// Get the current leg, if any remain.
56    #[must_use]
57    pub fn current(&self) -> Option<&RouteLeg> {
58        self.legs.get(self.current_leg)
59    }
60
61    /// Advance to the next leg. Returns true if there are more legs.
62    pub const fn advance(&mut self) -> bool {
63        self.current_leg += 1;
64        self.current_leg < self.legs.len()
65    }
66
67    /// Whether all legs have been completed.
68    #[must_use]
69    pub const fn is_complete(&self) -> bool {
70        self.current_leg >= self.legs.len()
71    }
72
73    /// The destination of the current leg.
74    #[must_use]
75    pub fn current_destination(&self) -> Option<EntityId> {
76        self.current().map(|leg| leg.to)
77    }
78
79    /// The final destination of the entire route.
80    #[must_use]
81    pub fn final_destination(&self) -> Option<EntityId> {
82        self.legs.last().map(|leg| leg.to)
83    }
84}