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(Derivative, Debug, Copy, Clone, PartialEq, Eq, Hash)]
27#[derivative(Default(bound = ""))]
28pub enum LocationType {
29    /// Stop (or Platform). A location where passengers board or disembark from a transit vehicle. Is called a platform when defined within a parent_station
30    #[derivative(Default)]
31    StopPoint,
32    /// Station. A physical structure or area that contains one or more platform
33    StopArea,
34    /// 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
35    StationEntrance,
36    /// A location within a station, not matching any other [Stop::location_type], which can be used to link together pathways define in pathways.txt.
37    GenericNode,
38    /// A specific location on a platform, where passengers can board and/or alight vehicles
39    BoardingArea,
40    /// An unknown value
41    Unknown(i16),
42}
43
44fn serialize_i16_as_str<S: Serializer>(s: S, value: i16) -> Result<S::Ok, S::Error> {
45    s.serialize_str(&value.to_string())
46}
47impl<'de> Deserialize<'de> for LocationType {
48    fn deserialize<D>(deserializer: D) -> Result<LocationType, D::Error>
49    where
50        D: Deserializer<'de>,
51    {
52        let s = <&str>::deserialize(deserializer)?;
53        Ok(match s {
54            "" | "0" => LocationType::StopPoint,
55            "1" => LocationType::StopArea,
56            "2" => LocationType::StationEntrance,
57            "3" => LocationType::GenericNode,
58            "4" => LocationType::BoardingArea,
59            s => LocationType::Unknown(s.parse().map_err(|_| {
60                serde::de::Error::custom(format!(
61                    "invalid value for LocationType, must be an integer: {s}"
62                ))
63            })?),
64        })
65    }
66}
67
68impl Serialize for LocationType {
69    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
70    where
71        S: Serializer,
72    {
73        // Note: for extended route type, we might loose the initial precise route type
74        serialize_i16_as_str(
75            serializer,
76            match self {
77                LocationType::StopPoint => 0,
78                LocationType::StopArea => 1,
79                LocationType::StationEntrance => 2,
80                LocationType::GenericNode => 3,
81                LocationType::BoardingArea => 4,
82                LocationType::Unknown(i) => *i,
83            },
84        )
85    }
86}
87
88/// Describes the kind of [Route]. See <https://gtfs.org/reference/static/#routestxt> `route_type`
89///
90/// -ome route types are extended GTFS (<https://developers.google.com/transit/gtfs/reference/extended-route-types)>
91#[derive(Debug, Derivative, Copy, Clone, PartialEq, Eq, Hash)]
92#[derivative(Default(bound = ""))]
93pub enum RouteType {
94    /// Tram, Streetcar, Light rail. Any light rail or street level system within a metropolitan area
95    Tramway,
96    /// Tram, Streetcar, Light rail. Any light rail or street level system within a metropolitan area
97    Subway,
98    /// Used for intercity or long-distance travel
99    Rail,
100    /// Used for short- and long-distance bus routes
101    #[derivative(Default)]
102    Bus,
103    /// Used for short- and long-distance boat service
104    Ferry,
105    /// Used for street-level rail cars where the cable runs beneath the vehicle, e.g., cable car in San Francisco
106    CableCar,
107    /// 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
108    Gondola,
109    /// Any rail system designed for steep inclines
110    Funicular,
111    /// (extended) Used for intercity bus services
112    Coach,
113    /// (extended) Airplanes
114    Air,
115    /// (extended) Taxi, Cab
116    Taxi,
117    /// (extended) any other value
118    Other(i16),
119}
120
121impl<'de> Deserialize<'de> for RouteType {
122    fn deserialize<D>(deserializer: D) -> Result<RouteType, D::Error>
123    where
124        D: Deserializer<'de>,
125    {
126        let i = i16::deserialize(deserializer)?;
127
128        let hundreds = i / 100;
129        Ok(match (i, hundreds) {
130            (0, _) | (_, 9) => RouteType::Tramway,
131            (1, _) | (_, 4) => RouteType::Subway,
132            (2, _) | (_, 1) => RouteType::Rail,
133            (3, _) | (_, 7) | (_, 8) => RouteType::Bus,
134            (4, _) | (_, 10) | (_, 12) => RouteType::Ferry,
135            (5, _) => RouteType::CableCar,
136            (6, _) | (_, 13) => RouteType::Gondola,
137            (7, _) | (_, 14) => RouteType::Funicular,
138            (_, 2) => RouteType::Coach,
139            (_, 11) => RouteType::Air,
140            (_, 15) => RouteType::Taxi,
141            _ => RouteType::Other(i),
142        })
143    }
144}
145
146impl Serialize for RouteType {
147    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
148    where
149        S: Serializer,
150    {
151        // Note: for extended route type, we might loose the initial precise route type
152        serializer.serialize_i16(match self {
153            RouteType::Tramway => 0,
154            RouteType::Subway => 1,
155            RouteType::Rail => 2,
156            RouteType::Bus => 3,
157            RouteType::Ferry => 4,
158            RouteType::CableCar => 5,
159            RouteType::Gondola => 6,
160            RouteType::Funicular => 7,
161            RouteType::Coach => 200,
162            RouteType::Air => 1100,
163            RouteType::Taxi => 1500,
164            RouteType::Other(i) => *i,
165        })
166    }
167}
168
169/// 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`
170#[derive(Debug, Derivative, Copy, Clone, PartialEq, Eq, Hash)]
171#[derivative(Default(bound = ""))]
172pub enum PickupDropOffType {
173    /// Regularly scheduled pickup or drop off (default when empty).
174    #[derivative(Default)]
175    Regular,
176    /// No pickup or drop off available.
177    NotAvailable,
178    /// Must phone agency to arrange pickup or drop off.
179    ArrangeByPhone,
180    /// Must coordinate with driver to arrange pickup or drop off.
181    CoordinateWithDriver,
182    /// An unknown value not in the specification
183    Unknown(i16),
184}
185
186impl<'de> Deserialize<'de> for PickupDropOffType {
187    fn deserialize<D>(deserializer: D) -> Result<PickupDropOffType, D::Error>
188    where
189        D: Deserializer<'de>,
190    {
191        let s = <&str>::deserialize(deserializer)?;
192        Ok(match s {
193            "" | "0" => PickupDropOffType::Regular,
194            "1" => PickupDropOffType::NotAvailable,
195            "2" => PickupDropOffType::ArrangeByPhone,
196            "3" => PickupDropOffType::CoordinateWithDriver,
197            s => PickupDropOffType::Unknown(s.parse().map_err(|_| {
198                serde::de::Error::custom(format!(
199                    "invalid value for PickupDropOffType, must be an integer: {s}"
200                ))
201            })?),
202        })
203    }
204}
205
206impl Serialize for PickupDropOffType {
207    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
208    where
209        S: Serializer,
210    {
211        // Note: for extended route type, we might loose the initial precise route type
212        serialize_i16_as_str(
213            serializer,
214            match self {
215                PickupDropOffType::Regular => 0,
216                PickupDropOffType::NotAvailable => 1,
217                PickupDropOffType::ArrangeByPhone => 2,
218                PickupDropOffType::CoordinateWithDriver => 3,
219                PickupDropOffType::Unknown(i) => *i,
220            },
221        )
222    }
223}
224
225/// Indicates whether a rider can board the transit vehicle anywhere along the vehicle’s travel path
226///
227/// Those values are only defined on <https://developers.google.com/transit/gtfs/reference#routestxt,> not on <https://gtfs.org/reference/static/#routestxt>
228#[derive(Debug, Derivative, Copy, Clone, PartialEq, Eq, Hash)]
229#[derivative(Default(bound = ""))]
230pub enum ContinuousPickupDropOff {
231    /// Continuous stopping pickup or drop off.
232    Continuous,
233    /// No continuous stopping pickup or drop off (default when empty).
234    #[derivative(Default)]
235    NotAvailable,
236    /// Must phone agency to arrange continuous stopping pickup or drop off.
237    ArrangeByPhone,
238    /// Must coordinate with driver to arrange continuous stopping pickup or drop off.
239    CoordinateWithDriver,
240    /// An unknown value not in the specification
241    Unknown(i16),
242}
243
244impl Serialize for ContinuousPickupDropOff {
245    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
246    where
247        S: Serializer,
248    {
249        // Note: for extended route type, we might loose the initial precise route type
250        serialize_i16_as_str(
251            serializer,
252            match self {
253                ContinuousPickupDropOff::Continuous => 0,
254                ContinuousPickupDropOff::NotAvailable => 1,
255                ContinuousPickupDropOff::ArrangeByPhone => 2,
256                ContinuousPickupDropOff::CoordinateWithDriver => 3,
257                ContinuousPickupDropOff::Unknown(i) => *i,
258            },
259        )
260    }
261}
262
263impl<'de> Deserialize<'de> for ContinuousPickupDropOff {
264    fn deserialize<D>(deserializer: D) -> Result<ContinuousPickupDropOff, D::Error>
265    where
266        D: Deserializer<'de>,
267    {
268        let s = <&str>::deserialize(deserializer)?;
269        Ok(match s {
270            "0" => ContinuousPickupDropOff::Continuous,
271            "" | "1" => ContinuousPickupDropOff::NotAvailable,
272            "2" => ContinuousPickupDropOff::ArrangeByPhone,
273            "3" => ContinuousPickupDropOff::CoordinateWithDriver,
274            s => ContinuousPickupDropOff::Unknown(s.parse().map_err(|_| {
275                serde::de::Error::custom(format!(
276                    "invalid value for ContinuousPickupDropOff, must be an integer: {s}"
277                ))
278            })?),
279        })
280    }
281}
282
283/// Describes if the stop time is exact or not. See <https://gtfs.org/reference/static/#stop_timestxt> `timepoint`
284#[derive(Debug, Derivative, Serialize, Copy, Clone, PartialEq, Eq, Hash)]
285#[derivative(Default)]
286pub enum TimepointType {
287    /// Times are considered approximate
288    #[serde(rename = "0")]
289    Approximate = 0,
290    /// Times are considered exact
291    #[derivative(Default)]
292    #[serde(rename = "1")]
293    Exact = 1,
294}
295
296impl<'de> Deserialize<'de> for TimepointType {
297    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
298    where
299        D: Deserializer<'de>,
300    {
301        let s = <&str>::deserialize(deserializer)?;
302        match s {
303            "" | "1" => Ok(Self::Exact),
304            "0" => Ok(Self::Approximate),
305            v => Err(serde::de::Error::custom(format!(
306                "invalid value for timepoint: {v}"
307            ))),
308        }
309    }
310}
311
312/// Generic enum to define if a service (like wheelchair boarding) is available
313#[derive(Debug, Derivative, PartialEq, Eq, Hash, Clone, Copy)]
314#[derivative(Default)]
315pub enum Availability {
316    /// No information if the service is available
317    #[derivative(Default)]
318    InformationNotAvailable,
319    /// The service is available
320    Available,
321    /// The service is not available
322    NotAvailable,
323    /// An unknown value not in the specification
324    Unknown(i16),
325}
326
327impl<'de> Deserialize<'de> for Availability {
328    fn deserialize<D>(deserializer: D) -> Result<Availability, D::Error>
329    where
330        D: Deserializer<'de>,
331    {
332        let s = <&str>::deserialize(deserializer)?;
333        Ok(match s {
334            "" | "0" => Availability::InformationNotAvailable,
335            "1" => Availability::Available,
336            "2" => Availability::NotAvailable,
337            s => Availability::Unknown(s.parse().map_err(|_| {
338                serde::de::Error::custom(format!(
339                    "invalid value for Availability, must be an integer: {s}"
340                ))
341            })?),
342        })
343    }
344}
345
346impl Serialize for Availability {
347    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
348    where
349        S: Serializer,
350    {
351        // Note: for extended route type, we might loose the initial precise route type
352        serialize_i16_as_str(
353            serializer,
354            match self {
355                Availability::InformationNotAvailable => 0,
356                Availability::Available => 1,
357                Availability::NotAvailable => 2,
358                Availability::Unknown(i) => *i,
359            },
360        )
361    }
362}
363
364/// Defines if a [CalendarDate] is added or deleted from a [Calendar]
365#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone, Copy)]
366pub enum Exception {
367    /// There will be a service on that day
368    #[serde(rename = "1")]
369    Added,
370    /// There won’t be a service on that day
371    #[serde(rename = "2")]
372    Deleted,
373}
374
375/// Defines the direction of a [Trip], only for display, not for routing. See <https://gtfs.org/reference/static/#tripstxt> `direction_id`
376#[derive(Debug, Deserialize, Serialize, Copy, Clone, PartialEq, Eq, Hash)]
377pub enum DirectionType {
378    /// Travel in one direction (e.g. outbound travel).
379    #[serde(rename = "0")]
380    Outbound,
381    /// Travel in the opposite direction (e.g. inbound travel).
382    #[serde(rename = "1")]
383    Inbound,
384}
385
386/// Is the [Trip] accessible with a bike. See <https://gtfs.org/reference/static/#tripstxt> `bikes_allowed`
387#[derive(Debug, Derivative, Copy, Clone, PartialEq, Eq, Hash)]
388#[derivative(Default())]
389pub enum BikesAllowedType {
390    /// No bike information for the trip
391    #[derivative(Default)]
392    NoBikeInfo,
393    /// Vehicle being used on this particular trip can accommodate at least one bicycle
394    AtLeastOneBike,
395    /// No bicycles are allowed on this trip
396    NoBikesAllowed,
397    /// An unknown value not in the specification
398    Unknown(i16),
399}
400
401impl<'de> Deserialize<'de> for BikesAllowedType {
402    fn deserialize<D>(deserializer: D) -> Result<BikesAllowedType, D::Error>
403    where
404        D: Deserializer<'de>,
405    {
406        let s = <&str>::deserialize(deserializer)?;
407        Ok(match s {
408            "" | "0" => BikesAllowedType::NoBikeInfo,
409            "1" => BikesAllowedType::AtLeastOneBike,
410            "2" => BikesAllowedType::NoBikesAllowed,
411            s => BikesAllowedType::Unknown(s.parse().map_err(|_| {
412                serde::de::Error::custom(format!(
413                    "invalid value for BikeAllowedType, must be an integer: {s}"
414                ))
415            })?),
416        })
417    }
418}
419
420impl Serialize for BikesAllowedType {
421    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
422    where
423        S: Serializer,
424    {
425        // Note: for extended route type, we might loose the initial precise route type
426        serialize_i16_as_str(
427            serializer,
428            match self {
429                BikesAllowedType::NoBikeInfo => 0,
430                BikesAllowedType::AtLeastOneBike => 1,
431                BikesAllowedType::NoBikesAllowed => 2,
432                BikesAllowedType::Unknown(i) => *i,
433            },
434        )
435    }
436}
437
438/// Defines where a [FareAttribute] can be paid
439#[derive(Debug, Deserialize, Serialize, Copy, Clone, PartialEq, Eq)]
440pub enum PaymentMethod {
441    /// Fare is paid on board
442    #[serde(rename = "0")]
443    Aboard,
444    /// Fare must be paid before boarding
445    #[serde(rename = "1")]
446    PreBoarding,
447}
448
449/// Defines if the [Frequency] is exact (the vehicle runs exactly every n minutes) or not
450#[derive(Debug, Serialize, Copy, Clone, PartialEq, Eq, Hash)]
451pub enum ExactTimes {
452    /// Frequency-based trips
453    FrequencyBased = 0,
454    /// Schedule-based trips with the exact same headway throughout the day.
455    ScheduleBased = 1,
456}
457
458impl<'de> Deserialize<'de> for ExactTimes {
459    fn deserialize<D>(deserializer: D) -> Result<ExactTimes, D::Error>
460    where
461        D: Deserializer<'de>,
462    {
463        let s = <&str>::deserialize(deserializer)?;
464        Ok(match s {
465            "" | "0" => ExactTimes::FrequencyBased,
466            "1" => ExactTimes::ScheduleBased,
467            &_ => {
468                return Err(serde::de::Error::custom(format!(
469                    "Invalid value `{s}`, expected 0 or 1"
470                )))
471            }
472        })
473    }
474}
475
476/// Defines how many transfers can be done with on [FareAttribute]
477#[derive(Debug, Derivative, Copy, Clone, PartialEq, Eq, Hash)]
478#[derivative(Default(bound = ""))]
479pub enum Transfers {
480    /// Unlimited transfers are permitted
481    #[derivative(Default)]
482    Unlimited,
483    /// No transfers permitted on this fare
484    NoTransfer,
485    /// Riders may transfer once
486    UniqueTransfer,
487    ///Riders may transfer twice
488    TwoTransfers,
489    /// Other transfer values
490    Other(i16),
491}
492
493impl<'de> Deserialize<'de> for Transfers {
494    fn deserialize<D>(deserializer: D) -> Result<Transfers, D::Error>
495    where
496        D: Deserializer<'de>,
497    {
498        let i = Option::<i16>::deserialize(deserializer)?;
499        Ok(match i {
500            Some(0) => Transfers::NoTransfer,
501            Some(1) => Transfers::UniqueTransfer,
502            Some(2) => Transfers::TwoTransfers,
503            Some(a) => Transfers::Other(a),
504            None => Transfers::default(),
505        })
506    }
507}
508
509impl Serialize for Transfers {
510    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
511    where
512        S: Serializer,
513    {
514        match self {
515            Transfers::NoTransfer => serialize_i16_as_str(serializer, 0),
516            Transfers::UniqueTransfer => serialize_i16_as_str(serializer, 1),
517            Transfers::TwoTransfers => serialize_i16_as_str(serializer, 2),
518            Transfers::Other(a) => serialize_i16_as_str(serializer, *a),
519            Transfers::Unlimited => serializer.serialize_none(),
520        }
521    }
522}
523/// Defines the type of a [StopTransfer]
524#[derive(Debug, Serialize, Derivative, Copy, Clone, PartialEq, Eq, Hash)]
525#[derivative(Default)]
526pub enum TransferType {
527    /// Recommended transfer point between routes
528    #[serde(rename = "0")]
529    #[derivative(Default)]
530    Recommended,
531    /// Departing vehicle waits for arriving one
532    #[serde(rename = "1")]
533    Timed,
534    /// Transfer requires a minimum amount of time between arrival and departure to ensure a connection.
535    #[serde(rename = "2")]
536    MinTime,
537    /// Transfer is not possible at this location
538    #[serde(rename = "3")]
539    Impossible,
540    /// Passengers can stay onboard the same vehicle to transfer from one trip to another
541    #[serde(rename = "4")]
542    StayOnBoard,
543    /// In-seat transfers aren't allowed between sequential trips.
544    /// The passenger must alight from the vehicle and re-board.
545    #[serde(rename = "5")]
546    MustAlight,
547}
548
549impl<'de> Deserialize<'de> for TransferType {
550    fn deserialize<D>(deserializer: D) -> Result<TransferType, D::Error>
551    where
552        D: Deserializer<'de>,
553    {
554        let s = <&str>::deserialize(deserializer)?;
555        Ok(match s {
556            "" | "0" => TransferType::Recommended,
557            "1" => TransferType::Timed,
558            "2" => TransferType::MinTime,
559            "3" => TransferType::Impossible,
560            "4" => TransferType::StayOnBoard,
561            "5" => TransferType::MustAlight,
562            s => {
563                return Err(serde::de::Error::custom(format!(
564                    "Invalid value `{s}`, expected 0, 1, 2, 3, 4, 5"
565                )))
566            }
567        })
568    }
569}
570
571/// Type of pathway between [from_stop] and [to_stop]
572#[derive(Debug, Serialize, Deserialize, Derivative, Copy, Clone, PartialEq, Eq, Hash)]
573#[derivative(Default)]
574pub enum PathwayMode {
575    /// A walkway
576    #[serde(rename = "1")]
577    #[derivative(Default)]
578    Walkway,
579    /// Stairs
580    #[serde(rename = "2")]
581    Stairs,
582    /// Moving sidewalk / travelator
583    #[serde(rename = "3")]
584    MovingSidewalk,
585    /// Escalator
586    #[serde(rename = "4")]
587    Escalator,
588    /// Elevator
589    #[serde(rename = "5")]
590    Elevator,
591    /// A pathway that crosses into an area of the station where a
592    /// proof of payment is required (usually via a physical payment gate)
593    #[serde(rename = "6")]
594    FareGate,
595    /// Indicates a pathway exiting an area where proof-of-payment is required
596    /// into an area where proof-of-payment is no longer required.
597    #[serde(rename = "7")]
598    ExitGate,
599}
600
601/// Indicates in which direction the pathway can be used
602#[derive(Debug, Serialize, Deserialize, Derivative, Copy, Clone, PartialEq, Eq, Hash)]
603#[derivative(Default)]
604pub enum PathwayDirectionType {
605    /// Unidirectional pathway, it can only be used from [from_stop_id] to [to_stop_id].
606    #[serde(rename = "0")]
607    #[derivative(Default)]
608    Unidirectional,
609    /// Bidirectional pathway, it can be used in the two directions.
610    #[serde(rename = "1")]
611    Bidirectional,
612}
613
614/// Defines the type of a [FareMedia]
615#[derive(Debug, Deserialize, Serialize, Copy, Clone, PartialEq, Eq)]
616pub enum FareMediaType {
617    /// Used when there is no fare media involved in purchasing or validating a fare product
618    #[serde(rename = "0")]
619    None,
620    /// Physical paper ticket
621    #[serde(rename = "1")]
622    PhysicalPaperTicket,
623    /// Physical transit card
624    #[serde(rename = "2")]
625    PhysicalTransitCard,
626    /// cEMV (contactless Europay, Mastercard and Visa)
627    #[serde(rename = "3")]
628    CEmv,
629    /// Mobile app
630    #[serde(rename = "4")]
631    MobileApp,
632}
633
634/// Specifies if an entry in rider_categories.txt should be considered the default category
635#[derive(Debug, Serialize, Derivative, Copy, Clone, PartialEq, Eq, Hash)]
636pub enum DefaultFareCategory {
637    /// Category is not considered the default.
638    NotDefault = 0,
639    /// Category is considered the default one.
640    Default = 1,
641}
642
643impl<'de> Deserialize<'de> for DefaultFareCategory {
644    fn deserialize<D>(deserializer: D) -> Result<DefaultFareCategory, D::Error>
645    where
646        D: Deserializer<'de>,
647    {
648        let s = <&str>::deserialize(deserializer)?;
649        Ok(match s {
650            "" | "0" => DefaultFareCategory::NotDefault,
651            "1" => DefaultFareCategory::Default,
652            &_ => {
653                return Err(serde::de::Error::custom(format!(
654                    "Invalid value `{s}`, expected 0 or 1"
655                )))
656            }
657        })
658    }
659}