gtfs_structures/
objects.rs

1pub use crate::enums::*;
2use crate::serde_helpers::*;
3use chrono::{Datelike, NaiveDate, Weekday};
4use rgb::RGB8;
5
6use std::fmt;
7use std::hash::Hash;
8use std::sync::Arc;
9
10/// Objects that have an identifier implement this trait
11///
12/// Those identifier are technical and should not be shown to travellers
13pub trait Id {
14    /// Identifier of the object
15    fn id(&self) -> &str;
16}
17
18impl<T: Id> Id for Arc<T> {
19    fn id(&self) -> &str {
20        self.as_ref().id()
21    }
22}
23
24/// Trait to introspect what is the object’s type (stop, route…)
25pub trait Type {
26    /// What is the type of the object
27    fn object_type(&self) -> ObjectType;
28}
29
30impl<T: Type> Type for Arc<T> {
31    fn object_type(&self) -> ObjectType {
32        self.as_ref().object_type()
33    }
34}
35
36/// A calender describes on which days the vehicle runs. See <https://gtfs.org/reference/static/#calendartxt>
37#[derive(Debug, Clone, Deserialize, Serialize, Hash, PartialEq, Eq)]
38pub struct Calendar {
39    /// Unique technical identifier (not for the traveller) of this calendar
40    #[serde(rename = "service_id")]
41    pub id: String,
42    /// Does the service run on mondays
43    #[serde(
44        deserialize_with = "deserialize_bool",
45        serialize_with = "serialize_bool"
46    )]
47    pub monday: bool,
48    /// Does the service run on tuesdays
49    #[serde(
50        deserialize_with = "deserialize_bool",
51        serialize_with = "serialize_bool"
52    )]
53    pub tuesday: bool,
54    /// Does the service run on wednesdays
55    #[serde(
56        deserialize_with = "deserialize_bool",
57        serialize_with = "serialize_bool"
58    )]
59    pub wednesday: bool,
60    /// Does the service run on thursdays
61    #[serde(
62        deserialize_with = "deserialize_bool",
63        serialize_with = "serialize_bool"
64    )]
65    pub thursday: bool,
66    /// Does the service run on fridays
67    #[serde(
68        deserialize_with = "deserialize_bool",
69        serialize_with = "serialize_bool"
70    )]
71    pub friday: bool,
72    /// Does the service run on saturdays
73    #[serde(
74        deserialize_with = "deserialize_bool",
75        serialize_with = "serialize_bool"
76    )]
77    pub saturday: bool,
78    /// Does the service run on sundays
79    #[serde(
80        deserialize_with = "deserialize_bool",
81        serialize_with = "serialize_bool"
82    )]
83    pub sunday: bool,
84    /// Start service day for the service interval
85    #[serde(
86        deserialize_with = "deserialize_date",
87        serialize_with = "serialize_date"
88    )]
89    pub start_date: NaiveDate,
90    /// End service day for the service interval. This service day is included in the interval
91    #[serde(
92        deserialize_with = "deserialize_date",
93        serialize_with = "serialize_date"
94    )]
95    pub end_date: NaiveDate,
96}
97
98impl Type for Calendar {
99    fn object_type(&self) -> ObjectType {
100        ObjectType::Calendar
101    }
102}
103
104impl Id for Calendar {
105    fn id(&self) -> &str {
106        &self.id
107    }
108}
109
110impl fmt::Display for Calendar {
111    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
112        write!(f, "{}—{}", self.start_date, self.end_date)
113    }
114}
115
116impl Calendar {
117    /// Returns true if there is a service running on that day
118    pub fn valid_weekday(&self, date: NaiveDate) -> bool {
119        match date.weekday() {
120            Weekday::Mon => self.monday,
121            Weekday::Tue => self.tuesday,
122            Weekday::Wed => self.wednesday,
123            Weekday::Thu => self.thursday,
124            Weekday::Fri => self.friday,
125            Weekday::Sat => self.saturday,
126            Weekday::Sun => self.sunday,
127        }
128    }
129}
130
131/// Defines a specific date that can be added or removed from a [Calendar]. See <https://gtfs.org/reference/static/#calendar_datestxt>
132#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq)]
133pub struct CalendarDate {
134    /// Identifier of the service that is modified at this date
135    pub service_id: String,
136    #[serde(
137        deserialize_with = "deserialize_date",
138        serialize_with = "serialize_date"
139    )]
140    /// Date where the service will be added or deleted
141    pub date: NaiveDate,
142    /// Is the service added or deleted
143    pub exception_type: Exception,
144}
145
146/// A physical stop, station or area. See <https://gtfs.org/reference/static/#stopstxt>
147#[derive(Debug, Serialize, Deserialize, Clone, Default)]
148pub struct Stop {
149    /// Unique technical identifier (not for the traveller) of the stop
150    #[serde(rename = "stop_id")]
151    pub id: String,
152    /// Short text or a number that identifies the location for riders
153    #[serde(rename = "stop_code")]
154    pub code: Option<String>,
155    ///Name of the location. Use a name that people will understand in the local and tourist vernacular
156    #[serde(rename = "stop_name")]
157    pub name: Option<String>,
158    /// Description of the location that provides useful, quality information
159    #[serde(default, rename = "stop_desc")]
160    pub description: Option<String>,
161    /// Type of the location
162    #[serde(default)]
163    pub location_type: LocationType,
164    /// Defines hierarchy between the different locations
165    pub parent_station: Option<String>,
166    /// Identifies the fare zone for a stop
167    pub zone_id: Option<String>,
168    /// URL of a web page about the location
169    #[serde(rename = "stop_url")]
170    pub url: Option<String>,
171    /// Longitude of the stop
172    #[serde(deserialize_with = "de_with_optional_float")]
173    #[serde(serialize_with = "serialize_float_as_str")]
174    #[serde(rename = "stop_lon", default)]
175    pub longitude: Option<f64>,
176    /// Latitude of the stop
177    #[serde(deserialize_with = "de_with_optional_float")]
178    #[serde(serialize_with = "serialize_float_as_str")]
179    #[serde(rename = "stop_lat", default)]
180    pub latitude: Option<f64>,
181    /// Timezone of the location
182    #[serde(rename = "stop_timezone")]
183    pub timezone: Option<String>,
184    /// Indicates whether wheelchair boardings are possible from the location
185    #[serde(deserialize_with = "de_with_empty_default", default)]
186    pub wheelchair_boarding: Availability,
187    /// Level of the location. The same level can be used by multiple unlinked stations
188    pub level_id: Option<String>,
189    /// Platform identifier for a platform stop (a stop belonging to a station)
190    pub platform_code: Option<String>,
191    /// Transfers from this Stop
192    #[serde(skip)]
193    pub transfers: Vec<StopTransfer>,
194    /// Pathways from this stop
195    #[serde(skip)]
196    pub pathways: Vec<Pathway>,
197    /// Text to speech readable version of the stop_name
198    #[serde(rename = "tts_stop_name")]
199    pub tts_name: Option<String>,
200}
201
202impl Type for Stop {
203    fn object_type(&self) -> ObjectType {
204        ObjectType::Stop
205    }
206}
207
208impl Id for Stop {
209    fn id(&self) -> &str {
210        &self.id
211    }
212}
213
214impl fmt::Display for Stop {
215    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
216        write!(f, "{}", self.name.as_ref().unwrap_or(&String::from("")))
217    }
218}
219
220/// A [StopTime] where the relations with [Trip] and [Stop] have not been tested
221#[derive(Debug, Clone, Serialize, Deserialize, Default)]
222pub struct RawStopTime {
223    /// [Trip] to which this stop time belongs to
224    pub trip_id: String,
225    /// Arrival time of the stop time.
226    /// It's an option since the intermediate stops can have have no arrival
227    /// and this arrival needs to be interpolated
228    #[serde(
229        deserialize_with = "deserialize_optional_time",
230        serialize_with = "serialize_optional_time"
231    )]
232    pub arrival_time: Option<u32>,
233    /// Departure time of the stop time.
234    /// It's an option since the intermediate stops can have have no departure
235    /// and this departure needs to be interpolated
236    #[serde(
237        deserialize_with = "deserialize_optional_time",
238        serialize_with = "serialize_optional_time"
239    )]
240    pub departure_time: Option<u32>,
241    /// Identifier of the [Stop] where the vehicle stops
242    pub stop_id: String,
243    /// Order of stops for a particular trip. The values must increase along the trip but do not need to be consecutive
244    pub stop_sequence: u32,
245    /// Text that appears on signage identifying the trip's destination to riders
246    pub stop_headsign: Option<String>,
247    /// Indicates pickup method
248    #[serde(default)]
249    pub pickup_type: PickupDropOffType,
250    /// Indicates drop off method
251    #[serde(default)]
252    pub drop_off_type: PickupDropOffType,
253    /// Indicates whether a rider can board the transit vehicle anywhere along the vehicle’s travel path
254    #[serde(default)]
255    pub continuous_pickup: ContinuousPickupDropOff,
256    /// Indicates whether a rider can alight from the transit vehicle at any point along the vehicle’s travel path
257    #[serde(default)]
258    pub continuous_drop_off: ContinuousPickupDropOff,
259    /// Actual distance traveled along the associated shape, from the first stop to the stop specified in this record. This field specifies how much of the shape to draw between any two stops during a trip
260    pub shape_dist_traveled: Option<f32>,
261    /// Indicates if arrival and departure times for a stop are strictly adhered to by the vehicle or if they are instead approximate and/or interpolated times
262    #[serde(default)]
263    pub timepoint: TimepointType,
264}
265
266/// The moment where a vehicle, running on [Trip] stops at a [Stop]. See <https://gtfs.org/reference/static/#stopstxt>
267#[derive(Clone, Debug, Default, Serialize, Deserialize)]
268pub struct StopTime {
269    /// Arrival time of the stop time.
270    /// It's an option since the intermediate stops can have have no arrival
271    /// and this arrival needs to be interpolated
272    pub arrival_time: Option<u32>,
273    /// [Stop] where the vehicle stops
274    pub stop: Arc<Stop>,
275    /// Departure time of the stop time.
276    /// It's an option since the intermediate stops can have have no departure
277    /// and this departure needs to be interpolated
278    pub departure_time: Option<u32>,
279    /// Indicates pickup method
280    pub pickup_type: PickupDropOffType,
281    /// Indicates drop off method
282    pub drop_off_type: PickupDropOffType,
283    /// Order of stops for a particular trip. The values must increase along the trip but do not need to be consecutive
284    pub stop_sequence: u32,
285    /// Text that appears on signage identifying the trip's destination to riders
286    pub stop_headsign: Option<String>,
287    /// Indicates whether a rider can board the transit vehicle anywhere along the vehicle’s travel path
288    pub continuous_pickup: ContinuousPickupDropOff,
289    /// Indicates whether a rider can alight from the transit vehicle at any point along the vehicle’s travel path
290    pub continuous_drop_off: ContinuousPickupDropOff,
291    /// Actual distance traveled along the associated shape, from the first stop to the stop specified in this record. This field specifies how much of the shape to draw between any two stops during a trip
292    pub shape_dist_traveled: Option<f32>,
293    /// Indicates if arrival and departure times for a stop are strictly adhered to by the vehicle or if they are instead approximate and/or interpolated times
294    pub timepoint: TimepointType,
295}
296
297impl StopTime {
298    /// Creates [StopTime] by linking a [RawStopTime::stop_id] to the actual [Stop]
299    pub fn from(stop_time_gtfs: RawStopTime, stop: Arc<Stop>) -> Self {
300        Self {
301            arrival_time: stop_time_gtfs.arrival_time,
302            departure_time: stop_time_gtfs.departure_time,
303            stop,
304            pickup_type: stop_time_gtfs.pickup_type,
305            drop_off_type: stop_time_gtfs.drop_off_type,
306            stop_sequence: stop_time_gtfs.stop_sequence,
307            stop_headsign: stop_time_gtfs.stop_headsign,
308            continuous_pickup: stop_time_gtfs.continuous_pickup,
309            continuous_drop_off: stop_time_gtfs.continuous_drop_off,
310            shape_dist_traveled: stop_time_gtfs.shape_dist_traveled,
311            timepoint: stop_time_gtfs.timepoint,
312        }
313    }
314}
315
316/// A route is a commercial line (there can be various stop sequences for a same line). See <https://gtfs.org/reference/static/#routestxt>
317#[derive(Debug, Clone, Serialize, Deserialize, Default)]
318pub struct Route {
319    /// Unique technical (not for the traveller) identifier for the route
320    #[serde(rename = "route_id")]
321    pub id: String,
322    /// Short name of a route. This will often be a short, abstract identifier like "32", "100X", or "Green" that riders use to identify a route, but which doesn't give any indication of what places the route serves
323    #[serde(rename = "route_short_name", default)]
324    pub short_name: Option<String>,
325    /// Full name of a route. This name is generally more descriptive than the [Route::short_name]] and often includes the route's destination or stop
326    #[serde(rename = "route_long_name", default)]
327    pub long_name: Option<String>,
328    /// Description of a route that provides useful, quality information
329    #[serde(rename = "route_desc")]
330    pub desc: Option<String>,
331    /// Indicates the type of transportation used on a route
332    pub route_type: RouteType,
333    /// URL of a web page about the particular route
334    #[serde(rename = "route_url")]
335    pub url: Option<String>,
336    /// Agency for the specified route
337    pub agency_id: Option<String>,
338    /// Orders the routes in a way which is ideal for presentation to customers. Routes with smaller route_sort_order values should be displayed first.
339    #[serde(rename = "route_sort_order")]
340    pub order: Option<u32>,
341    /// Route color designation that matches public facing material
342    #[serde(
343        deserialize_with = "deserialize_optional_color",
344        serialize_with = "serialize_optional_color",
345        rename = "route_color",
346        default
347    )]
348    pub color: Option<RGB8>,
349    /// Legible color to use for text drawn against a background of [Route::route_color]
350    #[serde(
351        deserialize_with = "deserialize_optional_color",
352        serialize_with = "serialize_optional_color",
353        rename = "route_text_color",
354        default
355    )]
356    pub text_color: Option<RGB8>,
357    /// Indicates whether a rider can board the transit vehicle anywhere along the vehicle’s travel path
358    #[serde(default)]
359    pub continuous_pickup: ContinuousPickupDropOff,
360    /// Indicates whether a rider can alight from the transit vehicle at any point along the vehicle’s travel path
361    #[serde(default)]
362    pub continuous_drop_off: ContinuousPickupDropOff,
363}
364
365impl Route {
366    /// Legible color to use for text drawn against a background of [Route::route_color]
367    /// Defaults to white (FFFFFF) when omitted or left empty.
368    pub fn text_color(&self) -> RGB8 {
369        self.text_color.unwrap_or_default()
370    }
371
372    /// Legible color to use for text drawn against a background of [Route::route_color]
373    /// Defaults to black (000000) when omitted or left empty.
374    pub fn color(&self) -> RGB8 {
375        self.color.unwrap_or_else(default_route_color)
376    }
377}
378
379impl Type for Route {
380    fn object_type(&self) -> ObjectType {
381        ObjectType::Route
382    }
383}
384
385impl Id for Route {
386    fn id(&self) -> &str {
387        &self.id
388    }
389}
390
391impl fmt::Display for Route {
392    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
393        if let Some(long_name) = self.long_name.as_ref() {
394            write!(f, "{long_name}")
395        } else if let Some(short_name) = self.short_name.as_ref() {
396            write!(f, "{short_name}")
397        } else {
398            write!(f, "{}", self.id)
399        }
400    }
401}
402
403/// Raw structure to hold translations as defined in the GTFS file. See <https://gtfs.org/schedule/reference/#translationstxt>
404#[derive(Debug, Clone, Serialize, Deserialize, Default)]
405pub struct RawTranslation {
406    /// To which table does the translation apply
407    pub table_name: String,
408    /// To which field does the translation apply
409    pub field_name: String,
410    /// Language of the translation
411    pub language: String,
412    /// Translated value
413    pub translation: String,
414    /// The record identifier to translate. For stop_times, it’s the trip_id
415    pub record_id: Option<String>,
416    /// Only for stop_times: the stop_sequence
417    pub record_sub_id: Option<String>,
418    /// Translate all values that match exactly, instead of specifying individual records
419    pub field_value: Option<String>,
420}
421
422/// A [Trip] where the relationships with other objects have not been checked
423#[derive(Debug, Clone, Serialize, Deserialize, Default)]
424pub struct RawTrip {
425    /// Unique technical (not for the traveller) identifier for the Trip
426    #[serde(rename = "trip_id")]
427    pub id: String,
428    /// References the [Calendar] on which this trip runs
429    pub service_id: String,
430    /// References along which [Route] this trip runs
431    pub route_id: String,
432    /// Shape of the trip
433    pub shape_id: Option<String>,
434    /// Text that appears on signage identifying the trip's destination to riders
435    pub trip_headsign: Option<String>,
436    /// Public facing text used to identify the trip to riders, for instance, to identify train numbers for commuter rail trips
437    pub trip_short_name: Option<String>,
438    /// Indicates the direction of travel for a trip. This field is not used in routing; it provides a way to separate trips by direction when publishing time tables
439    pub direction_id: Option<DirectionType>,
440    /// Identifies the block to which the trip belongs. A block consists of a single trip or many sequential trips made using the same vehicle, defined by shared service days and block_id. A block_id can have trips with different service days, making distinct blocks
441    pub block_id: Option<String>,
442    /// Indicates wheelchair accessibility
443    #[serde(default)]
444    pub wheelchair_accessible: Availability,
445    /// Indicates whether bikes are allowed
446    #[serde(default)]
447    pub bikes_allowed: BikesAllowedType,
448}
449
450impl Type for RawTrip {
451    fn object_type(&self) -> ObjectType {
452        ObjectType::Trip
453    }
454}
455
456impl Id for RawTrip {
457    fn id(&self) -> &str {
458        &self.id
459    }
460}
461
462impl fmt::Display for RawTrip {
463    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
464        write!(
465            f,
466            "route id: {}, service id: {}",
467            self.route_id, self.service_id
468        )
469    }
470}
471
472/// A Trip is a vehicle that follows a sequence of [StopTime] on certain days. See <https://gtfs.org/reference/static/#tripstxt>
473#[derive(Clone, Debug, Default, Serialize, Deserialize)]
474pub struct Trip {
475    /// Unique technical identifier (not for the traveller) for the Trip
476    pub id: String,
477    /// References the [Calendar] on which this trip runs
478    pub service_id: String,
479    /// References along which [Route] this trip runs
480    pub route_id: String,
481    /// All the [StopTime] that define the trip
482    pub stop_times: Vec<StopTime>,
483    /// Unique technical (not for the traveller) identifier for the Shape
484    pub shape_id: Option<String>,
485    /// Text that appears on signage identifying the trip's destination to riders
486    pub trip_headsign: Option<String>,
487    /// Public facing text used to identify the trip to riders, for instance, to identify train numbers for commuter rail trips
488    pub trip_short_name: Option<String>,
489    /// Indicates the direction of travel for a trip. This field is not used in routing; it provides a way to separate trips by direction when publishing time tables
490    pub direction_id: Option<DirectionType>,
491    /// Identifies the block to which the trip belongs. A block consists of a single trip or many sequential trips made using the same vehicle, defined by shared service days and block_id. A block_id can have trips with different service days, making distinct blocks
492    pub block_id: Option<String>,
493    /// Indicates wheelchair accessibility
494    pub wheelchair_accessible: Availability,
495    /// Indicates whether bikes are allowed
496    pub bikes_allowed: BikesAllowedType,
497    /// During which periods the trip runs by frequency and not by fixed timetable
498    pub frequencies: Vec<Frequency>,
499}
500
501impl Type for Trip {
502    fn object_type(&self) -> ObjectType {
503        ObjectType::Trip
504    }
505}
506
507impl Id for Trip {
508    fn id(&self) -> &str {
509        &self.id
510    }
511}
512
513impl fmt::Display for Trip {
514    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
515        write!(
516            f,
517            "route id: {}, service id: {}",
518            self.route_id, self.service_id
519        )
520    }
521}
522
523/// General informations about the agency running the network. See <https://gtfs.org/reference/static/#agencytxt>
524#[derive(Clone, Debug, Serialize, Deserialize, Default)]
525pub struct Agency {
526    /// Unique technical (not for the traveller) identifier for the Agency
527    #[serde(rename = "agency_id")]
528    pub id: Option<String>,
529    ///Full name of the transit agency
530    #[serde(rename = "agency_name")]
531    pub name: String,
532    /// Full url of the transit agency.
533    #[serde(rename = "agency_url")]
534    pub url: String,
535    /// Timezone where the transit agency is located
536    #[serde(rename = "agency_timezone")]
537    pub timezone: String,
538    /// Primary language used by this transit agency
539    #[serde(rename = "agency_lang")]
540    pub lang: Option<String>,
541    /// A voice telephone number for the specified agency
542    #[serde(rename = "agency_phone")]
543    pub phone: Option<String>,
544    /// URL of a web page that allows a rider to purchase tickets or other fare instruments for that agency online
545    #[serde(rename = "agency_fare_url")]
546    pub fare_url: Option<String>,
547    /// Email address actively monitored by the agency’s customer service department
548    #[serde(rename = "agency_email")]
549    pub email: Option<String>,
550}
551
552impl Type for Agency {
553    fn object_type(&self) -> ObjectType {
554        ObjectType::Agency
555    }
556}
557
558impl Id for Agency {
559    fn id(&self) -> &str {
560        match &self.id {
561            None => "",
562            Some(id) => id,
563        }
564    }
565}
566
567impl fmt::Display for Agency {
568    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
569        write!(f, "{}", self.name)
570    }
571}
572
573/// A single geographical point decribing the shape of a [Trip]. See <https://gtfs.org/reference/static/#shapestxt>
574#[derive(Clone, Debug, Serialize, Deserialize, Default)]
575pub struct Shape {
576    /// Unique technical (not for the traveller) identifier for the Shape
577    #[serde(rename = "shape_id")]
578    pub id: String,
579    #[serde(rename = "shape_pt_lat", default)]
580    /// Latitude of a shape point
581    pub latitude: f64,
582    /// Longitude of a shape point
583    #[serde(rename = "shape_pt_lon", default)]
584    pub longitude: f64,
585    /// Sequence in which the shape points connect to form the shape. Values increase along the trip but do not need to be consecutive.
586    #[serde(rename = "shape_pt_sequence")]
587    pub sequence: usize,
588    /// Actual distance traveled along the shape from the first shape point to the point specified in this record. Used by trip planners to show the correct portion of the shape on a map
589    #[serde(rename = "shape_dist_traveled")]
590    pub dist_traveled: Option<f32>,
591}
592
593impl Type for Shape {
594    fn object_type(&self) -> ObjectType {
595        ObjectType::Shape
596    }
597}
598
599impl Id for Shape {
600    fn id(&self) -> &str {
601        &self.id
602    }
603}
604
605/// Defines one possible fare. See <https://gtfs.org/reference/static/#fare_attributestxt>
606#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
607pub struct FareAttribute {
608    /// Unique technical (not for the traveller) identifier for the FareAttribute
609    #[serde(rename = "fare_id")]
610    pub id: String,
611    /// Fare price, in the unit specified by [FareAttribute::currency]
612    pub price: String,
613    /// Currency used to pay the fare.
614    #[serde(rename = "currency_type")]
615    pub currency: String,
616    ///Indicates when the fare must be paid
617    pub payment_method: PaymentMethod,
618    /// Indicates the number of transfers permitted on this fare
619    pub transfers: Transfers,
620    /// Identifies the relevant agency for a fare
621    pub agency_id: Option<String>,
622    /// Length of time in seconds before a transfer expires
623    pub transfer_duration: Option<usize>,
624}
625
626impl Id for FareAttribute {
627    fn id(&self) -> &str {
628        &self.id
629    }
630}
631
632impl Type for FareAttribute {
633    fn object_type(&self) -> ObjectType {
634        ObjectType::Fare
635    }
636}
637
638/// Used to describe the range of fares available for purchase by riders or taken into account
639/// when computing the total fare for journeys with multiple legs, such as transfer costs.
640/// https://gtfs.org/documentation/schedule/reference/#fare_productstxt
641#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
642pub struct FareProduct {
643    /// Identifies a fare product or set of fare products.
644    #[serde(rename = "fare_product_id")]
645    pub id: String,
646    /// The name of the fare product as displayed to riders.
647    #[serde(rename = "fare_product_name")]
648    pub name: Option<String>,
649    /// Identifies a rider category eligible for the fare product.
650    pub rider_category_id: Option<String>,
651    /// Identifies a fare media that can be employed to use the fare product during the trip.
652    pub fare_media_id: Option<String>,
653    /// The cost of the fare product. May be negative to represent transfer discounts. May be zero to represent a fare product that is free.
654    pub amount: String,
655    /// The currency of the cost of the fare product.
656    pub currency: String,
657}
658
659impl Id for FareProduct {
660    fn id(&self) -> &str {
661        &self.id
662    }
663}
664
665impl Type for FareProduct {
666    fn object_type(&self) -> ObjectType {
667        ObjectType::Fare
668    }
669}
670
671/// To describe the different fare media that can be employed to use fare products.
672/// Fare media are physical or virtual holders used for the representation and/or validation of a fare product.
673/// https://gtfs.org/documentation/schedule/reference/#fare_mediatxt
674#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
675pub struct FareMedia {
676    /// Identifies a fare media.
677    #[serde(rename = "fare_media_id")]
678    pub id: String,
679    /// The name of the fare media.
680    #[serde(rename = "fare_media_name")]
681    pub name: Option<String>,
682    /// The type of fare media
683    #[serde(rename = "fare_media_type")]
684    pub media_type: FareMediaType,
685}
686
687impl Id for FareMedia {
688    fn id(&self) -> &str {
689        &self.id
690    }
691}
692
693impl Type for FareMedia {
694    fn object_type(&self) -> ObjectType {
695        ObjectType::Fare
696    }
697}
698
699/// Defines categories of riders (e.g. elderly, student).
700/// https://gtfs.org/documentation/schedule/reference/#rider_categoriestxt
701#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
702pub struct RiderCategory {
703    /// Identifies a rider category.
704    #[serde(rename = "rider_category_id")]
705    pub id: String,
706    /// Rider category name as displayed to the rider.
707    #[serde(rename = "rider_category_name")]
708    pub name: String,
709    /// is_default_fare_category
710    pub is_default_fare_category: DefaultFareCategory,
711    /// URL of a web page, usually from the operating agency, that provides
712    /// detailed information about a specific rider category and/or describes its eligibility criteria.
713    pub eligibility_url: Option<String>,
714}
715
716impl Id for RiderCategory {
717    fn id(&self) -> &str {
718        &self.id
719    }
720}
721
722impl Type for RiderCategory {
723    fn object_type(&self) -> ObjectType {
724        ObjectType::Fare
725    }
726}
727
728/// Defines one possible fare. See <https://gtfs.org/schedule/reference/#fare_rulestxt>
729#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
730pub struct FareRule {
731    /// ID of the referenced FareAttribute.
732    pub fare_id: String,
733    /// ID of a [Route] associated with the fare class
734    pub route_id: Option<String>,
735    /// Identifies an origin zone. References a [Stop].zone_id
736    pub origin_id: Option<String>,
737    /// Identifies an destination zone. References a [Stop].zone_id
738    pub destination_id: Option<String>,
739    /// Identifies the zones that a rider will enter while using a given fare class. References a [Stop].zone_id
740    pub contains_id: Option<String>,
741}
742
743/// A [Frequency] before being merged into the corresponding [Trip]
744#[derive(Clone, Debug, Serialize, Deserialize, Default)]
745pub struct RawFrequency {
746    /// References the [Trip] that uses frequency
747    pub trip_id: String,
748    /// Time at which the first vehicle departs from the first stop of the trip
749    #[serde(
750        deserialize_with = "deserialize_time",
751        serialize_with = "serialize_time"
752    )]
753    pub start_time: u32,
754    /// Time at which service changes to a different headway (or ceases) at the first stop in the trip
755    #[serde(
756        deserialize_with = "deserialize_time",
757        serialize_with = "serialize_time"
758    )]
759    pub end_time: u32,
760    /// Time, in seconds, between departures from the same stop (headway) for the trip, during the time interval specified by start_time and end_time
761    pub headway_secs: u32,
762    /// Indicates the type of service for a trip
763    pub exact_times: Option<ExactTimes>,
764}
765
766/// Timetables can be defined by the frequency of their vehicles. See <<https://gtfs.org/reference/static/#frequenciestxt>>
767#[derive(Clone, Debug, Default, Deserialize, Serialize)]
768pub struct Frequency {
769    /// Time at which the first vehicle departs from the first stop of the trip
770    pub start_time: u32,
771    /// Time at which service changes to a different headway (or ceases) at the first stop in the trip
772    pub end_time: u32,
773    /// Time, in seconds, between departures from the same stop (headway) for the trip, during the time interval specified by start_time and end_time
774    pub headway_secs: u32,
775    /// Indicates the type of service for a trip
776    pub exact_times: Option<ExactTimes>,
777}
778
779impl Frequency {
780    /// Converts from a [RawFrequency] to a [Frequency]
781    pub fn from(frequency: &RawFrequency) -> Self {
782        Self {
783            start_time: frequency.start_time,
784            end_time: frequency.end_time,
785            headway_secs: frequency.headway_secs,
786            exact_times: frequency.exact_times,
787        }
788    }
789}
790
791/// Transfer information between stops before merged into [Stop]
792#[derive(Clone, Debug, Serialize, Deserialize, Default)]
793pub struct RawTransfer {
794    /// Stop from which to leave
795    pub from_stop_id: String,
796    /// Stop which to transfer to
797    pub to_stop_id: String,
798    /// Type of the transfer
799    pub transfer_type: TransferType,
800    /// Minimum time needed to make the transfer in seconds
801    pub min_transfer_time: Option<u32>,
802}
803
804#[derive(Clone, Debug, Default, Deserialize, Serialize)]
805/// Transfer information between stops
806pub struct StopTransfer {
807    /// Stop which to transfer to
808    pub to_stop_id: String,
809    /// Type of the transfer
810    pub transfer_type: TransferType,
811    /// Minimum time needed to make the transfer in seconds
812    pub min_transfer_time: Option<u32>,
813}
814
815impl From<RawTransfer> for StopTransfer {
816    /// Converts from a [RawTransfer] to a [StopTransfer]
817    fn from(transfer: RawTransfer) -> Self {
818        Self {
819            to_stop_id: transfer.to_stop_id,
820            transfer_type: transfer.transfer_type,
821            min_transfer_time: transfer.min_transfer_time,
822        }
823    }
824}
825
826/// Meta-data about the feed. See <https://gtfs.org/reference/static/#feed_infotxt>
827#[derive(Clone, Debug, Serialize, Deserialize)]
828pub struct FeedInfo {
829    /// Full name of the organization that publishes the dataset.
830    #[serde(rename = "feed_publisher_name")]
831    pub name: String,
832    /// URL of the dataset publishing organization's website
833    #[serde(rename = "feed_publisher_url")]
834    pub url: String,
835    /// Default language used for the text in this dataset
836    #[serde(rename = "feed_lang")]
837    pub lang: String,
838    /// Defines the language that should be used when the data consumer doesn’t know the language of the rider
839    pub default_lang: Option<String>,
840    /// The dataset provides complete and reliable schedule information for service in the period from this date
841    #[serde(
842        deserialize_with = "deserialize_option_date",
843        serialize_with = "serialize_option_date",
844        rename = "feed_start_date",
845        default
846    )]
847    pub start_date: Option<NaiveDate>,
848    ///The dataset provides complete and reliable schedule information for service in the period until this date
849    #[serde(
850        deserialize_with = "deserialize_option_date",
851        serialize_with = "serialize_option_date",
852        rename = "feed_end_date",
853        default
854    )]
855    pub end_date: Option<NaiveDate>,
856    /// String that indicates the current version of their GTFS dataset
857    #[serde(rename = "feed_version")]
858    pub version: Option<String>,
859    /// Email address for communication regarding the GTFS dataset and data publishing practices
860    #[serde(rename = "feed_contact_email")]
861    pub contact_email: Option<String>,
862    /// URL for contact information, a web-form, support desk, or other tools for communication regarding the GTFS dataset and data publishing practices
863    #[serde(rename = "feed_contact_url")]
864    pub contact_url: Option<String>,
865}
866
867impl fmt::Display for FeedInfo {
868    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
869        write!(f, "{}", self.name)
870    }
871}
872
873/// A graph representation to describe subway or train, with nodes (the locations) and edges (the pathways).
874#[derive(Clone, Debug, Serialize, Deserialize, Default)]
875pub struct RawPathway {
876    /// Uniquely identifies the pathway
877    #[serde(rename = "pathway_id")]
878    pub id: String,
879    /// Location at which the pathway begins
880    pub from_stop_id: String,
881    /// Location at which the pathway ends
882    pub to_stop_id: String,
883    /// Type of pathway between the specified (from_stop_id, to_stop_id) pair
884    #[serde(rename = "pathway_mode")]
885    pub mode: PathwayMode,
886    /// Indicates in which direction the pathway can be used
887    pub is_bidirectional: PathwayDirectionType,
888    /// Horizontal length in meters of the pathway from the origin location to the destination location
889    pub length: Option<f32>,
890    /// Average time in seconds needed to walk through the pathway from the origin location to the destination location
891    pub traversal_time: Option<u32>,
892    /// Number of stairs of the pathway
893    pub stair_count: Option<i32>,
894    /// Maximum slope ratio of the pathway
895    pub max_slope: Option<f32>,
896    /// Minimum width of the pathway in meters
897    pub min_width: Option<f32>,
898    /// String of text from physical signage visible to transit riders
899    pub signposted_as: Option<String>,
900    /// Same than the signposted_as field, but when the pathways is used backward
901    pub reversed_signposted_as: Option<String>,
902}
903
904impl Id for RawPathway {
905    fn id(&self) -> &str {
906        &self.id
907    }
908}
909
910impl Type for RawPathway {
911    fn object_type(&self) -> ObjectType {
912        ObjectType::Pathway
913    }
914}
915
916/// Pathway going from a stop to another.
917#[derive(Debug, Clone, Default, Serialize, Deserialize)]
918pub struct Pathway {
919    /// Uniquely identifies the pathway
920    pub id: String,
921    /// Location at which the pathway ends
922    pub to_stop_id: String,
923    /// Type of pathway between the specified (from_stop_id, to_stop_id) pair
924    pub mode: PathwayMode,
925    /// Indicates in which direction the pathway can be used
926    pub is_bidirectional: PathwayDirectionType,
927    /// Horizontal length in meters of the pathway from the origin location to the destination location
928    pub length: Option<f32>,
929    /// Average time in seconds needed to walk through the pathway from the origin location to the destination location
930    pub traversal_time: Option<u32>,
931    /// Number of stairs of the pathway
932    pub stair_count: Option<i32>,
933    /// Maximum slope ratio of the pathway
934    pub max_slope: Option<f32>,
935    /// Minimum width of the pathway in meters
936    pub min_width: Option<f32>,
937    /// String of text from physical signage visible to transit riders
938    pub signposted_as: Option<String>,
939    /// Same than the signposted_as field, but when the pathways is used backward
940    pub reversed_signposted_as: Option<String>,
941}
942
943impl Id for Pathway {
944    fn id(&self) -> &str {
945        &self.id
946    }
947}
948
949impl Type for Pathway {
950    fn object_type(&self) -> ObjectType {
951        ObjectType::Pathway
952    }
953}
954
955impl From<RawPathway> for Pathway {
956    /// Converts from a [RawPathway] to a [Pathway]
957    fn from(raw: RawPathway) -> Self {
958        Self {
959            id: raw.id,
960            to_stop_id: raw.to_stop_id,
961            mode: raw.mode,
962            is_bidirectional: raw.is_bidirectional,
963            length: raw.length,
964            max_slope: raw.max_slope,
965            min_width: raw.min_width,
966            reversed_signposted_as: raw.reversed_signposted_as,
967            signposted_as: raw.signposted_as,
968            stair_count: raw.stair_count,
969            traversal_time: raw.traversal_time,
970        }
971    }
972}
973
974/// Format of the data
975#[derive(Clone, Debug, Serialize, PartialEq)]
976pub enum SourceFormat {
977    /// `Directory` means the data comes from a directory
978    Directory,
979    /// `Zip` means the data were read from a zip
980    Zip,
981}