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}