gistools/readers/gtfs/schedule/
fare_leg_rules.rs

1use crate::readers::csv::parse_csv_as_record;
2use alloc::{string::String, vec::Vec};
3use s2json::MValueCompatible;
4
5/// # Fare Leg Rules
6///
7/// **Optional**
8/// Defines more granular fare rules for individual legs of travel (GTFS-Fares V2).
9///
10/// Use these rules by filtering on:
11/// - `network_id`
12/// - `from_area_id`
13/// - `to_area_id`
14/// - `from_timeframe_group_id`
15/// - `to_timeframe_group_id`
16///
17/// Multiple matching strategies exist depending on the presence or absence of `rule_priority`:
18/// - If `rule_priority` does **not** exist, empty fields represent an **inverse** match against
19///   all possible values **except** those otherwise specified.
20/// - If `rule_priority` **does** exist, empty fields mean the field does not affect matching.
21///
22/// For matching an “effective fare leg” that spans multiple legs, see the specification for
23/// rules on using the first vs. last leg’s departure/arrival areas and timeframes.
24#[derive(Debug, Default, Clone, PartialEq, MValueCompatible)]
25pub struct GTFSFareLegRule {
26    /// **Optional**
27    /// Identifies a group of entries in fare_leg_rules.txt that can be referenced
28    /// in `fare_transfer_rules.from_leg_group_id` or `fare_transfer_rules.to_leg_group_id`.
29    pub leg_group_id: Option<String>,
30    /// **Optional**
31    /// Identifies a route network (`routes.network_id` or `networks.network_id`) this rule applies to.
32    /// - If `rule_priority` is omitted and no matching `network_id`, empty matches “all but listed”.
33    /// - If `rule_priority` exists, empty means network does not affect matching.
34    pub network_id: Option<String>,
35    /// **Optional**
36    /// Identifies a departure area (`areas.area_id`) for this fare leg rule.
37    /// - If `rule_priority` is omitted and no matching `from_area_id`, empty matches “all but listed”.
38    /// - If `rule_priority` exists, empty means departure area does not affect matching.
39    pub from_area_id: Option<String>,
40    /// **Optional**
41    /// Identifies an arrival area (`areas.area_id`) for this fare leg rule.
42    /// - If `rule_priority` is omitted and no matching `to_area_id`, empty matches “all but listed”.
43    /// - If `rule_priority` exists, empty means arrival area does not affect matching.
44    pub to_area_id: Option<String>,
45    /// **Optional**
46    /// References a `timeframes.timeframe_group_id` for the start of the fare leg.
47    /// An empty value means the start time does not affect matching.
48    pub from_timeframe_group_id: Option<String>,
49    /// **Optional**
50    /// References a `timeframes.timeframe_group_id` for the end of the fare leg.
51    /// An empty value means the end time does not affect matching.
52    pub to_timeframe_group_id: Option<String>,
53    /// **Required**
54    /// References a `fare_products.fare_product_id`.
55    /// The rider must possess/purchase this fare product for the described leg.
56    pub fare_product_id: String,
57    /// **Optional**
58    /// Defines the order of priority in which matching rules are applied.
59    /// - Higher priority overrides lower priority when multiple rules match.
60    /// - Empty is treated as zero.
61    pub rule_priority: i64,
62}
63impl GTFSFareLegRule {
64    /// Create a new GTFSFareLegRule
65    pub fn new(source: &str) -> Vec<GTFSFareLegRule> {
66        let mut res = Vec::new();
67        for record in parse_csv_as_record::<GTFSFareLegRule>(source, None, None) {
68            res.push(record);
69        }
70        res
71    }
72}