Skip to main content

gtfs_structures/
objects.rs

1pub use crate::enums::*;
2use crate::serde_helpers::*;
3use jiff::civil::{Date, 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: Date,
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: Date,
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: Date) -> bool {
119        match date.weekday() {
120            Weekday::Monday => self.monday,
121            Weekday::Tuesday => self.tuesday,
122            Weekday::Wednesday => self.wednesday,
123            Weekday::Thursday => self.thursday,
124            Weekday::Friday => self.friday,
125            Weekday::Saturday => self.saturday,
126            Weekday::Sunday => 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: Date,
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::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::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    /// Background of [Route::text_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    /// Indicates whether cars can be transported
456    #[serde(default)]
457    pub cars_allowed: CarsAllowedType,
458    /// This field is not part of the main GTFS specification, it is part of the Google Transit Ticketing extension
459    /// Trip ID to pass to a ticket shop
460    #[serde(default)]
461    pub ticketing_trip_id: Option<String>,
462    /// This field is not part of the main GTFS specification, it is part of the Google Transit Ticketing extension
463    /// Enable or disable buying tickets via a deep link
464    #[serde(default)]
465    pub ticketing_type: TicketingType,
466}
467
468impl Type for RawTrip {
469    fn object_type(&self) -> ObjectType {
470        ObjectType::Trip
471    }
472}
473
474impl Id for RawTrip {
475    fn id(&self) -> &str {
476        &self.id
477    }
478}
479
480impl fmt::Display for RawTrip {
481    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
482        write!(
483            f,
484            "route id: {}, service id: {}",
485            self.route_id, self.service_id
486        )
487    }
488}
489
490/// A Trip is a vehicle that follows a sequence of [StopTime] on certain days. See <https://gtfs.org/reference/static/#tripstxt>
491#[derive(Clone, Debug, Default, Serialize, Deserialize)]
492pub struct Trip {
493    /// Unique technical identifier (not for the traveller) for the Trip
494    pub id: String,
495    /// References the [Calendar] on which this trip runs
496    pub service_id: String,
497    /// References along which [Route] this trip runs
498    pub route_id: String,
499    /// All the [StopTime] that define the trip
500    pub stop_times: Vec<StopTime>,
501    /// Unique technical (not for the traveller) identifier for the Shape
502    pub shape_id: Option<String>,
503    /// Text that appears on signage identifying the trip's destination to riders
504    pub trip_headsign: Option<String>,
505    /// Public facing text used to identify the trip to riders, for instance, to identify train numbers for commuter rail trips
506    pub trip_short_name: Option<String>,
507    /// 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
508    pub direction_id: Option<DirectionType>,
509    /// 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
510    pub block_id: Option<String>,
511    /// Indicates wheelchair accessibility
512    pub wheelchair_accessible: Availability,
513    /// Indicates whether bikes are allowed
514    pub bikes_allowed: BikesAllowedType,
515    /// Indicates whether cars can be transported
516    pub cars_allowed: CarsAllowedType,
517    /// During which periods the trip runs by frequency and not by fixed timetable
518    pub frequencies: Vec<Frequency>,
519}
520
521impl Type for Trip {
522    fn object_type(&self) -> ObjectType {
523        ObjectType::Trip
524    }
525}
526
527impl Id for Trip {
528    fn id(&self) -> &str {
529        &self.id
530    }
531}
532
533impl fmt::Display for Trip {
534    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
535        write!(
536            f,
537            "route id: {}, service id: {}",
538            self.route_id, self.service_id
539        )
540    }
541}
542
543/// General informations about the agency running the network. See <https://gtfs.org/reference/static/#agencytxt>
544#[derive(Clone, Debug, Serialize, Deserialize, Default)]
545pub struct Agency {
546    /// Unique technical (not for the traveller) identifier for the Agency
547    #[serde(rename = "agency_id")]
548    pub id: Option<String>,
549    ///Full name of the transit agency
550    #[serde(rename = "agency_name")]
551    pub name: String,
552    /// Full url of the transit agency.
553    #[serde(rename = "agency_url")]
554    pub url: String,
555    /// Timezone where the transit agency is located
556    #[serde(rename = "agency_timezone")]
557    pub timezone: String,
558    /// Primary language used by this transit agency
559    #[serde(rename = "agency_lang")]
560    pub lang: Option<String>,
561    /// A voice telephone number for the specified agency
562    #[serde(rename = "agency_phone")]
563    pub phone: Option<String>,
564    /// URL of a web page that allows a rider to purchase tickets or other fare instruments for that agency online
565    #[serde(rename = "agency_fare_url")]
566    pub fare_url: Option<String>,
567    /// Email address actively monitored by the agency’s customer service department
568    #[serde(rename = "agency_email")]
569    pub email: Option<String>,
570    /// This field is not part of the main GTFS specification, it is part of the Google Transit Ticketing extension.
571    /// Trip ID to pass to a ticket shop
572    pub ticketing_deep_link_id: Option<String>,
573}
574
575impl Type for Agency {
576    fn object_type(&self) -> ObjectType {
577        ObjectType::Agency
578    }
579}
580
581impl Id for Agency {
582    fn id(&self) -> &str {
583        match &self.id {
584            None => "",
585            Some(id) => id,
586        }
587    }
588}
589
590impl fmt::Display for Agency {
591    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
592        write!(f, "{}", self.name)
593    }
594}
595
596/// A single geographical point decribing the shape of a [Trip]. See <https://gtfs.org/reference/static/#shapestxt>
597#[derive(Clone, Debug, Serialize, Deserialize, Default)]
598pub struct Shape {
599    /// Unique technical (not for the traveller) identifier for the Shape
600    #[serde(rename = "shape_id")]
601    pub id: String,
602    #[serde(rename = "shape_pt_lat", default)]
603    /// Latitude of a shape point
604    pub latitude: f64,
605    /// Longitude of a shape point
606    #[serde(rename = "shape_pt_lon", default)]
607    pub longitude: f64,
608    /// Sequence in which the shape points connect to form the shape. Values increase along the trip but do not need to be consecutive.
609    #[serde(rename = "shape_pt_sequence")]
610    pub sequence: usize,
611    /// 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
612    #[serde(rename = "shape_dist_traveled")]
613    pub dist_traveled: Option<f32>,
614}
615
616impl Type for Shape {
617    fn object_type(&self) -> ObjectType {
618        ObjectType::Shape
619    }
620}
621
622impl Id for Shape {
623    fn id(&self) -> &str {
624        &self.id
625    }
626}
627
628/// Defines one possible fare. See <https://gtfs.org/reference/static/#fare_attributestxt>
629#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
630pub struct FareAttribute {
631    /// Unique technical (not for the traveller) identifier for the FareAttribute
632    #[serde(rename = "fare_id")]
633    pub id: String,
634    /// Fare price, in the unit specified by [FareAttribute::currency]
635    pub price: String,
636    /// Currency used to pay the fare.
637    #[serde(rename = "currency_type")]
638    pub currency: String,
639    ///Indicates when the fare must be paid
640    pub payment_method: PaymentMethod,
641    /// Indicates the number of transfers permitted on this fare
642    pub transfers: Transfers,
643    /// Identifies the relevant agency for a fare
644    pub agency_id: Option<String>,
645    /// Length of time in seconds before a transfer expires
646    pub transfer_duration: Option<usize>,
647}
648
649impl Id for FareAttribute {
650    fn id(&self) -> &str {
651        &self.id
652    }
653}
654
655impl Type for FareAttribute {
656    fn object_type(&self) -> ObjectType {
657        ObjectType::Fare
658    }
659}
660
661/// Used to describe the range of fares available for purchase by riders or taken into account
662/// when computing the total fare for journeys with multiple legs, such as transfer costs.
663/// <https://gtfs.org/documentation/schedule/reference/#fare_productstxt>
664#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
665pub struct FareProduct {
666    /// Identifies a fare product or set of fare products.
667    #[serde(rename = "fare_product_id")]
668    pub id: String,
669    /// The name of the fare product as displayed to riders.
670    #[serde(rename = "fare_product_name")]
671    pub name: Option<String>,
672    /// Identifies a rider category eligible for the fare product.
673    pub rider_category_id: Option<String>,
674    /// Identifies a fare media that can be employed to use the fare product during the trip.
675    pub fare_media_id: Option<String>,
676    /// The cost of the fare product. May be negative to represent transfer discounts. May be zero to represent a fare product that is free.
677    pub amount: String,
678    /// The currency of the cost of the fare product.
679    pub currency: String,
680}
681
682impl Id for FareProduct {
683    fn id(&self) -> &str {
684        &self.id
685    }
686}
687
688impl Type for FareProduct {
689    fn object_type(&self) -> ObjectType {
690        ObjectType::Fare
691    }
692}
693
694/// To describe the different fare media that can be employed to use fare products.
695/// Fare media are physical or virtual holders used for the representation and/or validation of a fare product.
696/// <https://gtfs.org/documentation/schedule/reference/#fare_mediatxt>
697#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
698pub struct FareMedia {
699    /// Identifies a fare media.
700    #[serde(rename = "fare_media_id")]
701    pub id: String,
702    /// The name of the fare media.
703    #[serde(rename = "fare_media_name")]
704    pub name: Option<String>,
705    /// The type of fare media
706    #[serde(rename = "fare_media_type")]
707    pub media_type: FareMediaType,
708}
709
710impl Id for FareMedia {
711    fn id(&self) -> &str {
712        &self.id
713    }
714}
715
716impl Type for FareMedia {
717    fn object_type(&self) -> ObjectType {
718        ObjectType::Fare
719    }
720}
721
722/// Defines categories of riders (e.g. elderly, student).
723/// <https://gtfs.org/documentation/schedule/reference/#rider_categoriestxt>
724#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
725pub struct RiderCategory {
726    /// Identifies a rider category.
727    #[serde(rename = "rider_category_id")]
728    pub id: String,
729    /// Rider category name as displayed to the rider.
730    #[serde(rename = "rider_category_name")]
731    pub name: String,
732    /// is_default_fare_category
733    pub is_default_fare_category: DefaultFareCategory,
734    /// URL of a web page, usually from the operating agency, that provides
735    /// detailed information about a specific rider category and/or describes its eligibility criteria.
736    pub eligibility_url: Option<String>,
737}
738
739impl Id for RiderCategory {
740    fn id(&self) -> &str {
741        &self.id
742    }
743}
744
745impl Type for RiderCategory {
746    fn object_type(&self) -> ObjectType {
747        ObjectType::Fare
748    }
749}
750
751/// Defines one possible fare. See <https://gtfs.org/schedule/reference/#fare_rulestxt>
752#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
753pub struct FareRule {
754    /// ID of the referenced FareAttribute.
755    pub fare_id: String,
756    /// ID of a [Route] associated with the fare class
757    pub route_id: Option<String>,
758    /// Identifies an origin zone. References a [Stop].zone_id
759    pub origin_id: Option<String>,
760    /// Identifies an destination zone. References a [Stop].zone_id
761    pub destination_id: Option<String>,
762    /// Identifies the zones that a rider will enter while using a given fare class. References a [Stop].zone_id
763    pub contains_id: Option<String>,
764}
765
766/// A [Frequency] before being merged into the corresponding [Trip]
767#[derive(Clone, Debug, Serialize, Deserialize, Default)]
768pub struct RawFrequency {
769    /// References the [Trip] that uses frequency
770    pub trip_id: String,
771    /// Time at which the first vehicle departs from the first stop of the trip
772    #[serde(
773        deserialize_with = "deserialize_time",
774        serialize_with = "serialize_time"
775    )]
776    pub start_time: u32,
777    /// Time at which service changes to a different headway (or ceases) at the first stop in the trip
778    #[serde(
779        deserialize_with = "deserialize_time",
780        serialize_with = "serialize_time"
781    )]
782    pub end_time: u32,
783    /// Time, in seconds, between departures from the same stop (headway) for the trip, during the time interval specified by start_time and end_time
784    pub headway_secs: u32,
785    /// Indicates the type of service for a trip
786    pub exact_times: Option<ExactTimes>,
787}
788
789/// Timetables can be defined by the frequency of their vehicles. See <<https://gtfs.org/reference/static/#frequenciestxt>>
790#[derive(Clone, Debug, Default, Deserialize, Serialize)]
791pub struct Frequency {
792    /// Time at which the first vehicle departs from the first stop of the trip
793    pub start_time: u32,
794    /// Time at which service changes to a different headway (or ceases) at the first stop in the trip
795    pub end_time: u32,
796    /// Time, in seconds, between departures from the same stop (headway) for the trip, during the time interval specified by start_time and end_time
797    pub headway_secs: u32,
798    /// Indicates the type of service for a trip
799    pub exact_times: Option<ExactTimes>,
800}
801
802impl Frequency {
803    /// Converts from a [RawFrequency] to a [Frequency]
804    pub fn from(frequency: &RawFrequency) -> Self {
805        Self {
806            start_time: frequency.start_time,
807            end_time: frequency.end_time,
808            headway_secs: frequency.headway_secs,
809            exact_times: frequency.exact_times,
810        }
811    }
812}
813
814/// Transfer information between stops before merged into [Stop]
815#[derive(Clone, Debug, Serialize, Deserialize, Default)]
816pub struct RawTransfer {
817    /// Stop from which to leave
818    pub from_stop_id: String,
819    /// Stop which to transfer to
820    pub to_stop_id: String,
821    /// Type of the transfer
822    pub transfer_type: TransferType,
823    /// Minimum time needed to make the transfer in seconds
824    pub min_transfer_time: Option<u32>,
825}
826
827#[derive(Clone, Debug, Default, Deserialize, Serialize)]
828/// Transfer information between stops
829pub struct StopTransfer {
830    /// Stop which to transfer to
831    pub to_stop_id: String,
832    /// Type of the transfer
833    pub transfer_type: TransferType,
834    /// Minimum time needed to make the transfer in seconds
835    pub min_transfer_time: Option<u32>,
836}
837
838impl From<RawTransfer> for StopTransfer {
839    /// Converts from a [RawTransfer] to a [StopTransfer]
840    fn from(transfer: RawTransfer) -> Self {
841        Self {
842            to_stop_id: transfer.to_stop_id,
843            transfer_type: transfer.transfer_type,
844            min_transfer_time: transfer.min_transfer_time,
845        }
846    }
847}
848
849/// Meta-data about the feed. See <https://gtfs.org/reference/static/#feed_infotxt>
850#[derive(Clone, Debug, Serialize, Deserialize, Default)]
851pub struct FeedInfo {
852    /// Full name of the organization that publishes the dataset.
853    #[serde(rename = "feed_publisher_name")]
854    pub name: String,
855    /// URL of the dataset publishing organization's website
856    #[serde(rename = "feed_publisher_url")]
857    pub url: String,
858    /// Default language used for the text in this dataset
859    #[serde(rename = "feed_lang")]
860    pub lang: String,
861    /// Defines the language that should be used when the data consumer doesn’t know the language of the rider
862    pub default_lang: Option<String>,
863    /// The dataset provides complete and reliable schedule information for service in the period from this date
864    #[serde(
865        deserialize_with = "deserialize_option_date",
866        serialize_with = "serialize_option_date",
867        rename = "feed_start_date",
868        default
869    )]
870    pub start_date: Option<Date>,
871    ///The dataset provides complete and reliable schedule information for service in the period until this date
872    #[serde(
873        deserialize_with = "deserialize_option_date",
874        serialize_with = "serialize_option_date",
875        rename = "feed_end_date",
876        default
877    )]
878    pub end_date: Option<Date>,
879    /// String that indicates the current version of their GTFS dataset
880    #[serde(rename = "feed_version")]
881    pub version: Option<String>,
882    /// Email address for communication regarding the GTFS dataset and data publishing practices
883    #[serde(rename = "feed_contact_email")]
884    pub contact_email: Option<String>,
885    /// URL for contact information, a web-form, support desk, or other tools for communication regarding the GTFS dataset and data publishing practices
886    #[serde(rename = "feed_contact_url")]
887    pub contact_url: Option<String>,
888}
889
890impl fmt::Display for FeedInfo {
891    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
892        write!(f, "{}", self.name)
893    }
894}
895
896/// A graph representation to describe subway or train, with nodes (the locations) and edges (the pathways).
897#[derive(Clone, Debug, Serialize, Deserialize, Default)]
898pub struct RawPathway {
899    /// Uniquely identifies the pathway
900    #[serde(rename = "pathway_id")]
901    pub id: String,
902    /// Location at which the pathway begins
903    pub from_stop_id: String,
904    /// Location at which the pathway ends
905    pub to_stop_id: String,
906    /// Type of pathway between the specified (from_stop_id, to_stop_id) pair
907    #[serde(rename = "pathway_mode")]
908    pub mode: PathwayMode,
909    /// Indicates in which direction the pathway can be used
910    pub is_bidirectional: PathwayDirectionType,
911    /// Horizontal length in meters of the pathway from the origin location to the destination location
912    pub length: Option<f32>,
913    /// Average time in seconds needed to walk through the pathway from the origin location to the destination location
914    pub traversal_time: Option<u32>,
915    /// Number of stairs of the pathway
916    pub stair_count: Option<i32>,
917    /// Maximum slope ratio of the pathway
918    pub max_slope: Option<f32>,
919    /// Minimum width of the pathway in meters
920    pub min_width: Option<f32>,
921    /// String of text from physical signage visible to transit riders
922    pub signposted_as: Option<String>,
923    /// Same than the signposted_as field, but when the pathways is used backward
924    pub reversed_signposted_as: Option<String>,
925}
926
927impl Id for RawPathway {
928    fn id(&self) -> &str {
929        &self.id
930    }
931}
932
933/// This object is not part of the main GTFS specification, it is part of the Google Transit Ticketing extension.
934/// A mapping of the GTFS-identifiers to the ticket shop identifiers
935#[derive(Clone, Debug, Serialize, Deserialize, Default)]
936pub struct TicketingIdentifier {
937    /// Stop ID used by the ticket shop
938    pub ticketing_stop_id: String,
939    /// GTFS-side stop id
940    pub stop_id: String,
941    /// GTFS-side agency id
942    pub agency_id: String,
943}
944
945/// This object is not part of the main GTFS specification, it is part of the Google Transit Ticketing extension.
946/// The base url to a ticket shop without the trip specific parameters
947#[derive(Clone, Debug, Serialize, Deserialize, Default)]
948pub struct TicketingDeepLink {
949    /// Unique identifier for this base link
950    pub ticketing_deep_link_id: String,
951    /// URL to be used for buying a ticket on the web
952    pub web_url: Option<String>,
953    /// URI to be used for buying a ticket in an android app
954    pub android_intent_url: Option<String>,
955    /// URL used to use on iOS
956    pub ios_universal_link_url: Option<String>,
957}
958
959/// Attribution for a dataset
960#[derive(Clone, Debug, Serialize, Deserialize, Default)]
961pub struct Attribution {
962    /// Identifies an attribution for the dataset or a subset of it. This is mostly useful for translations.
963    pub attribution_id: Option<String>,
964    /// Agency to which the attribution applies.
965    pub agency_id: Option<String>,
966    /// Route to which the attribution applies.
967    pub route_id: Option<String>,
968    /// Trip to which the attribution applies.
969    pub trip_id: Option<String>,
970    /// Name of the organization that the dataset is attributed to.
971    pub organization_name: String,
972    #[serde(
973        deserialize_with = "deserialize_bool",
974        serialize_with = "serialize_bool"
975    )]
976    #[serde(default)]
977    /// Whether the organization is the producer
978    pub is_producer: bool,
979    #[serde(
980        deserialize_with = "deserialize_bool",
981        serialize_with = "serialize_bool"
982    )]
983    #[serde(default)]
984    /// Whether the organization is the operator
985    pub is_operator: bool,
986    #[serde(
987        deserialize_with = "deserialize_bool",
988        serialize_with = "serialize_bool"
989    )]
990    #[serde(default)]
991    /// Whether the organization is a transport authority
992    pub is_authority: bool,
993    /// URL of the organization.
994    pub attribution_url: Option<String>,
995    /// Email of the organization.
996    pub attribution_email: Option<String>,
997    /// Phone number of the organization.
998    pub attribution_phone: Option<String>,
999}
1000
1001impl Type for RawPathway {
1002    fn object_type(&self) -> ObjectType {
1003        ObjectType::Pathway
1004    }
1005}
1006
1007/// Describes a level in a station. See <https://gtfs.org/reference/static/#levelstxt>
1008#[derive(Clone, Debug, Serialize, Deserialize, Default)]
1009pub struct Level {
1010    /// Uniquely identifies the level when a station has multiple levels
1011    #[serde(rename = "level_id")]
1012    pub id: String,
1013    /// Numeric index of the level that indicates its relative position
1014    #[serde(rename = "level_index")]
1015    pub level_index: f32,
1016    /// Optional name of the level
1017    #[serde(rename = "level_name")]
1018    pub level_name: Option<String>,
1019}
1020
1021impl Id for Level {
1022    fn id(&self) -> &str {
1023        &self.id
1024    }
1025}
1026
1027impl Type for Level {
1028    fn object_type(&self) -> ObjectType {
1029        ObjectType::Level
1030    }
1031}
1032
1033/// Pathway going from a stop to another.
1034#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1035pub struct Pathway {
1036    /// Uniquely identifies the pathway
1037    pub id: String,
1038    /// the stop_id of the origin of the pathway
1039    pub from_stop_id: String,
1040    /// Location at which the pathway ends
1041    pub to_stop_id: String,
1042    /// Type of pathway between the specified (from_stop_id, to_stop_id) pair
1043    pub mode: PathwayMode,
1044    /// Indicates in which direction the pathway can be used
1045    pub is_bidirectional: PathwayDirectionType,
1046    /// Horizontal length in meters of the pathway from the origin location to the destination location
1047    pub length: Option<f32>,
1048    /// Average time in seconds needed to walk through the pathway from the origin location to the destination location
1049    pub traversal_time: Option<u32>,
1050    /// Number of stairs of the pathway
1051    pub stair_count: Option<i32>,
1052    /// Maximum slope ratio of the pathway
1053    pub max_slope: Option<f32>,
1054    /// Minimum width of the pathway in meters
1055    pub min_width: Option<f32>,
1056    /// String of text from physical signage visible to transit riders
1057    pub signposted_as: Option<String>,
1058    /// Same than the signposted_as field, but when the pathways is used backward
1059    pub reversed_signposted_as: Option<String>,
1060}
1061
1062impl Id for Pathway {
1063    fn id(&self) -> &str {
1064        &self.id
1065    }
1066}
1067
1068impl Type for Pathway {
1069    fn object_type(&self) -> ObjectType {
1070        ObjectType::Pathway
1071    }
1072}
1073
1074impl From<RawPathway> for Pathway {
1075    /// Converts from a [RawPathway] to a [Pathway]
1076    fn from(raw: RawPathway) -> Self {
1077        Self {
1078            id: raw.id,
1079            from_stop_id: raw.from_stop_id,
1080            to_stop_id: raw.to_stop_id,
1081            mode: raw.mode,
1082            is_bidirectional: raw.is_bidirectional,
1083            length: raw.length,
1084            max_slope: raw.max_slope,
1085            min_width: raw.min_width,
1086            reversed_signposted_as: raw.reversed_signposted_as,
1087            signposted_as: raw.signposted_as,
1088            stair_count: raw.stair_count,
1089            traversal_time: raw.traversal_time,
1090        }
1091    }
1092}
1093
1094/// Format of the data
1095#[derive(Clone, Debug, Serialize, PartialEq)]
1096pub enum SourceFormat {
1097    /// `Directory` means the data comes from a directory
1098    Directory,
1099    /// `Zip` means the data were read from a zip
1100    Zip,
1101}
1102
1103/// Licenses that apply to the feed or to specific files
1104#[derive(Debug, Clone, Default, Deserialize, Serialize)]
1105pub struct License {
1106    /// Defines the table which the license applies to
1107    pub licensed_table_name: Option<String>,
1108    /// The SPDX identifier of the license
1109    #[serde(rename = "license_spdx_id")]
1110    pub spdx_id: Option<String>,
1111    /// The URL that contains the terms of the custom license
1112    pub custom_license_url: Option<String>,
1113}