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