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}