Skip to main content

gtfs_structures/
enums.rs

1use serde::de::{Deserialize, Deserializer};
2use serde::ser::{Serialize, Serializer};
3
4/// All the objects type from the GTFS specification that this library reads
5#[derive(Debug, Serialize, Eq, PartialEq, Hash)]
6pub enum ObjectType {
7    /// [Agency] <https://gtfs.org/reference/static/#agencytxt>
8    Agency,
9    /// [Stop] <https://gtfs.org/reference/static/#stopstxt>
10    Stop,
11    /// [Route] <https://gtfs.org/reference/static/#routestxt>
12    Route,
13    /// [Trip] <https://gtfs.org/reference/static/#tripstxt>
14    Trip,
15    /// [Calendar] <https://gtfs.org/reference/static/#calendartxt>
16    Calendar,
17    /// [Shape] <https://gtfs.org/reference/static/#shapestxt>
18    Shape,
19    /// [FareAttribute] <https://gtfs.org/reference/static/#fare_rulestxt>
20    Fare,
21    /// [Pathway] <https://gtfs.org/schedule/reference/#pathwaystxt>
22    Pathway,
23}
24
25/// Describes the kind of [Stop]. See <https://gtfs.org/reference/static/#stopstxt> `location_type`
26#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
27pub enum LocationType {
28    /// Stop (or Platform). A location where passengers board or disembark from a transit vehicle. Is called a platform when defined within a parent_station
29    #[default]
30    StopPoint,
31    /// Station. A physical structure or area that contains one or more platform
32    StopArea,
33    /// A location where passengers can enter or exit a station from the street. If an entrance/exit belongs to multiple stations, it can be linked by pathways to both, but the data provider must pick one of them as parent
34    StationEntrance,
35    /// A location within a station, not matching any other [Stop::location_type], which can be used to link together pathways define in pathways.txt.
36    GenericNode,
37    /// A specific location on a platform, where passengers can board and/or alight vehicles
38    BoardingArea,
39    /// An unknown value
40    Unknown(i16),
41}
42
43fn serialize_i16_as_str<S: Serializer>(s: S, value: i16) -> Result<S::Ok, S::Error> {
44    s.serialize_str(&value.to_string())
45}
46impl<'de> Deserialize<'de> for LocationType {
47    fn deserialize<D>(deserializer: D) -> Result<LocationType, D::Error>
48    where
49        D: Deserializer<'de>,
50    {
51        let s = <&str>::deserialize(deserializer)?;
52        Ok(match s {
53            "" | "0" => LocationType::StopPoint,
54            "1" => LocationType::StopArea,
55            "2" => LocationType::StationEntrance,
56            "3" => LocationType::GenericNode,
57            "4" => LocationType::BoardingArea,
58            s => LocationType::Unknown(s.parse().map_err(|_| {
59                serde::de::Error::custom(format!(
60                    "invalid value for LocationType, must be an integer: {s}"
61                ))
62            })?),
63        })
64    }
65}
66
67impl Serialize for LocationType {
68    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
69    where
70        S: Serializer,
71    {
72        // Note: for extended route type, we might loose the initial precise route type
73        serialize_i16_as_str(
74            serializer,
75            match self {
76                LocationType::StopPoint => 0,
77                LocationType::StopArea => 1,
78                LocationType::StationEntrance => 2,
79                LocationType::GenericNode => 3,
80                LocationType::BoardingArea => 4,
81                LocationType::Unknown(i) => *i,
82            },
83        )
84    }
85}
86
87#[derive(Debug, Clone, derive_more::TryFrom, Copy, PartialEq, Eq, Hash)]
88#[repr(i16)]
89#[try_from(repr)]
90/// Google Transit extended route types [https://developers.google.com/transit/gtfs/reference/extended-route-types](https://developers.google.com/transit/gtfs/reference/extended-route-types)
91pub enum ExtendedRouteType {
92    /// Railway Service.
93    Railway = 100,
94    /// High Speed Rail Service. Examples: TGV (FR), ICE (DE), Eurostar (GB).
95    HighSpeedRail = 101,
96    /// Long Distance Trains. Examples: InterCity/EuroCity.
97    LongDistanceTrains = 102,
98    /// Inter Regional Rail Service. Examples: InterRegio (DE), Cross County Rail (GB).
99    InterRegionalRail = 103,
100    /// Car Transport Rail Service.
101    CarTransportRail = 104,
102    /// Sleeper Rail Service. Example: GNER Sleeper (GB).
103    SleeperRail = 105,
104    /// Regional Rail Service. Examples: TER (FR), Regionalzug (DE).
105    RegionalRail = 106,
106    /// Tourist Railway Service. Example: Romney, Hythe & Dymchurch (GB).
107    TouristRailway = 107,
108    /// Rail Shuttle (Within Complex). Examples: Gatwick Shuttle (GB), Sky Line (DE).
109    RailShuttleWithinComplex = 108,
110    /// Suburban Railway. Examples: S-Bahn (DE), RER (FR), S-tog (Kopenhagen).
111    SuburbanRailway = 109,
112    /// Replacement Rail Service.
113    ReplacementRail = 110,
114    /// Special Rail Service.
115    SpecialRail = 111,
116    /// Lorry Transport Rail Service.
117    LorryTransportRail = 112,
118    /// All Rail Services.
119    OtherRail = 113,
120    /// Cross-Country Rail Service.
121    CrossCountryRail = 114,
122    /// Vehicle Transport Rail Service.
123    VehicleTransportRail = 115,
124    /// Rack and Pinion Railway. Examples: Rochers de Naye (CH), Dolderbahn (CH).
125    RackAndPinionRailway = 116,
126    /// Additional Rail Service.
127    AdditionalRail = 117,
128
129    /// Coach Service.
130    Coach = 200,
131    /// International Coach Service. Examples: EuroLine, Touring.
132    InternationalCoach = 201,
133    /// National Coach Service. Example: National Express (GB).
134    NationalCoach = 202,
135    /// Shuttle Coach Service. Examples: Roissy Bus (FR), Reading-Heathrow (GB).
136    ShuttleCoach = 203,
137    /// Regional Coach Service.
138    RegionalCoach = 204,
139    /// Special Coach Service.
140    SpecialCoach = 205,
141    /// Sightseeing Coach Service.
142    SightseeingCoach = 206,
143    /// Tourist Coach Service.
144    TouristCoach = 207,
145    /// Commuter Coach Service.
146    CommuterCoach = 208,
147    /// All Coach Services.
148    OtherCoach = 209,
149
150    /// Urban Railway Service.
151    UrbanRailway = 400,
152    /// Metro Service. Example: Métro de Paris.
153    Metro = 401,
154    /// Underground Service. Examples: London Underground, U-Bahn.
155    Underground = 402,
156    /// Urban Railway Service.
157    UrbanRailwayServiceDetail = 403,
158    /// All Urban Railway Services.
159    OtherUrbanRailway = 404,
160    /// Monorail.
161    Monorail = 405,
162
163    /// Bus Service.
164    Bus = 700,
165    /// Regional Bus Service. Example: Eastbourne-Maidstone (GB).
166    RegionalBus = 701,
167    /// Express Bus Service. Example: X19 Wokingham-Heathrow (GB).
168    ExpressBus = 702,
169    /// Stopping Bus Service. Example: 38 London: Clapton Pond-Victoria (GB).
170    StoppingBus = 703,
171    /// Local Bus Service.
172    LocalBus = 704,
173    /// Night Bus Service. Example: N prefixed buses in London (GB).
174    NightBus = 705,
175    /// Post Bus Service. Example: Maidstone P4 (GB).
176    PostBus = 706,
177    /// Special Needs Bus.
178    SpecialNeedsBus = 707,
179    /// Mobility Bus Service.
180    MobilityBus = 708,
181    /// Mobility Bus for Registered Disabled.
182    MobilityBusForRegisteredDisabled = 709,
183    /// Sightseeing Bus.
184    SightseeingBus = 710,
185    /// Shuttle Bus. Example: 747 Heathrow-Gatwick Airport Service (GB).
186    ShuttleBus = 711,
187    /// School Bus.
188    SchoolBus = 712,
189    /// School and Public Service Bus.
190    SchoolAndPublicServiceBus = 713,
191    /// Rail Replacement Bus Service.
192    RailReplacementBus = 714,
193    /// Demand and Response Bus Service.
194    DemandAndResponseBus = 715,
195    /// All Bus Services.
196    OtherBus = 716,
197
198    /// Trolleybus Service.
199    Trolleybus = 800,
200
201    /// Tram Service.
202    Tram = 900,
203    /// City Tram Service.
204    CityTram = 901,
205    /// Local Tram Service. Examples: Munich (DE), Brussels (BE), Croydon (GB).
206    LocalTram = 902,
207    /// Regional Tram Service.
208    RegionalTram = 903,
209    /// Sightseeing Tram Service. Example: Blackpool Seafront (GB).
210    SightseeingTram = 904,
211    /// Shuttle Tram Service.
212    ShuttleTram = 905,
213    /// All Tram Services.
214    OtherTram = 906,
215
216    /// Water Transport Service.
217    WaterTransport = 1000,
218    /// Air Service.
219    Air = 1100,
220    /// Ferry Service.
221    Ferry = 1200,
222
223    /// Aerial Lift Service. Examples: Telefèric de Montjuïc (ES), Saleve (CH), Roosevelt Island Tramway (US).
224    AerialLift = 1300,
225    /// Telecabin Service.
226    Telecabin = 1301,
227    /// Cable Car Service.
228    CableCar = 1302,
229    /// Elevator Service.
230    Elevator = 1303,
231    /// Chair Lift Service.
232    ChairLift = 1304,
233    /// Drag Lift Service.
234    DragLift = 1305,
235    /// Small Telecabin Service.
236    SmallTelecabin = 1306,
237    /// All Telecabin Services.
238    OtherTelecabin = 1307,
239
240    // Funicular Service
241    /// Funicular Service. Example: Rigiblick (Zürich, CH).
242    Funicular = 1400,
243
244    /// Taxi Service.
245    Taxi = 1500,
246    /// Communal Taxi Service. Examples: Marshrutka (RU), dolmuş (TR).
247    CommunalTaxi = 1501,
248    /// Water Taxi Service.
249    WaterTaxi = 1502,
250    /// Rail Taxi Service.
251    RailTaxi = 1503,
252    /// Bike Taxi Service.
253    BikeTaxi = 1504,
254    /// Licensed Taxi Service.
255    LicensedTaxi = 1505,
256    /// Private Hire Service Vehicle.
257    PrivateHireServiceVehicle = 1506,
258    /// All Taxi Services.
259    OtherTaxi = 1507,
260
261    /// Miscellaneous Service.
262    MiscellaneousService = 1700,
263    /// Horse-drawn Carriage.
264    HorseDrawnCarriage = 1702,
265}
266
267/// Describes the kind of [Route]. See <https://gtfs.org/reference/static/#routestxt> `route_type`
268///
269/// Some route types are extended GTFS (<https://developers.google.com/transit/gtfs/reference/extended-route-types)>
270#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
271pub enum RouteType {
272    /// Tram, Streetcar, Light rail. Any light rail or street level system within a metropolitan area
273    Tramway,
274    /// Subway, Metro. Any underground rail system within a metropolitan area.
275    Subway,
276    /// Used for intercity or long-distance travel
277    Rail,
278    /// Used for short- and long-distance bus routes
279    #[default]
280    Bus,
281    /// Used for short- and long-distance boat service
282    Ferry,
283    /// Used for street-level rail cars where the cable runs beneath the vehicle, e.g., cable car in San Francisco
284    CableCar,
285    /// Aerial lift, suspended cable car (e.g., gondola lift, aerial tramway). Cable transport where cabins, cars, gondolas or open chairs are suspended by means of one or more cables
286    Gondola,
287    /// Any rail system designed for steep inclines
288    Funicular,
289    /// Google Transit extended route types <https://developers.google.com/transit/gtfs/reference/extended-route-types>
290    Extended(ExtendedRouteType),
291    /// Any other value
292    Other(i16),
293}
294
295impl ExtendedRouteType {
296    /// Convert extended route types to standard route types if possible. All route types that can not be represented in standard route types at all are kept as-is.
297    /// This loses precision.
298    pub fn to_standard_route_type(&self) -> RouteType {
299        let int = *self as i16;
300        let hundreds = int / 100;
301        match hundreds {
302            1 => RouteType::Rail,
303            4 => RouteType::Subway,
304            2 | 7 | 8 => RouteType::Bus,
305            9 => RouteType::Tramway,
306            10 | 12 => RouteType::Ferry,
307            13 => RouteType::Gondola,
308            14 => RouteType::Funicular,
309            _ => RouteType::Extended(*self),
310        }
311    }
312}
313
314impl<'de> Deserialize<'de> for RouteType {
315    fn deserialize<D>(deserializer: D) -> Result<RouteType, D::Error>
316    where
317        D: Deserializer<'de>,
318    {
319        let i = i16::deserialize(deserializer)?;
320        if let Ok(ert) = ExtendedRouteType::try_from(i) {
321            return Ok(RouteType::Extended(ert));
322        }
323
324        Ok(match i {
325            0 => RouteType::Tramway,
326            1 => RouteType::Subway,
327            2 => RouteType::Rail,
328            3 => RouteType::Bus,
329            4 => RouteType::Ferry,
330            5 => RouteType::CableCar,
331            6 => RouteType::Gondola,
332            7 => RouteType::Funicular,
333            _ => RouteType::Other(i),
334        })
335    }
336}
337
338impl Serialize for RouteType {
339    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
340    where
341        S: Serializer,
342    {
343        serializer.serialize_i16(match self {
344            RouteType::Tramway => 0,
345            RouteType::Subway => 1,
346            RouteType::Rail => 2,
347            RouteType::Bus => 3,
348            RouteType::Ferry => 4,
349            RouteType::CableCar => 5,
350            RouteType::Gondola => 6,
351            RouteType::Funicular => 7,
352            RouteType::Extended(ert) => *ert as i16,
353            RouteType::Other(i) => *i,
354        })
355    }
356}
357
358/// Describes if and how a traveller can board or alight the vehicle. See <https://gtfs.org/reference/static/#stop_timestxt> `pickup_type` and `dropoff_type`
359#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
360pub enum PickupDropOffType {
361    /// Regularly scheduled pickup or drop off (default when empty).
362    #[default]
363    Regular,
364    /// No pickup or drop off available.
365    NotAvailable,
366    /// Must phone agency to arrange pickup or drop off.
367    ArrangeByPhone,
368    /// Must coordinate with driver to arrange pickup or drop off.
369    CoordinateWithDriver,
370    /// An unknown value not in the specification
371    Unknown(i16),
372}
373
374impl<'de> Deserialize<'de> for PickupDropOffType {
375    fn deserialize<D>(deserializer: D) -> Result<PickupDropOffType, D::Error>
376    where
377        D: Deserializer<'de>,
378    {
379        let s = <&str>::deserialize(deserializer)?;
380        Ok(match s {
381            "" | "0" => PickupDropOffType::Regular,
382            "1" => PickupDropOffType::NotAvailable,
383            "2" => PickupDropOffType::ArrangeByPhone,
384            "3" => PickupDropOffType::CoordinateWithDriver,
385            s => PickupDropOffType::Unknown(s.parse().map_err(|_| {
386                serde::de::Error::custom(format!(
387                    "invalid value for PickupDropOffType, must be an integer: {s}"
388                ))
389            })?),
390        })
391    }
392}
393
394impl Serialize for PickupDropOffType {
395    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
396    where
397        S: Serializer,
398    {
399        // Note: for extended route type, we might loose the initial precise route type
400        serialize_i16_as_str(
401            serializer,
402            match self {
403                PickupDropOffType::Regular => 0,
404                PickupDropOffType::NotAvailable => 1,
405                PickupDropOffType::ArrangeByPhone => 2,
406                PickupDropOffType::CoordinateWithDriver => 3,
407                PickupDropOffType::Unknown(i) => *i,
408            },
409        )
410    }
411}
412
413/// Indicates whether a rider can board the transit vehicle anywhere along the vehicle’s travel path
414///
415/// Those values are only defined on <https://developers.google.com/transit/gtfs/reference#routestxt,> not on <https://gtfs.org/reference/static/#routestxt>
416#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
417pub enum ContinuousPickupDropOff {
418    /// Continuous stopping pickup or drop off.
419    Continuous,
420    /// No continuous stopping pickup or drop off (default when empty).
421    #[default]
422    NotAvailable,
423    /// Must phone agency to arrange continuous stopping pickup or drop off.
424    ArrangeByPhone,
425    /// Must coordinate with driver to arrange continuous stopping pickup or drop off.
426    CoordinateWithDriver,
427    /// An unknown value not in the specification
428    Unknown(i16),
429}
430
431impl Serialize for ContinuousPickupDropOff {
432    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
433    where
434        S: Serializer,
435    {
436        // Note: for extended route type, we might loose the initial precise route type
437        serialize_i16_as_str(
438            serializer,
439            match self {
440                ContinuousPickupDropOff::Continuous => 0,
441                ContinuousPickupDropOff::NotAvailable => 1,
442                ContinuousPickupDropOff::ArrangeByPhone => 2,
443                ContinuousPickupDropOff::CoordinateWithDriver => 3,
444                ContinuousPickupDropOff::Unknown(i) => *i,
445            },
446        )
447    }
448}
449
450impl<'de> Deserialize<'de> for ContinuousPickupDropOff {
451    fn deserialize<D>(deserializer: D) -> Result<ContinuousPickupDropOff, D::Error>
452    where
453        D: Deserializer<'de>,
454    {
455        let s = <&str>::deserialize(deserializer)?;
456        Ok(match s {
457            "0" => ContinuousPickupDropOff::Continuous,
458            "" | "1" => ContinuousPickupDropOff::NotAvailable,
459            "2" => ContinuousPickupDropOff::ArrangeByPhone,
460            "3" => ContinuousPickupDropOff::CoordinateWithDriver,
461            s => ContinuousPickupDropOff::Unknown(s.parse().map_err(|_| {
462                serde::de::Error::custom(format!(
463                    "invalid value for ContinuousPickupDropOff, must be an integer: {s}"
464                ))
465            })?),
466        })
467    }
468}
469
470/// Describes if the stop time is exact or not. See <https://gtfs.org/reference/static/#stop_timestxt> `timepoint`
471#[derive(Debug, Default, Serialize, Copy, Clone, PartialEq, Eq, Hash)]
472pub enum TimepointType {
473    /// Times are considered approximate
474    #[serde(rename = "0")]
475    Approximate = 0,
476    /// Times are considered exact
477    #[default]
478    #[serde(rename = "1")]
479    Exact = 1,
480}
481
482impl<'de> Deserialize<'de> for TimepointType {
483    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
484    where
485        D: Deserializer<'de>,
486    {
487        let s = <&str>::deserialize(deserializer)?;
488        match s {
489            "" | "1" => Ok(Self::Exact),
490            "0" => Ok(Self::Approximate),
491            v => Err(serde::de::Error::custom(format!(
492                "invalid value for timepoint: {v}"
493            ))),
494        }
495    }
496}
497
498/// Generic enum to define if a service (like wheelchair boarding) is available
499#[derive(Debug, Default, PartialEq, Eq, Hash, Clone, Copy)]
500pub enum Availability {
501    /// No information if the service is available
502    #[default]
503    InformationNotAvailable,
504    /// The service is available
505    Available,
506    /// The service is not available
507    NotAvailable,
508    /// An unknown value not in the specification
509    Unknown(i16),
510}
511
512impl<'de> Deserialize<'de> for Availability {
513    fn deserialize<D>(deserializer: D) -> Result<Availability, D::Error>
514    where
515        D: Deserializer<'de>,
516    {
517        let s = <&str>::deserialize(deserializer)?;
518        Ok(match s {
519            "" | "0" => Availability::InformationNotAvailable,
520            "1" => Availability::Available,
521            "2" => Availability::NotAvailable,
522            s => Availability::Unknown(s.parse().map_err(|_| {
523                serde::de::Error::custom(format!(
524                    "invalid value for Availability, must be an integer: {s}"
525                ))
526            })?),
527        })
528    }
529}
530
531impl Serialize for Availability {
532    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
533    where
534        S: Serializer,
535    {
536        // Note: for extended route type, we might loose the initial precise route type
537        serialize_i16_as_str(
538            serializer,
539            match self {
540                Availability::InformationNotAvailable => 0,
541                Availability::Available => 1,
542                Availability::NotAvailable => 2,
543                Availability::Unknown(i) => *i,
544            },
545        )
546    }
547}
548
549/// Defines if a [CalendarDate] is added or deleted from a [Calendar]
550#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone, Copy)]
551pub enum Exception {
552    /// There will be a service on that day
553    #[serde(rename = "1")]
554    Added,
555    /// There won’t be a service on that day
556    #[serde(rename = "2")]
557    Deleted,
558}
559
560/// Defines the direction of a [Trip], only for display, not for routing. See <https://gtfs.org/reference/static/#tripstxt> `direction_id`
561#[derive(Debug, Deserialize, Serialize, Copy, Clone, PartialEq, Eq, Hash)]
562pub enum DirectionType {
563    /// Travel in one direction (e.g. outbound travel).
564    #[serde(rename = "0")]
565    Outbound,
566    /// Travel in the opposite direction (e.g. inbound travel).
567    #[serde(rename = "1")]
568    Inbound,
569}
570
571/// Is the [Trip] accessible with a bike. See <https://gtfs.org/reference/static/#tripstxt> `bikes_allowed`
572#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
573pub enum BikesAllowedType {
574    /// No bike information for the trip
575    #[default]
576    NoBikeInfo,
577    /// Vehicle being used on this particular trip can accommodate at least one bicycle
578    AtLeastOneBike,
579    /// No bicycles are allowed on this trip
580    NoBikesAllowed,
581    /// An unknown value not in the specification
582    Unknown(i16),
583}
584
585impl<'de> Deserialize<'de> for BikesAllowedType {
586    fn deserialize<D>(deserializer: D) -> Result<BikesAllowedType, D::Error>
587    where
588        D: Deserializer<'de>,
589    {
590        let s = <&str>::deserialize(deserializer)?;
591        Ok(match s {
592            "" | "0" => BikesAllowedType::NoBikeInfo,
593            "1" => BikesAllowedType::AtLeastOneBike,
594            "2" => BikesAllowedType::NoBikesAllowed,
595            s => BikesAllowedType::Unknown(s.parse().map_err(|_| {
596                serde::de::Error::custom(format!(
597                    "invalid value for BikeAllowedType, must be an integer: {s}"
598                ))
599            })?),
600        })
601    }
602}
603
604impl Serialize for BikesAllowedType {
605    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
606    where
607        S: Serializer,
608    {
609        // Note: for extended route type, we might loose the initial precise route type
610        serialize_i16_as_str(
611            serializer,
612            match self {
613                BikesAllowedType::NoBikeInfo => 0,
614                BikesAllowedType::AtLeastOneBike => 1,
615                BikesAllowedType::NoBikesAllowed => 2,
616                BikesAllowedType::Unknown(i) => *i,
617            },
618        )
619    }
620}
621
622/// Defines where a [FareAttribute] can be paid
623#[derive(Debug, Deserialize, Serialize, Copy, Clone, PartialEq, Eq)]
624pub enum PaymentMethod {
625    /// Fare is paid on board
626    #[serde(rename = "0")]
627    Aboard,
628    /// Fare must be paid before boarding
629    #[serde(rename = "1")]
630    PreBoarding,
631}
632
633/// Defines if the [Frequency] is exact (the vehicle runs exactly every n minutes) or not
634#[derive(Debug, Serialize, Copy, Clone, PartialEq, Eq, Hash)]
635pub enum ExactTimes {
636    /// Frequency-based trips
637    FrequencyBased = 0,
638    /// Schedule-based trips with the exact same headway throughout the day.
639    ScheduleBased = 1,
640}
641
642impl<'de> Deserialize<'de> for ExactTimes {
643    fn deserialize<D>(deserializer: D) -> Result<ExactTimes, D::Error>
644    where
645        D: Deserializer<'de>,
646    {
647        let s = <&str>::deserialize(deserializer)?;
648        Ok(match s {
649            "" | "0" => ExactTimes::FrequencyBased,
650            "1" => ExactTimes::ScheduleBased,
651            &_ => {
652                return Err(serde::de::Error::custom(format!(
653                    "Invalid value `{s}`, expected 0 or 1"
654                )));
655            }
656        })
657    }
658}
659
660/// Defines how many transfers can be done with on [FareAttribute]
661#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
662pub enum Transfers {
663    /// Unlimited transfers are permitted
664    #[default]
665    Unlimited,
666    /// No transfers permitted on this fare
667    NoTransfer,
668    /// Riders may transfer once
669    UniqueTransfer,
670    ///Riders may transfer twice
671    TwoTransfers,
672    /// Other transfer values
673    Other(i16),
674}
675
676impl<'de> Deserialize<'de> for Transfers {
677    fn deserialize<D>(deserializer: D) -> Result<Transfers, D::Error>
678    where
679        D: Deserializer<'de>,
680    {
681        let i = Option::<i16>::deserialize(deserializer)?;
682        Ok(match i {
683            Some(0) => Transfers::NoTransfer,
684            Some(1) => Transfers::UniqueTransfer,
685            Some(2) => Transfers::TwoTransfers,
686            Some(a) => Transfers::Other(a),
687            None => Transfers::default(),
688        })
689    }
690}
691
692impl Serialize for Transfers {
693    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
694    where
695        S: Serializer,
696    {
697        match self {
698            Transfers::NoTransfer => serialize_i16_as_str(serializer, 0),
699            Transfers::UniqueTransfer => serialize_i16_as_str(serializer, 1),
700            Transfers::TwoTransfers => serialize_i16_as_str(serializer, 2),
701            Transfers::Other(a) => serialize_i16_as_str(serializer, *a),
702            Transfers::Unlimited => serializer.serialize_none(),
703        }
704    }
705}
706/// Defines the type of a [StopTransfer]
707#[derive(Debug, Serialize, Default, Copy, Clone, PartialEq, Eq, Hash)]
708pub enum TransferType {
709    /// Recommended transfer point between routes
710    #[serde(rename = "0")]
711    #[default]
712    Recommended,
713    /// Departing vehicle waits for arriving one
714    #[serde(rename = "1")]
715    Timed,
716    /// Transfer requires a minimum amount of time between arrival and departure to ensure a connection.
717    #[serde(rename = "2")]
718    MinTime,
719    /// Transfer is not possible at this location
720    #[serde(rename = "3")]
721    Impossible,
722    /// Passengers can stay onboard the same vehicle to transfer from one trip to another
723    #[serde(rename = "4")]
724    StayOnBoard,
725    /// In-seat transfers aren't allowed between sequential trips.
726    /// The passenger must alight from the vehicle and re-board.
727    #[serde(rename = "5")]
728    MustAlight,
729}
730
731impl<'de> Deserialize<'de> for TransferType {
732    fn deserialize<D>(deserializer: D) -> Result<TransferType, D::Error>
733    where
734        D: Deserializer<'de>,
735    {
736        let s = <&str>::deserialize(deserializer)?;
737        Ok(match s {
738            "" | "0" => TransferType::Recommended,
739            "1" => TransferType::Timed,
740            "2" => TransferType::MinTime,
741            "3" => TransferType::Impossible,
742            "4" => TransferType::StayOnBoard,
743            "5" => TransferType::MustAlight,
744            s => {
745                return Err(serde::de::Error::custom(format!(
746                    "Invalid value `{s}`, expected 0, 1, 2, 3, 4, 5"
747                )));
748            }
749        })
750    }
751}
752
753/// Type of pathway between [from_stop] and [to_stop]
754#[derive(Debug, Serialize, Deserialize, Default, Copy, Clone, PartialEq, Eq, Hash)]
755pub enum PathwayMode {
756    /// A walkway
757    #[serde(rename = "1")]
758    #[default]
759    Walkway,
760    /// Stairs
761    #[serde(rename = "2")]
762    Stairs,
763    /// Moving sidewalk / travelator
764    #[serde(rename = "3")]
765    MovingSidewalk,
766    /// Escalator
767    #[serde(rename = "4")]
768    Escalator,
769    /// Elevator
770    #[serde(rename = "5")]
771    Elevator,
772    /// A pathway that crosses into an area of the station where a
773    /// proof of payment is required (usually via a physical payment gate)
774    #[serde(rename = "6")]
775    FareGate,
776    /// Indicates a pathway exiting an area where proof-of-payment is required
777    /// into an area where proof-of-payment is no longer required.
778    #[serde(rename = "7")]
779    ExitGate,
780}
781
782/// Indicates in which direction the pathway can be used
783#[derive(Debug, Serialize, Deserialize, Default, Copy, Clone, PartialEq, Eq, Hash)]
784pub enum PathwayDirectionType {
785    /// Unidirectional pathway, it can only be used from [from_stop_id] to [to_stop_id].
786    #[serde(rename = "0")]
787    #[default]
788    Unidirectional,
789    /// Bidirectional pathway, it can be used in the two directions.
790    #[serde(rename = "1")]
791    Bidirectional,
792}
793
794/// Defines the type of a [FareMedia]
795#[derive(Debug, Deserialize, Serialize, Copy, Clone, PartialEq, Eq)]
796pub enum FareMediaType {
797    /// Used when there is no fare media involved in purchasing or validating a fare product
798    #[serde(rename = "0")]
799    None,
800    /// Physical paper ticket
801    #[serde(rename = "1")]
802    PhysicalPaperTicket,
803    /// Physical transit card
804    #[serde(rename = "2")]
805    PhysicalTransitCard,
806    /// cEMV (contactless Europay, Mastercard and Visa)
807    #[serde(rename = "3")]
808    CEmv,
809    /// Mobile app
810    #[serde(rename = "4")]
811    MobileApp,
812}
813
814/// Specifies if an entry in rider_categories.txt should be considered the default category
815#[derive(Debug, Serialize, Copy, Clone, PartialEq, Eq, Hash)]
816pub enum DefaultFareCategory {
817    /// Category is not considered the default.
818    NotDefault = 0,
819    /// Category is considered the default one.
820    Default = 1,
821}
822
823impl<'de> Deserialize<'de> for DefaultFareCategory {
824    fn deserialize<D>(deserializer: D) -> Result<DefaultFareCategory, D::Error>
825    where
826        D: Deserializer<'de>,
827    {
828        let s = <&str>::deserialize(deserializer)?;
829        Ok(match s {
830            "" | "0" => DefaultFareCategory::NotDefault,
831            "1" => DefaultFareCategory::Default,
832            &_ => {
833                return Err(serde::de::Error::custom(format!(
834                    "Invalid value `{s}`, expected 0 or 1"
835                )));
836            }
837        })
838    }
839}
840
841/// Specifies whether tickets can be bought for this item
842#[derive(Debug, Default, Deserialize, Serialize, Copy, Clone, PartialEq, Eq)]
843pub enum TicketingType {
844    /// If a ticketing_deep_link_id is set, tickets are available
845    #[default]
846    #[serde(rename = "0")]
847    Available,
848    /// Tickets are unavailable
849    #[serde(rename = "1")]
850    Unavailable,
851}