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}