rustsim_transit/
boarding.rs1use std::collections::VecDeque;
4
5use crate::policy::{BoardingPolicy, FifoBoardingPolicy};
6use crate::stop::StopId;
7use crate::vehicle::TransitVehicle;
8use crate::PassengerId;
9
10#[derive(Debug, Clone, Copy, PartialEq)]
12pub struct Waiter {
13 pub passenger: PassengerId,
15 pub destination: StopId,
17 pub arrived_at: f64,
19}
20
21#[derive(Debug, Clone, Default)]
23pub struct Boarding {
24 queue: VecDeque<Waiter>,
26}
27
28#[derive(Debug, Clone, PartialEq)]
30pub struct BoardingResult {
31 pub boarded: u32,
33 pub passed_over: u32,
36}
37
38impl Boarding {
39 pub fn new() -> Self {
41 Self::default()
42 }
43
44 pub fn enqueue(&mut self, waiter: Waiter) {
46 self.queue.push_back(waiter);
47 }
48
49 pub fn len(&self) -> usize {
51 self.queue.len()
52 }
53
54 pub fn is_empty(&self) -> bool {
56 self.queue.is_empty()
57 }
58
59 pub fn board_vehicle(
65 &mut self,
66 vehicle: &mut TransitVehicle,
67 served_stops: &[StopId],
68 passenger_destinations: &mut Vec<StopId>,
69 ) -> BoardingResult {
70 self.board_vehicle_with_policy(
71 vehicle,
72 served_stops,
73 passenger_destinations,
74 &FifoBoardingPolicy::default(),
75 )
76 }
77
78 pub fn board_vehicle_with_policy<P: BoardingPolicy>(
80 &mut self,
81 vehicle: &mut TransitVehicle,
82 served_stops: &[StopId],
83 passenger_destinations: &mut Vec<StopId>,
84 policy: &P,
85 ) -> BoardingResult {
86 let mut boarded: u32 = 0;
87 let mut passed: u32 = 0;
88
89 let initial = self.queue.len();
93 for _ in 0..initial {
94 if !vehicle.has_room() {
95 break;
96 }
97 if policy
98 .max_boardings()
99 .is_some_and(|max_boardings| boarded >= max_boardings)
100 {
101 break;
102 }
103 let Some(w) = self.queue.pop_front() else {
104 break;
105 };
106 if policy.may_board(&w, vehicle, served_stops) {
107 vehicle.passengers.push(w.passenger);
108 passenger_destinations.push(w.destination);
109 boarded += 1;
110 } else {
111 self.queue.push_back(w);
112 passed += 1;
113 }
114 }
115
116 BoardingResult {
117 boarded,
118 passed_over: passed,
119 }
120 }
121}
122
123#[cfg(test)]
124mod tests {
125 use super::*;
126
127 #[test]
128 fn boarding_matches_served_destinations() {
129 let mut q = Boarding::new();
130 q.enqueue(Waiter {
131 passenger: 10,
132 destination: 3,
133 arrived_at: 0.0,
134 });
135 q.enqueue(Waiter {
136 passenger: 11,
137 destination: 99, arrived_at: 0.0,
139 });
140 q.enqueue(Waiter {
141 passenger: 12,
142 destination: 4,
143 arrived_at: 0.0,
144 });
145
146 let mut v = TransitVehicle::idle(1, 1, 10);
147 let mut dests = Vec::new();
148 let r = q.board_vehicle(&mut v, &[3, 4, 5], &mut dests);
149
150 assert_eq!(r.boarded, 2);
151 assert_eq!(r.passed_over, 1);
152 assert_eq!(v.passengers, vec![10, 12]);
153 assert_eq!(dests, vec![3, 4]);
154 assert_eq!(q.len(), 1);
155 }
156
157 #[test]
158 fn full_vehicle_stops_boarding() {
159 let mut q = Boarding::new();
160 for i in 0..5 {
161 q.enqueue(Waiter {
162 passenger: i,
163 destination: 3,
164 arrived_at: 0.0,
165 });
166 }
167 let mut v = TransitVehicle::idle(1, 1, 2);
168 let mut dests = Vec::new();
169 let r = q.board_vehicle(&mut v, &[3], &mut dests);
170 assert_eq!(r.boarded, 2);
171 assert_eq!(q.len(), 3);
172 }
173}