Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Fares v1 #157

Merged
merged 1 commit into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
description = "Read GTFS (public transit timetables) files"
name = "gtfs-structures"
version = "0.39.1"
version = "0.40.0"
authors = ["Tristram Gräbener <[email protected]>", "Antoine Desbordes <[email protected]>"]
repository = "https://github.com/rust-transit/gtfs-structure"
license = "MIT"
Expand Down
1 change: 1 addition & 0 deletions fixtures/fares_v1/agency.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
agency_name,agency_url,agency_timezone,agency_lang
2 changes: 2 additions & 0 deletions fixtures/fares_v1/fare_attributes.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
fare_id,price,currency_type,payment_method,transfers,transfer_duration
presto_fare,3.2,CAD,1,,7200
3 changes: 3 additions & 0 deletions fixtures/fares_v1/fare_rules.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fare_id,route_id,origin_id,destination_id
presto_fare,line1,ttc_subway_stations,ttc_subway_stations
presto_fare,line2,ttc_subway_stations,ttc_subway_stations
1 change: 1 addition & 0 deletions fixtures/fares_v1/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Dataset constructed from the [GTFS fares v1 example](https://gtfs.org/schedule/examples/fares-v1/).
3 changes: 3 additions & 0 deletions fixtures/fares_v1/routes.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
agency_id,route_id,route_type
TTC,Line1,1
TTC,Line2,1
1 change: 1 addition & 0 deletions fixtures/fares_v1/stop_times.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
trip_id,arrival_time,departure_time,stop_id,stop_sequence,stop_time_desc,pickup_type,drop_off_type,timepoint
3 changes: 3 additions & 0 deletions fixtures/fares_v1/stops.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
stop_id,stop_name,stop_lat,stop_lon,zone_id
Bloor,Bloor Station,,43.670049,-79.385389,ttc_subway_stations
Yonge,Yonge Station,,43.671049,-79.386789,ttc_subway_stations
3 changes: 3 additions & 0 deletions fixtures/fares_v1/transfers.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from_stop_id,to_stop_id,from_route_id,to_route_id,transfer_type
Bloor,Yonge,line1,line2,0
Yonge,Bloor,line2,line1,0
1 change: 1 addition & 0 deletions fixtures/fares_v1/trips.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
route_id,service_id,trip_id,trip_headsign,trip_short_name,direction_id,block_id,wheelchair_accessible,bikes_allowed,trip_desc,shape_id
2 changes: 1 addition & 1 deletion src/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub enum ObjectType {
}

/// Describes the kind of [Stop]. See <https://gtfs.org/reference/static/#stopstxt> `location_type`
#[derive(Derivative, Debug, Copy, Clone, PartialEq, Eq)]
#[derive(Derivative, Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[derivative(Default(bound = ""))]
pub enum LocationType {
/// Stop (or Platform). A location where passengers board or disembark from a transit vehicle. Is called a platform when defined within a parent_station
Expand Down
8 changes: 8 additions & 0 deletions src/gtfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ pub struct Gtfs {
pub shapes: HashMap<String, Vec<Shape>>,
/// All fare attributes by `fare_id`
pub fare_attributes: HashMap<String, FareAttribute>,
/// All fare rules by `fare_id`
pub fare_rules: HashMap<String, Vec<FareRule>>,
/// All feed information. There is no identifier
pub feed_info: Vec<FeedInfo>,
}
Expand All @@ -57,13 +59,19 @@ impl TryFrom<RawGtfs> for Gtfs {
let frequencies = raw.frequencies.unwrap_or_else(|| Ok(Vec::new()))?;
let trips = create_trips(raw.trips?, raw.stop_times?, frequencies, &stops)?;

let mut fare_rules = HashMap::<String, Vec<FareRule>>::new();
for f in raw.fare_rules.unwrap_or_else(|| Ok(Vec::new()))? {
(*fare_rules.entry(f.fare_id.clone()).or_default()).push(f);
}

Ok(Gtfs {
stops,
routes: to_map(raw.routes?),
trips,
agencies: raw.agencies?,
shapes: to_shape_map(raw.shapes.unwrap_or_else(|| Ok(Vec::new()))?),
fare_attributes: to_map(raw.fare_attributes.unwrap_or_else(|| Ok(Vec::new()))?),
fare_rules,
feed_info: raw.feed_info.unwrap_or_else(|| Ok(Vec::new()))?,
calendar: to_map(raw.calendar.unwrap_or_else(|| Ok(Vec::new()))?),
calendar_dates: to_calendar_dates(
Expand Down
3 changes: 3 additions & 0 deletions src/gtfs_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ impl RawGtfsReader {
agencies: self.read_objs_from_path(p.join("agency.txt")),
shapes: self.read_objs_from_optional_path(p, "shapes.txt"),
fare_attributes: self.read_objs_from_optional_path(p, "fare_attributes.txt"),
fare_rules: self.read_objs_from_optional_path(p, "fare_rules.txt"),
frequencies: self.read_objs_from_optional_path(p, "frequencies.txt"),
transfers: self.read_objs_from_optional_path(p, "transfers.txt"),
pathways: self.read_objs_from_optional_path(p, "pathways.txt"),
Expand Down Expand Up @@ -262,6 +263,7 @@ impl RawGtfsReader {
"stop_times.txt",
"trips.txt",
"fare_attributes.txt",
"fare_rules.txt",
"frequencies.txt",
"transfers.txt",
"pathways.txt",
Expand Down Expand Up @@ -297,6 +299,7 @@ impl RawGtfsReader {
&mut archive,
"fare_attributes.txt",
),
fare_rules: self.read_optional_file(&file_mapping, &mut archive, "fare_rules.txt"),
frequencies: self.read_optional_file(&file_mapping, &mut archive, "frequencies.txt"),
transfers: self.read_optional_file(&file_mapping, &mut archive, "transfers.txt"),
pathways: self.read_optional_file(&file_mapping, &mut archive, "pathways.txt"),
Expand Down
17 changes: 16 additions & 1 deletion src/objects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,7 @@ impl Id for Shape {
}

/// Defines one possible fare. See <https://gtfs.org/reference/static/#fare_attributestxt>
#[derive(Debug, Serialize, Deserialize)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct FareAttribute {
/// Unique technical (not for the traveller) identifier for the FareAttribute
#[serde(rename = "fare_id")]
Expand Down Expand Up @@ -596,6 +596,21 @@ impl Type for FareAttribute {
}
}

/// Defines one possible fare. See <https://gtfs.org/schedule/reference/#fare_rulestxt>
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct FareRule {
/// ID of the referenced FareAttribute.
pub fare_id: String,
/// ID of a [Route] associated with the fare class
pub route_id: Option<String>,
/// Identifies an origin zone. References a [Stop].zone_id
pub origin_id: Option<String>,
/// Identifies an destination zone. References a [Stop].zone_id
pub destination_id: Option<String>,
/// Identifies the zones that a rider will enter while using a given fare class. References a [Stop].zone_id
pub contains_id: Option<String>,
}

/// A [Frequency] before being merged into the corresponding [Trip]
#[derive(Debug, Serialize, Deserialize, Default)]
pub struct RawFrequency {
Expand Down
2 changes: 2 additions & 0 deletions src/raw_gtfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ pub struct RawGtfs {
pub shapes: Option<Result<Vec<Shape>, Error>>,
/// All FareAttribates, None if the file was absent as it is not mandatory
pub fare_attributes: Option<Result<Vec<FareAttribute>, Error>>,
/// All FareRules, None if the file was absent as it is not mandatory
pub fare_rules: Option<Result<Vec<FareRule>, Error>>,
/// All Frequencies, None if the file was absent as it is not mandatory
pub frequencies: Option<Result<Vec<RawFrequency>, Error>>,
/// All Transfers, None if the file was absent as it is not mandatory
Expand Down
44 changes: 44 additions & 0 deletions src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::collections::HashMap;

use crate::objects::*;
use crate::Gtfs;
use crate::RawGtfs;
Expand Down Expand Up @@ -470,3 +472,45 @@ fn sorted_shapes() {
]
);
}

#[test]
fn fare_v1() {
let gtfs = Gtfs::from_path("fixtures/fares_v1").expect("impossible to read gtfs");

let mut expected_attributes = HashMap::new();
expected_attributes.insert(
"presto_fare".to_string(),
FareAttribute {
id: "presto_fare".to_string(),
currency: "CAD".to_string(),
price: "3.2".to_string(),
payment_method: PaymentMethod::PreBoarding,
transfer_duration: Some(7200),
agency_id: None,
transfers: Transfers::Unlimited,
},
);
assert_eq!(gtfs.fare_attributes, expected_attributes);

let mut expected_rules = HashMap::new();
expected_rules.insert(
"presto_fare".to_string(),
vec![
FareRule {
fare_id: "presto_fare".to_string(),
route_id: Some("line1".to_string()),
origin_id: Some("ttc_subway_stations".to_string()),
destination_id: Some("ttc_subway_stations".to_string()),
contains_id: None,
},
FareRule {
fare_id: "presto_fare".to_string(),
route_id: Some("line2".to_string()),
origin_id: Some("ttc_subway_stations".to_string()),
destination_id: Some("ttc_subway_stations".to_string()),
contains_id: None,
},
],
);
assert_eq!(gtfs.fare_rules, expected_rules);
}
Loading