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}