gistools/readers/gtfs/realtime/vehicle_position.rs
1use crate::{
2 readers::{GTFSRealtimePosition, GTFSRealtimeTripDescriptor},
3 util::Date,
4};
5use alloc::{string::String, vec::Vec};
6use pbf::{BitCast, ProtoRead, Protobuf};
7
8/// Status of the vehicle relative to the stop
9#[repr(u8)]
10#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, BitCast)]
11pub enum GTFSVehicleStopStatus {
12 /// The vehicle is just about to arrive at the stop (on a stop
13 /// display, the vehicle symbol typically flashes).
14 IncomingAt = 0,
15 /// The vehicle is standing at the stop.
16 StoppedAt = 1,
17 /// The vehicle has departed and is in transit to the next stop.
18 #[default]
19 InTransitTo = 2,
20}
21
22/// Congestion level that is affecting this vehicle.
23#[repr(u8)]
24#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, BitCast)]
25pub enum GTFSRealtimeCongestionLevel {
26 /// Unknown congestion level
27 #[default]
28 UnknownCongestionLevel = 0,
29 /// Smooth traffic
30 RunningSmoothly = 1,
31 /// Stop and go traffic
32 StopAndGo = 2,
33 /// Heavy traffic
34 Congestion = 3,
35 /// Severe traffic (people leaving their cars)
36 SevereCongestion = 4,
37}
38
39/// The state of passenger occupancy for the vehicle or carriage.
40/// Individual producers may not publish all OccupancyStatus values. Therefore, consumers
41/// must not assume that the OccupancyStatus values follow a linear scale.
42/// Consumers should represent OccupancyStatus values as the state indicated
43/// and intended by the producer. Likewise, producers must use OccupancyStatus values that
44/// correspond to actual vehicle occupancy states.
45/// For describing passenger occupancy levels on a linear scale, see `occupancy_percentage`.
46/// This field is still experimental, and subject to change. It may be formally adopted in the future.
47#[repr(u8)]
48#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, BitCast)]
49pub enum GTFSRealtimeOccupancyStatus {
50 /// The vehicle or carriage is considered empty by most measures, and has few or no
51 /// passengers onboard, but is still accepting passengers.
52 Empty = 0,
53 /// The vehicle or carriage has a large number of seats available.
54 /// The amount of free seats out of the total seats available to be
55 /// considered large enough to fall into this category is determined at the
56 /// discretion of the producer.
57 ManySeatsAvailable = 1,
58 /// The vehicle or carriage has a relatively small number of seats available.
59 /// The amount of free seats out of the total seats available to be
60 /// considered small enough to fall into this category is determined at the
61 /// discretion of the feed producer.
62 FewSeatsAvailable = 2,
63 /// The vehicle or carriage can currently accommodate only standing passengers.
64 StandingRoomOnly = 3,
65 /// The vehicle or carriage can currently accommodate only standing passengers
66 /// and has limited space for them.
67 CrushedStandingRoomOnly = 4,
68 /// The vehicle or carriage is considered full by most measures, but may still be
69 /// allowing passengers to board.
70 Full = 5,
71 /// The vehicle or carriage is not accepting passengers, but usually accepts passengers for
72 /// boarding.
73 NotAcceptingPassengers = 6,
74 /// The vehicle or carriage doesn't have any occupancy data available at that time.
75 #[default]
76 NoDataAvailable = 7,
77 /// The vehicle or carriage is not boardable and never accepts passengers.
78 /// Useful for special vehicles or carriages (engine, maintenance carriage, etc.).
79 NotBoardable = 8,
80}
81
82/// Realtime positioning information for a given vehicle.
83#[derive(Debug, Default, Clone, PartialEq)]
84pub struct GTFSRealtimeVehiclePosition {
85 /// The Trip that this vehicle is serving.
86 /// Can be empty or partial if the vehicle can not be identified with a given
87 /// trip instance.
88 pub trip: Option<GTFSRealtimeTripDescriptor>, // 1 [message]
89 /// Current position of this vehicle. */
90 pub position: GTFSRealtimePosition, // 2 [message]
91 /// The stop sequence index of the current stop. The meaning of
92 /// current_stop_sequence (i.e., the stop that it refers to) is determined by
93 /// current_status.
94 /// If current_status is missing IN_TRANSIT_TO is assumed.
95 pub current_stop_sequence: Option<u32>, // 3 [uint32]
96 /// The exact status of the vehicle with respect to the current stop.
97 /// Ignored if current_stop_sequence is missing.
98 pub current_status: GTFSVehicleStopStatus, // 4 [enum]
99 /// Moment at which the vehicle's position was measured. In POSIX time
100 /// (i.e., number of seconds since January 1st 1970 00:00:00 UTC).
101 pub timestamp: Option<Date>, // 5 [uint64]
102 /// Congestion level that is affecting this vehicle.
103 pub congestion_level: GTFSRealtimeCongestionLevel, // 6 [enum]
104 /// Identifies the current stop. The value must be the same as in stops.txt in
105 /// the corresponding GTFS feed.
106 pub stop_id: Option<String>,
107 /// 7 Additional information on the vehicle that is serving this trip.
108 pub vehicle: Option<GTFSRealtimeVehicleDescriptor>, // 8 [message]
109 /// If multi_carriage_status is populated with per-carriage OccupancyStatus,
110 /// then this field should describe the entire vehicle with all carriages accepting passengers considered.
111 pub occupancy_status: Option<GTFSRealtimeOccupancyStatus>, // 9 [enum]
112 /// A percentage value indicating the degree of passenger occupancy in the vehicle.
113 /// The values are represented as an integer without decimals. 0 means 0% and 100 means 100%.
114 /// The value 100 should represent the total maximum occupancy the vehicle was designed for,
115 /// including both seated and standing capacity, and current operating regulations allow.
116 /// The value may exceed 100 if there are more passengers than the maximum designed capacity.
117 /// The precision of occupancy_percentage should be low enough that individual passengers cannot be tracked boarding or alighting the vehicle.
118 /// If multi_carriage_status is populated with per-carriage occupancy_percentage,
119 /// then this field should describe the entire vehicle with all carriages accepting passengers considered.
120 /// This field is still experimental, and subject to change. It may be formally adopted in the future.
121 pub occupancy_percentage: Option<u32>, // 10 [uint32]
122 /// Details of the multiple carriages of this given vehicle.
123 /// The first occurrence represents the first carriage of the vehicle,
124 /// given the current direction of travel.
125 /// The number of occurrences of the multi_carriage_details
126 /// field represents the number of carriages of the vehicle.
127 /// It also includes non boardable carriages,
128 /// like engines, maintenance carriages, etc… as they provide valuable
129 /// information to passengers about where to stand on a platform.
130 /// This message/field is still experimental, and subject to change. It may be formally adopted in the future.
131 pub multi_carriage_details: Vec<GTFSRealtimeMultiCarriageDetails>, // 11 [message]
132}
133/// Read in the contents of the GTFSRealtimeVehiclePosition
134impl ProtoRead for GTFSRealtimeVehiclePosition {
135 fn read(&mut self, tag: u64, pb: &mut Protobuf) {
136 match tag {
137 1 => {
138 let mut trip = GTFSRealtimeTripDescriptor::default();
139 pb.read_message(&mut trip);
140 self.trip = Some(trip);
141 }
142 2 => {
143 let mut position = GTFSRealtimePosition::default();
144 pb.read_message(&mut position);
145 self.position = position;
146 }
147 3 => self.current_stop_sequence = Some(pb.read_varint()),
148 4 => self.current_status = pb.read_varint(),
149 5 => self.timestamp = Some(Date::from_time(pb.read_varint::<u64>() as i64 * 1000)),
150 6 => self.congestion_level = pb.read_varint(),
151 7 => self.stop_id = Some(pb.read_string()),
152 8 => {
153 let mut vehicle = GTFSRealtimeVehicleDescriptor::default();
154 pb.read_message(&mut vehicle);
155 self.vehicle = Some(vehicle);
156 }
157 9 => self.occupancy_status = Some(pb.read_varint()),
158 10 => self.occupancy_percentage = Some(pb.read_varint()),
159 11 => {
160 let mut multi_carriage_details = GTFSRealtimeMultiCarriageDetails::default();
161 pb.read_message(&mut multi_carriage_details);
162 self.multi_carriage_details.push(multi_carriage_details);
163 }
164 _ => panic!("unknown tag {}", tag),
165 }
166 }
167}
168
169/// Wheelchair accessibility of the trip
170#[repr(u8)]
171#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, BitCast)]
172pub enum GTFSRealtimeWheelchairAccessible {
173 /// The trip doesn't have information about wheelchair accessibility.
174 /// This is the **default** behavior. If the static GTFS contains a
175 /// _wheelchair_accessible_ value, it won't be overwritten.
176 #[default]
177 NoValue = 0,
178 /// The trip has no accessibility value present.
179 /// This value will overwrite the value from the GTFS.
180 Unknown = 1,
181 /// The trip is wheelchair accessible.
182 /// This value will overwrite the value from the GTFS.
183 WheelchairAccessible = 2,
184 /// The trip is **not** wheelchair accessible.
185 /// This value will overwrite the value from the GTFS.
186 WheelchairInaccessible = 3,
187}
188
189/// Identification information for the vehicle performing the trip.
190#[derive(Debug, Default, Clone, PartialEq)]
191pub struct GTFSRealtimeVehicleDescriptor {
192 /// Internal system identification of the vehicle. Should be unique per
193 /// vehicle, and can be used for tracking the vehicle as it proceeds through
194 /// the system.
195 pub id: Option<String>, // 1 [string]
196 /// User visible label, i.e., something that must be shown to the passenger to
197 /// help identify the correct vehicle.
198 pub label: Option<String>, // 2 [string]
199 /// The license plate of the vehicle.
200 pub license_plate: Option<String>, // 3 [string]
201 /// Wheelchair accessibility of the trip
202 pub wheelchair_accessible: GTFSRealtimeWheelchairAccessible, // 4 [enum]
203}
204/// Read in the contents of the GTFSRealtimeVehicleDescriptor
205impl ProtoRead for GTFSRealtimeVehicleDescriptor {
206 fn read(&mut self, tag: u64, pb: &mut Protobuf) {
207 match tag {
208 1 => self.id = Some(pb.read_string()),
209 2 => self.label = Some(pb.read_string()),
210 3 => self.license_plate = Some(pb.read_string()),
211 4 => self.wheelchair_accessible = pb.read_varint(),
212 _ => panic!("unknown tag {}", tag),
213 }
214 }
215}
216
217/// Carriage specific details, used for vehicles composed of several carriages
218/// This message/field is still experimental, and subject to change. It may be formally adopted in the future.
219#[derive(Debug, Default, Clone, PartialEq)]
220pub struct GTFSRealtimeMultiCarriageDetails {
221 /// Identification of the carriage. Should be unique per vehicle.
222 pub id: Option<String>, // 1 [string]
223 /// User visible label that may be shown to the passenger to help identify
224 /// the carriage. Example: "7712", "Car ABC-32", etc...
225 /// This message/field is still experimental, and subject to change. It may be formally adopted in the future.
226 pub label: Option<String>, // 2 [string]
227 /// Occupancy status for this given carriage, in this vehicle
228 /// This message/field is still experimental, and subject to change. It may be formally adopted in the future.
229 pub occupancy_status: GTFSRealtimeOccupancyStatus, // 3 [enum]
230 /// Occupancy percentage for this given carriage, in this vehicle.
231 /// Follows the same rules as "VehiclePosition.occupancy_percentage"
232 /// -1 in case data is not available for this given carriage (as protobuf defaults to 0 otherwise)
233 /// This message/field is still experimental, and subject to change. It may be formally adopted in the future.
234 pub occupancy_percentage: i32, // 4 [int32]
235 /// Identifies the order of this carriage with respect to the other
236 /// carriages in the vehicle's list of CarriageDetails.
237 /// The first carriage in the direction of travel must have a value of 1.
238 /// The second value corresponds to the second carriage in the direction
239 /// of travel and must have a value of 2, and so forth.
240 /// For example, the first carriage in the direction of travel has a value of 1.
241 /// If the second carriage in the direction of travel has a value of 3,
242 /// consumers will discard data for all carriages (i.e., the multi_carriage_details field).
243 /// Carriages without data must be represented with a valid carriage_sequence number and the fields
244 /// without data should be omitted (alternately, those fields could also be included and set to the "no data" values).
245 /// This message/field is still experimental, and subject to change. It may be formally adopted in the future.
246 pub carriage_sequence: Option<u32>, // 5 [uint32]
247}
248/// Read in the contents of the GTFSRealtimeMultiCarriageDetails
249impl ProtoRead for GTFSRealtimeMultiCarriageDetails {
250 fn read(&mut self, tag: u64, pb: &mut Protobuf) {
251 match tag {
252 1 => self.id = Some(pb.read_string()),
253 2 => self.label = Some(pb.read_string()),
254 3 => self.occupancy_status = pb.read_varint(),
255 4 => self.occupancy_percentage = pb.read_s_varint(),
256 5 => self.carriage_sequence = Some(pb.read_varint()),
257 _ => panic!("unknown tag {}", tag),
258 }
259 }
260}