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}