gistools/readers/gtfs/schedule/fare_leg_join_rules.rs
1use crate::readers::csv::parse_csv_as_record;
2use alloc::{string::String, vec::Vec};
3use s2json::MValueCompatible;
4
5/// # Fare Leg Join Rules
6///
7/// **Optional**
8/// Defines when two consecutive legs with a transfer should be considered as
9/// a single “effective fare leg” for the purpose of matching rules in `fare_leg_rules.txt`.
10///
11/// **Primary Key**: (`from_network_id`, `to_network_id`, `from_stop_id`, `to_stop_id`)
12///
13/// Matching Logic:
14/// - If both `from_network_id` and `to_network_id` match consecutive legs’ networks,
15/// and `from_stop_id`/`to_stop_id` match station or stop IDs for the transfer,
16/// those two legs merge into one effective leg.
17/// - If a field is empty, that field is ignored for matching.
18/// - Consecutive transfers that each match a join rule merge the entire sub-journey
19/// into a single effective fare leg.
20#[derive(Debug, Default, Clone, PartialEq, MValueCompatible)]
21pub struct GTFSFareLegJoinRule {
22 /// **Required**
23 /// Matches the pre-transfer leg’s route network (`routes.network_id` or `networks.network_id`).
24 /// Must be specified alongside `toNetworkId`.
25 pub from_network_id: String,
26 /// **Required**
27 /// Matches the post-transfer leg’s route network (`routes.network_id` or `networks.network_id`).
28 /// Must be specified alongside `fromNetworkId`.
29 pub to_network_id: String,
30 /// **Conditionally Required**
31 /// Matches the pre-transfer leg’s ending stop/station (`stops.stop_id`).
32 /// Required if `toStopId` is defined; optional otherwise.
33 pub from_stop_id: Option<String>,
34 /// **Conditionally Required**
35 /// Matches the post-transfer leg’s starting stop/station (`stops.stop_id`).
36 /// Required if `fromStopId` is defined; optional otherwise.
37 pub to_stop_id: Option<String>,
38}
39impl GTFSFareLegJoinRule {
40 /// Create a new GTFSFareLegJoinRule
41 pub fn new(source: &str) -> Vec<GTFSFareLegJoinRule> {
42 let mut res = Vec::new();
43 for record in parse_csv_as_record::<GTFSFareLegJoinRule>(source, None, None) {
44 res.push(record);
45 }
46 res
47 }
48}