gistools/readers/gtfs/schedule/trips.rs
1use crate::readers::csv::parse_csv_as_record;
2use alloc::{collections::BTreeMap, string::String};
3use s2json::MValueCompatible;
4
5/// Indicates the direction of travel for a trip. This field should not be used in routing; it provides a way to separate trips by direction when publishing time tables. Valid options are:
6/// - 0 - Travel in one direction (e.g. outbound travel).
7/// - 1 - Travel in the opposite direction (e.g. inbound travel).
8///
9/// Example: The trip_headsign and direction_id fields may be used together to assign a name to travel in each direction for a set of trips. A trips.txt file could contain these records for use in time tables:
10///
11/// ```csv
12/// trip_id,...,trip_headsign,direction_id
13/// 1234,...,Airport,0
14/// 1505,...,Downtown,1
15/// ```
16#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)]
17pub enum GTFSDirectionId {
18 /// Outbound, e.g., "Airport"
19 #[default]
20 Outbound = 0, // e.g., "Airport"
21 /// Inbound, e.g., "Downtown"
22 Inbound = 1, // e.g., "Downtown"
23}
24impl From<i8> for GTFSDirectionId {
25 fn from(value: i8) -> Self {
26 match value {
27 1 => GTFSDirectionId::Inbound,
28 _ => GTFSDirectionId::Outbound,
29 }
30 }
31}
32
33/// Indicates wheelchair accessibility. Valid options are:
34/// - 0 or empty - No accessibility information for the trip.
35/// - 1 - Vehicle being used on this particular trip can accommodate at least one rider in a wheelchair.
36/// - 2 - No riders in wheelchairs can be accommodated on this trip.
37#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)]
38pub enum GTFSWheelchairAccessibility {
39 /// Or empty
40 #[default]
41 NoInfo = 0, // or empty
42 /// At least one wheelchair
43 Accessible = 1, // at least one wheelchair space
44 /// No wheelchair
45 NotAccessible = 2, // no wheelchair accommodation
46}
47impl From<i8> for GTFSWheelchairAccessibility {
48 fn from(value: i8) -> Self {
49 match value {
50 1 => GTFSWheelchairAccessibility::Accessible,
51 2 => GTFSWheelchairAccessibility::NotAccessible,
52 _ => GTFSWheelchairAccessibility::NoInfo,
53 }
54 }
55}
56
57/// Indicates whether bikes are allowed. Valid options are:
58/// - 0 or empty - No bike information for the trip.
59/// - 1 - Vehicle being used on this particular trip can accommodate at least one bicycle.
60/// - 2 - No bicycles are allowed on this trip.
61#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)]
62pub enum GTFSBikesAllowed {
63 /// Or empty
64 #[default]
65 NoInfo = 0,
66 /// at least one bicycle can be accommodated
67 Allowed = 1,
68 /// no bicycles allowed
69 NotAllowed = 2,
70}
71impl From<i8> for GTFSBikesAllowed {
72 fn from(value: i8) -> Self {
73 match value {
74 1 => GTFSBikesAllowed::Allowed,
75 2 => GTFSBikesAllowed::NotAllowed,
76 _ => GTFSBikesAllowed::NoInfo,
77 }
78 }
79}
80
81/// # Trip Information
82///
83/// ## Details
84/// **Required** - Trips for each route. A trip is a sequence of two or more stops that occur during
85/// a specific time period.
86#[derive(Debug, Default, Clone, PartialEq, MValueCompatible)]
87pub struct GTFSTrip {
88 /// **Required**
89 /// Identifies which route this trip belongs to (`routes.route_id`).
90 pub route_id: String,
91 /// **Required**
92 /// Identifies a set of dates when service is available (`calendar.service_id` or `calendar_dates.service_id`).
93 pub service_id: String,
94 /// **Required**
95 /// Unique identifier for a trip (`trip_id`).
96 pub trip_id: String,
97 /// **Optional**
98 /// Text that appears on signage identifying the trip's destination to riders. This field is
99 /// recommended for all services with headsign text displayed on the vehicle which may be used
100 /// to distinguish amongst trips in a route.
101 ///
102 /// If the headsign changes during a trip, values for trip_headsign may be overridden by
103 /// defining values in stop_times.stop_headsign for specific stop_times along the trip.
104 pub trip_headsign: Option<String>,
105 /// **Optional**
106 /// Public-facing text used to identify the trip (e.g., train numbers).
107 pub trip_short_name: Option<String>,
108 /// **Optional**
109 /// Updated to use an enum for direction.
110 /// 0 = Outbound, 1 = Inbound.
111 pub direction_id: Option<i8>,
112 /// **Optional**
113 /// Identifies the block this trip belongs to. Sequential trips with the same block_id typically
114 /// use the same vehicle.
115 pub block_id: Option<String>,
116 /// **Conditionally Required**
117 /// References a geospatial shape describing the vehicle's travel path (`shapes.shape_id`).
118 /// Required if the trip uses continuous pickup or drop-off rules; otherwise optional.
119 pub shape_id: Option<String>,
120 /// **Optional**
121 /// Updated to use an enum for wheelchair accessibility.
122 /// 0 = NoInfo, 1 = Accessible, 2 = NotAccessible.
123 pub wheelchair_accessible: Option<i8>,
124 /// **Optional**
125 /// Updated to use an enum for bikes allowed.
126 /// 0 = NoInfo, 1 = Allowed, 2 = NotAllowed.
127 pub bikes_allowed: Option<i8>,
128}
129impl GTFSTrip {
130 /// Create a new GTFSTrip
131 pub fn new(source: &str) -> BTreeMap<String, GTFSTrip> {
132 let mut res = BTreeMap::new();
133 for record in parse_csv_as_record::<GTFSTrip>(source, None, None) {
134 res.insert(record.trip_id.clone(), record);
135 }
136 res
137 }
138 /// Get the direction_id
139 pub fn direction_id(&self) -> Option<GTFSDirectionId> {
140 self.direction_id.map(GTFSDirectionId::from)
141 }
142 /// Get the wheelchair_accessible
143 pub fn wheelchair_accessible(&self) -> Option<GTFSWheelchairAccessibility> {
144 self.wheelchair_accessible.map(GTFSWheelchairAccessibility::from)
145 }
146 /// Get the bikes_allowed
147 pub fn bikes_allowed(&self) -> Option<GTFSBikesAllowed> {
148 self.bikes_allowed.map(GTFSBikesAllowed::from)
149 }
150}