gistools/readers/gtfs/schedule/
fare_attributes.rs

1use crate::readers::csv::parse_csv_as_record;
2use alloc::{collections::BTreeMap, string::String};
3use s2json::MValueCompatible;
4
5// NOTE:
6// The files associated with GTFS-Fares V1 are:
7// - fare_attributes.txt
8// - fare_rules.txt
9//
10// The files associated with GTFS-Fares V2 are:
11// - fare_media.txt
12// - fare_products.txt
13// - fare_leg_rules.txt
14// - fare_transfer_rules.txt
15
16/// Indicates when the fare must be paid:
17/// - 0 = On board
18/// - 1 = Before boarding
19#[derive(Debug, Clone, Copy, PartialEq)]
20pub enum GTFSPaymentMethod {
21    /// 0 = On board
22    OnBoard = 0,
23    /// 1 = Before boarding
24    PreBoard = 1,
25}
26impl From<i8> for GTFSPaymentMethod {
27    fn from(s: i8) -> Self {
28        match s {
29            1 => GTFSPaymentMethod::PreBoard,
30            _ => GTFSPaymentMethod::OnBoard,
31        }
32    }
33}
34
35/// Transfers can be:
36/// - 0 = No transfers permitted
37/// - 1 = One transfer
38/// - 2 = Two transfers
39/// - '' (empty string) = Unlimited transfers
40#[derive(Debug, Clone, Copy, PartialEq)]
41pub enum GTFSTransfersType {
42    /// 0 = No transfers permitted
43    NoTransfers = 0,
44    /// 1 = One transfer
45    OneTransfer = 1,
46    /// 2 = Two transfers
47    TwoTransfers = 2,
48    /// '' (empty string) = Unlimited transfers
49    UnlimitedTransfers,
50}
51impl From<&str> for GTFSTransfersType {
52    fn from(s: &str) -> Self {
53        match s {
54            "1" => GTFSTransfersType::OneTransfer,
55            "2" => GTFSTransfersType::TwoTransfers,
56            "" => GTFSTransfersType::UnlimitedTransfers,
57            _ => GTFSTransfersType::NoTransfers,
58        }
59    }
60}
61
62/// # Fare Attributes (GTFS-Fares V1)
63///
64/// **Optional** - But required if using GTFS-Fares V1 approach.
65/// Defines basic fare information such as price, currency, and transfer limits.
66#[derive(Debug, Default, Clone, PartialEq, MValueCompatible)]
67pub struct GTFSFareAttribute {
68    /// **Required**
69    /// Identifies a fare class.
70    pub fare_id: String,
71    /// **Required**
72    /// Fare price in the currency specified by `currencyType`.
73    pub price: f64,
74    /// **Required**
75    /// Currency code (e.g., "USD", "EUR").
76    pub currency_type: String,
77    /// **Required**
78    /// When the fare must be paid.
79    /// - 0 = Paid on board
80    /// - 1 = Must be paid before boarding
81    pub payment_method: i8,
82    /// **Required**
83    /// Number of transfers permitted on this fare.
84    /// - 0 = No transfers
85    /// - 1 = One transfer
86    /// - 2 = Two transfers
87    /// - '' (empty) = Unlimited transfers
88    pub transfers: String,
89    /// **Conditionally Required**
90    /// Agency for the specified fare.
91    /// Required if multiple agencies exist in `agency.txt`.
92    pub agency_id: Option<String>,
93    /// **Optional**
94    /// Length of time in seconds before a transfer (or this fare) expires.
95    /// When transfers=0, may indicate ticket validity duration or be empty.
96    pub transfer_duration: Option<i32>,
97}
98impl GTFSFareAttribute {
99    /// Create a new GTFSFareAttribute
100    pub fn new(source: &str) -> BTreeMap<String, GTFSFareAttribute> {
101        let mut res = BTreeMap::new();
102        for record in parse_csv_as_record::<GTFSFareAttribute>(source, None, None) {
103            res.insert(record.fare_id.clone(), record);
104        }
105        res
106    }
107    /// Get the payment type
108    pub fn payment_method(&self) -> GTFSPaymentMethod {
109        self.payment_method.into()
110    }
111    /// Get the transfers type
112    pub fn transfers(&self) -> GTFSTransfersType {
113        self.transfers.as_str().into()
114    }
115}