Skip to main content

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    /// This field is not part of the main GTFS specification, it is part of the Google Transit Ticketing extension
265    /// Enable or disable buying tickets via a deep link
266    #[serde(default)]
267    pub ticketing_type: TicketingType,
268}
269
270/// The moment where a vehicle, running on [Trip] stops at a [Stop]. See <https://gtfs.org/reference/static/#stopstxt>
271#[derive(Clone, Debug, Default, Serialize, Deserialize)]
272pub struct StopTime {
273    /// Arrival time of the stop time.
274    /// It's an option since the intermediate stops can have have no arrival
275    /// and this arrival needs to be interpolated
276    pub arrival_time: Option<u32>,
277    /// [Stop] where the vehicle stops
278    pub stop: Arc<Stop>,
279    /// Departure time of the stop time.
280    /// It's an option since the intermediate stops can have have no departure
281    /// and this departure needs to be interpolated
282    pub departure_time: Option<u32>,
283    /// Indicates pickup method
284    pub pickup_type: PickupDropOffType,
285    /// Indicates drop off method
286    pub drop_off_type: PickupDropOffType,
287    /// Order of stops for a particular trip. The values must increase along the trip but do not need to be consecutive
288    pub stop_sequence: u32,
289    /// Text that appears on signage identifying the trip's destination to riders
290    pub stop_headsign: Option<String>,
291    /// Indicates whether a rider can board the transit vehicle anywhere along the vehicle’s travel path
292    pub continuous_pickup: ContinuousPickupDropOff,
293    /// Indicates whether a rider can alight from the transit vehicle at any point along the vehicle’s travel path
294    pub continuous_drop_off: ContinuousPickupDropOff,
295    /// 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
296    pub shape_dist_traveled: Option<f32>,
297    /// 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
298    pub timepoint: TimepointType,
299}
300
301impl StopTime {
302    /// Creates [StopTime] by linking a [RawStopTime::stop_id] to the actual [Stop]
303    pub fn from(stop_time_gtfs: RawStopTime, stop: Arc<Stop>) -> Self {
304        Self {
305            arrival_time: stop_time_gtfs.arrival_time,
306            departure_time: stop_time_gtfs.departure_time,
307            stop,
308            pickup_type: stop_time_gtfs.pickup_type,
309            drop_off_type: stop_time_gtfs.drop_off_type,
310            stop_sequence: stop_time_gtfs.stop_sequence,
311            stop_headsign: stop_time_gtfs.stop_headsign,
312            continuous_pickup: stop_time_gtfs.continuous_pickup,
313            continuous_drop_off: stop_time_gtfs.continuous_drop_off,
314            shape_dist_traveled: stop_time_gtfs.shape_dist_traveled,
315            timepoint: stop_time_gtfs.timepoint,
316        }
317    }
318}
319
320/// A route is a commercial line (there can be various stop sequences for a same line). See <https://gtfs.org/reference/static/#routestxt>
321#[derive(Debug, Clone, Serialize, Deserialize, Default)]
322pub struct Route {
323    /// Unique technical (not for the traveller) identifier for the route
324    #[serde(rename = "route_id")]
325    pub id: String,
326    /// 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
327    #[serde(rename = "route_short_name", default)]
328    pub short_name: Option<String>,
329    /// 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
330    #[serde(rename = "route_long_name", default)]
331    pub long_name: Option<String>,
332    /// Description of a route that provides useful, quality information
333    #[serde(rename = "route_desc")]
334    pub desc: Option<String>,
335    /// Indicates the type of transportation used on a route
336    pub route_type: RouteType,
337    /// URL of a web page about the particular route
338    #[serde(rename = "route_url")]
339    pub url: Option<String>,
340    /// Agency for the specified route
341    pub agency_id: Option<String>,
342    /// Orders the routes in a way which is ideal for presentation to customers. Routes with smaller route_sort_order values should be displayed first.
343    #[serde(rename = "route_sort_order")]
344    pub order: Option<u32>,
345    /// Route color designation that matches public facing material
346    #[serde(
347        deserialize_with = "deserialize_optional_color",
348        serialize_with = "serialize_optional_color",
349        rename = "route_color",
350        default
351    )]
352    pub color: Option<RGB8>,
353    /// Legible color to use for text drawn against a background of [Route::route_color]
354    #[serde(
355        deserialize_with = "deserialize_optional_color",
356        serialize_with = "serialize_optional_color",
357        rename = "route_text_color",
358        default
359    )]
360    pub text_color: Option<RGB8>,
361    /// Indicates whether a rider can board the transit vehicle anywhere along the vehicle’s travel path
362    #[serde(default)]
363    pub continuous_pickup: ContinuousPickupDropOff,
364    /// Indicates whether a rider can alight from the transit vehicle at any point along the vehicle’s travel path
365    #[serde(default)]
366    pub continuous_drop_off: ContinuousPickupDropOff,
367    /// This field is not part of the main GTFS specification, it is part of the Google Transit Ticketing extension
368    /// Enable or disable buying tickets via a deep link
369    pub ticketing_deep_link_id: Option<String>,
370}
371
372impl Route {
373    /// Legible color to use for text drawn against a background of [Route::route_color]
374    /// Defaults to white (FFFFFF) when omitted or left empty.
375    pub fn text_color(&self) -> RGB8 {
376        self.text_color.unwrap_or_default()
377    }
378
379    /// Legible color to use for text drawn against a background of [Route::route_color]
380    /// Defaults to black (000000) when omitted or left empty.
381    pub fn color(&self) -> RGB8 {
382        self.color.unwrap_or_else(default_route_color)
383    }
384}
385
386impl Type for Route {
387    fn object_type(&self) -> ObjectType {
388        ObjectType::Route
389    }
390}
391
392impl Id for Route {
393    fn id(&self) -> &str {
394        &self.id
395    }
396}
397
398impl fmt::Display for Route {
399    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
400        if let Some(long_name) = self.long_name.as_ref() {
401            write!(f, "{long_name}")
402        } else if let Some(short_name) = self.short_name.as_ref() {
403            write!(f, "{short_name}")
404        } else {
405            write!(f, "{}", self.id)
406        }
407    }
408}
409
410/// Raw structure to hold translations as defined in the GTFS file. See <https://gtfs.org/schedule/reference/#translationstxt>
411#[derive(Debug, Clone, Serialize, Deserialize, Default)]
412pub struct RawTranslation {
413    /// To which table does the translation apply
414    pub table_name: String,
415    /// To which field does the translation apply
416    pub field_name: String,
417    /// Language of the translation
418    pub language: String,
419    /// Translated value
420    pub translation: String,
421    /// The record identifier to translate. For stop_times, it’s the trip_id
422    pub record_id: Option<String>,
423    /// Only for stop_times: the stop_sequence
424    pub record_sub_id: Option<String>,
425    /// Translate all values that match exactly, instead of specifying individual records
426    pub field_value: Option<String>,
427}
428
429/// A [Trip] where the relationships with other objects have not been checked
430#[derive(Debug, Clone, Serialize, Deserialize, Default)]
431pub struct RawTrip {
432    /// Unique technical (not for the traveller) identifier for the Trip
433    #[serde(rename = "trip_id")]
434    pub id: String,
435    /// References the [Calendar] on which this trip runs
436    pub service_id: String,
437    /// References along which [Route] this trip runs
438    pub route_id: String,
439    /// Shape of the trip
440    pub shape_id: Option<String>,
441    /// Text that appears on signage identifying the trip's destination to riders
442    pub trip_headsign: Option<String>,
443    /// Public facing text used to identify the trip to riders, for instance, to identify train numbers for commuter rail trips
444    pub trip_short_name: Option<String>,
445    /// 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
446    pub direction_id: Option<DirectionType>,
447    /// 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
448    pub block_id: Option<String>,
449    /// Indicates wheelchair accessibility
450    #[serde(default)]
451    pub wheelchair_accessible: Availability,
452    /// Indicates whether bikes are allowed
453    #[serde(default)]
454    pub bikes_allowed: BikesAllowedType,
455    /// This field is not part of the main GTFS specification, it is part of the Google Transit Ticketing extension
456    /// Trip ID to pass to a ticket shop
457    #[serde(default)]
458    pub ticketing_trip_id: Option<String>,
459    /// This field is not part of the main GTFS specification, it is part of the Google Transit Ticketing extension
460    /// Enable or disable buying tickets via a deep link
461    #[serde(default)]
462    pub ticketing_type: TicketingType,
463}
464
465impl Type for RawTrip {
466    fn object_type(&self) -> ObjectType {
467        ObjectType::Trip
468    }
469}
470
471impl Id for RawTrip {
472    fn id(&self) -> &str {
473        &self.id
474    }
475}
476
477impl fmt::Display for RawTrip {
478    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
479        write!(
480            f,
481            "route id: {}, service id: {}",
482            self.route_id, self.service_id
483        )
484    }
485}
486
487/// A Trip is a vehicle that follows a sequence of [StopTime] on certain days. See <https://gtfs.org/reference/static/#tripstxt>
488#[derive(Clone, Debug, Default, Serialize, Deserialize)]
489pub struct Trip {
490    /// Unique technical identifier (not for the traveller) for the Trip
491    pub id: String,
492    /// References the [Calendar] on which this trip runs
493    pub service_id: String,
494    /// References along which [Route] this trip runs
495    pub route_id: String,
496    /// All the [StopTime] that define the trip
497    pub stop_times: Vec<StopTime>,
498    /// Unique technical (not for the traveller) identifier for the Shape
499    pub shape_id: Option<String>,
500    /// Text that appears on signage identifying the trip's destination to riders
501    pub trip_headsign: Option<String>,
502    /// Public facing text used to identify the trip to riders, for instance, to identify train numbers for commuter rail trips
503    pub trip_short_name: Option<String>,
504    /// 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
505    pub direction_id: Option<DirectionType>,
506    /// 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
507    pub block_id: Option<String>,
508    /// Indicates wheelchair accessibility
509    pub wheelchair_accessible: Availability,
510    /// Indicates whether bikes are allowed
511    pub bikes_allowed: BikesAllowedType,
512    /// During which periods the trip runs by frequency and not by fixed timetable
513    pub frequencies: Vec<Frequency>,
514}
515
516impl Type for Trip {
517    fn object_type(&self) -> ObjectType {
518        ObjectType::Trip
519    }
520}
521
522impl Id for Trip {
523    fn id(&self) -> &str {
524        &self.id
525    }
526}
527
528impl fmt::Display for Trip {
529    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
530        write!(
531            f,
532            "route id: {}, service id: {}",
533            self.route_id, self.service_id
534        )
535    }
536}
537
538/// General informations about the agency running the network. See <https://gtfs.org/reference/static/#agencytxt>
539#[derive(Clone, Debug, Serialize, Deserialize, Default)]
540pub struct Agency {
541    /// Unique technical (not for the traveller) identifier for the Agency
542    #[serde(rename = "agency_id")]
543    pub id: Option<String>,
544    ///Full name of the transit agency
545    #[serde(rename = "agency_name")]
546    pub name: String,
547    /// Full url of the transit agency.
548    #[serde(rename = "agency_url")]
549    pub url: String,
550    /// Timezone where the transit agency is located
551    #[serde(rename = "agency_timezone")]
552    pub timezone: String,
553    /// Primary language used by this transit agency
554    #[serde(rename = "agency_lang")]
555    pub lang: Option<String>,
556    /// A voice telephone number for the specified agency
557    #[serde(rename = "agency_phone")]
558    pub phone: Option<String>,
559    /// URL of a web page that allows a rider to purchase tickets or other fare instruments for that agency online
560    #[serde(rename = "agency_fare_url")]
561    pub fare_url: Option<String>,
562    /// Email address actively monitored by the agency’s customer service department
563    #[serde(rename = "agency_email")]
564    pub email: Option<String>,
565    /// This field is not part of the main GTFS specification, it is part of the Google Transit Ticketing extension
566    /// Trip ID to pass to a ticket shop
567    pub ticketing_deep_link_id: Option<String>,
568}
569
570impl Type for Agency {
571    fn object_type(&self) -> ObjectType {
572        ObjectType::Agency
573    }
574}
575
576impl Id for Agency {
577    fn id(&self) -> &str {
578        match &self.id {
579            None => "",
580            Some(id) => id,
581        }
582    }
583}
584
585impl fmt::Display for Agency {
586    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
587        write!(f, "{}", self.name)
588    }
589}
590
591/// A single geographical point decribing the shape of a [Trip]. See <https://gtfs.org/reference/static/#shapestxt>
592#[derive(Clone, Debug, Serialize, Deserialize, Default)]
593pub struct Shape {
594    /// Unique technical (not for the traveller) identifier for the Shape
595    #[serde(rename = "shape_id")]
596    pub id: String,
597    #[serde(rename = "shape_pt_lat", default)]
598    /// Latitude of a shape point
599    pub latitude: f64,
600    /// Longitude of a shape point
601    #[serde(rename = "shape_pt_lon", default)]
602    pub longitude: f64,
603    /// Sequence in which the shape points connect to form the shape. Values increase along the trip but do not need to be consecutive.
604    #[serde(rename = "shape_pt_sequence")]
605    pub sequence: usize,
606    /// 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
607    #[serde(rename = "shape_dist_traveled")]
608    pub dist_traveled: Option<f32>,
609}
610
611impl Type for Shape {
612    fn object_type(&self) -> ObjectType {
613        ObjectType::Shape
614    }
615}
616
617impl Id for Shape {
618    fn id(&self) -> &str {
619        &self.id
620    }
621}
622
623/// Defines one possible fare. See <https://gtfs.org/reference/static/#fare_attributestxt>
624#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
625pub struct FareAttribute {
626    /// Unique technical (not for the traveller) identifier for the FareAttribute
627    #[serde(rename = "fare_id")]
628    pub id: String,
629    /// Fare price, in the unit specified by [FareAttribute::currency]
630    pub price: String,
631    /// Currency used to pay the fare.
632    #[serde(rename = "currency_type")]
633    pub currency: String,
634    ///Indicates when the fare must be paid
635    pub payment_method: PaymentMethod,
636    /// Indicates the number of transfers permitted on this fare
637    pub transfers: Transfers,
638    /// Identifies the relevant agency for a fare
639    pub agency_id: Option<String>,
640    /// Length of time in seconds before a transfer expires
641    pub transfer_duration: Option<usize>,
642}
643
644impl Id for FareAttribute {
645    fn id(&self) -> &str {
646        &self.id
647    }
648}
649
650impl Type for FareAttribute {
651    fn object_type(&self) -> ObjectType {
652        ObjectType::Fare
653    }
654}
655
656/// Used to describe the range of fares available for purchase by riders or taken into account
657/// when computing the total fare for journeys with multiple legs, such as transfer costs.
658/// https://gtfs.org/documentation/schedule/reference/#fare_productstxt
659#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
660pub struct FareProduct {
661    /// Identifies a fare product or set of fare products.
662    #[serde(rename = "fare_product_id")]
663    pub id: String,
664    /// The name of the fare product as displayed to riders.
665    #[serde(rename = "fare_product_name")]
666    pub name: Option<String>,
667    /// Identifies a rider category eligible for the fare product.
668    pub rider_category_id: Option<String>,
669    /// Identifies a fare media that can be employed to use the fare product during the trip.
670    pub fare_media_id: Option<String>,
671    /// The cost of the fare product. May be negative to represent transfer discounts. May be zero to represent a fare product that is free.
672    pub amount: String,
673    /// The currency of the cost of the fare product.
674    pub currency: String,
675}
676
677impl Id for FareProduct {
678    fn id(&self) -> &str {
679        &self.id
680    }
681}
682
683impl Type for FareProduct {
684    fn object_type(&self) -> ObjectType {
685        ObjectType::Fare
686    }
687}
688
689/// To describe the different fare media that can be employed to use fare products.
690/// Fare media are physical or virtual holders used for the representation and/or validation of a fare product.
691/// https://gtfs.org/documentation/schedule/reference/#fare_mediatxt
692#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
693pub struct FareMedia {
694    /// Identifies a fare media.
695    #[serde(rename = "fare_media_id")]
696    pub id: String,
697    /// The name of the fare media.
698    #[serde(rename = "fare_media_name")]
699    pub name: Option<String>,
700    /// The type of fare media
701    #[serde(rename = "fare_media_type")]
702    pub media_type: FareMediaType,
703}
704
705impl Id for FareMedia {
706    fn id(&self) -> &str {
707        &self.id
708    }
709}
710
711impl Type for FareMedia {
712    fn object_type(&self) -> ObjectType {
713        ObjectType::Fare
714    }
715}
716
717/// Defines categories of riders (e.g. elderly, student).
718/// https://gtfs.org/documentation/schedule/reference/#rider_categoriestxt
719#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
720pub struct RiderCategory {
721    /// Identifies a rider category.
722    #[serde(rename = "rider_category_id")]
723    pub id: String,
724    /// Rider category name as displayed to the rider.
725    #[serde(rename = "rider_category_name")]
726    pub name: String,
727    /// is_default_fare_category
728    pub is_default_fare_category: DefaultFareCategory,
729    /// URL of a web page, usually from the operating agency, that provides
730    /// detailed information about a specific rider category and/or describes its eligibility criteria.
731    pub eligibility_url: Option<String>,
732}
733
734impl Id for RiderCategory {
735    fn id(&self) -> &str {
736        &self.id
737    }
738}
739
740impl Type for RiderCategory {
741    fn object_type(&self) -> ObjectType {
742        ObjectType::Fare
743    }
744}
745
746/// Defines one possible fare. See <https://gtfs.org/schedule/reference/#fare_rulestxt>
747#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
748pub struct FareRule {
749    /// ID of the referenced FareAttribute.
750    pub fare_id: String,
751    /// ID of a [Route] associated with the fare class
752    pub route_id: Option<String>,
753    /// Identifies an origin zone. References a [Stop].zone_id
754    pub origin_id: Option<String>,
755    /// Identifies an destination zone. References a [Stop].zone_id
756    pub destination_id: Option<String>,
757    /// Identifies the zones that a rider will enter while using a given fare class. References a [Stop].zone_id
758    pub contains_id: Option<String>,
759}
760
761/// A [Frequency] before being merged into the corresponding [Trip]
762#[derive(Clone, Debug, Serialize, Deserialize, Default)]
763pub struct RawFrequency {
764    /// References the [Trip] that uses frequency
765    pub trip_id: String,
766    /// Time at which the first vehicle departs from the first stop of the trip
767    #[serde(
768        deserialize_with = "deserialize_time",
769        serialize_with = "serialize_time"
770    )]
771    pub start_time: u32,
772    /// Time at which service changes to a different headway (or ceases) at the first stop in the trip
773    #[serde(
774        deserialize_with = "deserialize_time",
775        serialize_with = "serialize_time"
776    )]
777    pub end_time: u32,
778    /// Time, in seconds, between departures from the same stop (headway) for the trip, during the time interval specified by start_time and end_time
779    pub headway_secs: u32,
780    /// Indicates the type of service for a trip
781    pub exact_times: Option<ExactTimes>,
782}
783
784/// Timetables can be defined by the frequency of their vehicles. See <<https://gtfs.org/reference/static/#frequenciestxt>>
785#[derive(Clone, Debug, Default, Deserialize, Serialize)]
786pub struct Frequency {
787    /// Time at which the first vehicle departs from the first stop of the trip
788    pub start_time: u32,
789    /// Time at which service changes to a different headway (or ceases) at the first stop in the trip
790    pub end_time: u32,
791    /// Time, in seconds, between departures from the same stop (headway) for the trip, during the time interval specified by start_time and end_time
792    pub headway_secs: u32,
793    /// Indicates the type of service for a trip
794    pub exact_times: Option<ExactTimes>,
795}
796
797impl Frequency {
798    /// Converts from a [RawFrequency] to a [Frequency]
799    pub fn from(frequency: &RawFrequency) -> Self {
800        Self {
801            start_time: frequency.start_time,
802            end_time: frequency.end_time,
803            headway_secs: frequency.headway_secs,
804            exact_times: frequency.exact_times,
805        }
806    }
807}
808
809/// Transfer information between stops before merged into [Stop]
810#[derive(Clone, Debug, Serialize, Deserialize, Default)]
811pub struct RawTransfer {
812    /// Stop from which to leave
813    pub from_stop_id: String,
814    /// Stop which to transfer to
815    pub to_stop_id: String,
816    /// Type of the transfer
817    pub transfer_type: TransferType,
818    /// Minimum time needed to make the transfer in seconds
819    pub min_transfer_time: Option<u32>,
820}
821
822#[derive(Clone, Debug, Default, Deserialize, Serialize)]
823/// Transfer information between stops
824pub struct StopTransfer {
825    /// Stop which to transfer to
826    pub to_stop_id: String,
827    /// Type of the transfer
828    pub transfer_type: TransferType,
829    /// Minimum time needed to make the transfer in seconds
830    pub min_transfer_time: Option<u32>,
831}
832
833impl From<RawTransfer> for StopTransfer {
834    /// Converts from a [RawTransfer] to a [StopTransfer]
835    fn from(transfer: RawTransfer) -> Self {
836        Self {
837            to_stop_id: transfer.to_stop_id,
838            transfer_type: transfer.transfer_type,
839            min_transfer_time: transfer.min_transfer_time,
840        }
841    }
842}
843
844/// Meta-data about the feed. See <https://gtfs.org/reference/static/#feed_infotxt>
845#[derive(Clone, Debug, Serialize, Deserialize, Default)]
846pub struct FeedInfo {
847    /// Full name of the organization that publishes the dataset.
848    #[serde(rename = "feed_publisher_name")]
849    pub name: String,
850    /// URL of the dataset publishing organization's website
851    #[serde(rename = "feed_publisher_url")]
852    pub url: String,
853    /// Default language used for the text in this dataset
854    #[serde(rename = "feed_lang")]
855    pub lang: String,
856    /// Defines the language that should be used when the data consumer doesn’t know the language of the rider
857    pub default_lang: Option<String>,
858    /// The dataset provides complete and reliable schedule information for service in the period from this date
859    #[serde(
860        deserialize_with = "deserialize_option_date",
861        serialize_with = "serialize_option_date",
862        rename = "feed_start_date",
863        default
864    )]
865    pub start_date: Option<NaiveDate>,
866    ///The dataset provides complete and reliable schedule information for service in the period until this date
867    #[serde(
868        deserialize_with = "deserialize_option_date",
869        serialize_with = "serialize_option_date",
870        rename = "feed_end_date",
871        default
872    )]
873    pub end_date: Option<NaiveDate>,
874    /// String that indicates the current version of their GTFS dataset
875    #[serde(rename = "feed_version")]
876    pub version: Option<String>,
877    /// Email address for communication regarding the GTFS dataset and data publishing practices
878    #[serde(rename = "feed_contact_email")]
879    pub contact_email: Option<String>,
880    /// URL for contact information, a web-form, support desk, or other tools for communication regarding the GTFS dataset and data publishing practices
881    #[serde(rename = "feed_contact_url")]
882    pub contact_url: Option<String>,
883}
884
885impl fmt::Display for FeedInfo {
886    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
887        write!(f, "{}", self.name)
888    }
889}
890
891/// A graph representation to describe subway or train, with nodes (the locations) and edges (the pathways).
892#[derive(Clone, Debug, Serialize, Deserialize, Default)]
893pub struct RawPathway {
894    /// Uniquely identifies the pathway
895    #[serde(rename = "pathway_id")]
896    pub id: String,
897    /// Location at which the pathway begins
898    pub from_stop_id: String,
899    /// Location at which the pathway ends
900    pub to_stop_id: String,
901    /// Type of pathway between the specified (from_stop_id, to_stop_id) pair
902    #[serde(rename = "pathway_mode")]
903    pub mode: PathwayMode,
904    /// Indicates in which direction the pathway can be used
905    pub is_bidirectional: PathwayDirectionType,
906    /// Horizontal length in meters of the pathway from the origin location to the destination location
907    pub length: Option<f32>,
908    /// Average time in seconds needed to walk through the pathway from the origin location to the destination location
909    pub traversal_time: Option<u32>,
910    /// Number of stairs of the pathway
911    pub stair_count: Option<i32>,
912    /// Maximum slope ratio of the pathway
913    pub max_slope: Option<f32>,
914    /// Minimum width of the pathway in meters
915    pub min_width: Option<f32>,
916    /// String of text from physical signage visible to transit riders
917    pub signposted_as: Option<String>,
918    /// Same than the signposted_as field, but when the pathways is used backward
919    pub reversed_signposted_as: Option<String>,
920}
921
922impl Id for RawPathway {
923    fn id(&self) -> &str {
924        &self.id
925    }
926}
927
928/// This object is not part of the main GTFS specification, it is part of the Google Transit Ticketing extension
929/// A mapping of the GTFS-identifiers to the ticket shop identifiers
930#[derive(Clone, Debug, Serialize, Deserialize, Default)]
931pub struct TicketingIdentifier {
932    /// Stop ID used by the ticket shop
933    pub ticketing_stop_id: String,
934    /// GTFS-side stop id
935    pub stop_id: String,
936    /// GTFS-side agency id
937    pub agency_id: String,
938}
939
940/// This object is not part of the main GTFS specification, it is part of the Google Transit Ticketing extension
941/// The base url to a ticket shop without the trip specific parameters
942#[derive(Clone, Debug, Serialize, Deserialize, Default)]
943pub struct TicketingDeepLink {
944    /// Unique identifier for this base link
945    pub ticketing_deep_link_id: String,
946    /// URL to be used for buying a ticket on the web
947    pub web_url: Option<String>,
948    /// URI to be used for buying a ticket in an android app
949    pub android_intent_url: Option<String>,
950    /// URL used to use on iOS
951    pub ios_universal_link_url: Option<String>,
952}
953
954impl Type for RawPathway {
955    fn object_type(&self) -> ObjectType {
956        ObjectType::Pathway
957    }
958}
959
960/// Pathway going from a stop to another.
961#[derive(Debug, Clone, Default, Serialize, Deserialize)]
962pub struct Pathway {
963    /// Uniquely identifies the pathway
964    pub id: String,
965    /// Location at which the pathway ends
966    pub to_stop_id: String,
967    /// Type of pathway between the specified (from_stop_id, to_stop_id) pair
968    pub mode: PathwayMode,
969    /// Indicates in which direction the pathway can be used
970    pub is_bidirectional: PathwayDirectionType,
971    /// Horizontal length in meters of the pathway from the origin location to the destination location
972    pub length: Option<f32>,
973    /// Average time in seconds needed to walk through the pathway from the origin location to the destination location
974    pub traversal_time: Option<u32>,
975    /// Number of stairs of the pathway
976    pub stair_count: Option<i32>,
977    /// Maximum slope ratio of the pathway
978    pub max_slope: Option<f32>,
979    /// Minimum width of the pathway in meters
980    pub min_width: Option<f32>,
981    /// String of text from physical signage visible to transit riders
982    pub signposted_as: Option<String>,
983    /// Same than the signposted_as field, but when the pathways is used backward
984    pub reversed_signposted_as: Option<String>,
985}
986
987impl Id for Pathway {
988    fn id(&self) -> &str {
989        &self.id
990    }
991}
992
993impl Type for Pathway {
994    fn object_type(&self) -> ObjectType {
995        ObjectType::Pathway
996    }
997}
998
999impl From<RawPathway> for Pathway {
1000    /// Converts from a [RawPathway] to a [Pathway]
1001    fn from(raw: RawPathway) -> Self {
1002        Self {
1003            id: raw.id,
1004            to_stop_id: raw.to_stop_id,
1005            mode: raw.mode,
1006            is_bidirectional: raw.is_bidirectional,
1007            length: raw.length,
1008            max_slope: raw.max_slope,
1009            min_width: raw.min_width,
1010            reversed_signposted_as: raw.reversed_signposted_as,
1011            signposted_as: raw.signposted_as,
1012            stair_count: raw.stair_count,
1013            traversal_time: raw.traversal_time,
1014        }
1015    }
1016}
1017
1018/// Format of the data
1019#[derive(Clone, Debug, Serialize, PartialEq)]
1020pub enum SourceFormat {
1021    /// `Directory` means the data comes from a directory
1022    Directory,
1023    /// `Zip` means the data were read from a zip
1024    Zip,
1025}