pub use crate::enums::*;
use crate::serde_helpers::*;
use chrono::{Datelike, NaiveDate, Weekday};
use rgb::RGB8;
use std::fmt;
use std::hash::Hash;
use std::sync::Arc;
pub trait Id {
fn id(&self) -> &str;
}
impl<T: Id> Id for Arc<T> {
fn id(&self) -> &str {
self.as_ref().id()
}
}
pub trait Type {
fn object_type(&self) -> ObjectType;
}
impl<T: Type> Type for Arc<T> {
fn object_type(&self) -> ObjectType {
self.as_ref().object_type()
}
}
#[derive(Debug, Clone, Deserialize, Serialize, Hash, PartialEq, Eq)]
pub struct Calendar {
#[serde(rename = "service_id")]
pub id: String,
#[serde(
deserialize_with = "deserialize_bool",
serialize_with = "serialize_bool"
)]
pub monday: bool,
#[serde(
deserialize_with = "deserialize_bool",
serialize_with = "serialize_bool"
)]
pub tuesday: bool,
#[serde(
deserialize_with = "deserialize_bool",
serialize_with = "serialize_bool"
)]
pub wednesday: bool,
#[serde(
deserialize_with = "deserialize_bool",
serialize_with = "serialize_bool"
)]
pub thursday: bool,
#[serde(
deserialize_with = "deserialize_bool",
serialize_with = "serialize_bool"
)]
pub friday: bool,
#[serde(
deserialize_with = "deserialize_bool",
serialize_with = "serialize_bool"
)]
pub saturday: bool,
#[serde(
deserialize_with = "deserialize_bool",
serialize_with = "serialize_bool"
)]
pub sunday: bool,
#[serde(
deserialize_with = "deserialize_date",
serialize_with = "serialize_date"
)]
pub start_date: NaiveDate,
#[serde(
deserialize_with = "deserialize_date",
serialize_with = "serialize_date"
)]
pub end_date: NaiveDate,
}
impl Type for Calendar {
fn object_type(&self) -> ObjectType {
ObjectType::Calendar
}
}
impl Id for Calendar {
fn id(&self) -> &str {
&self.id
}
}
impl fmt::Display for Calendar {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}—{}", self.start_date, self.end_date)
}
}
impl Calendar {
pub fn valid_weekday(&self, date: NaiveDate) -> bool {
match date.weekday() {
Weekday::Mon => self.monday,
Weekday::Tue => self.tuesday,
Weekday::Wed => self.wednesday,
Weekday::Thu => self.thursday,
Weekday::Fri => self.friday,
Weekday::Sat => self.saturday,
Weekday::Sun => self.sunday,
}
}
}
#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq)]
pub struct CalendarDate {
pub service_id: String,
#[serde(
deserialize_with = "deserialize_date",
serialize_with = "serialize_date"
)]
pub date: NaiveDate,
pub exception_type: Exception,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
pub struct Stop {
#[serde(rename = "stop_id")]
pub id: String,
#[serde(rename = "stop_code")]
pub code: Option<String>,
#[serde(rename = "stop_name")]
pub name: Option<String>,
#[serde(default, rename = "stop_desc")]
pub description: Option<String>,
#[serde(default)]
pub location_type: LocationType,
pub parent_station: Option<String>,
pub zone_id: Option<String>,
#[serde(rename = "stop_url")]
pub url: Option<String>,
#[serde(deserialize_with = "de_with_optional_float")]
#[serde(serialize_with = "serialize_float_as_str")]
#[serde(rename = "stop_lon", default)]
pub longitude: Option<f64>,
#[serde(deserialize_with = "de_with_optional_float")]
#[serde(serialize_with = "serialize_float_as_str")]
#[serde(rename = "stop_lat", default)]
pub latitude: Option<f64>,
#[serde(rename = "stop_timezone")]
pub timezone: Option<String>,
#[serde(deserialize_with = "de_with_empty_default", default)]
pub wheelchair_boarding: Availability,
pub level_id: Option<String>,
pub platform_code: Option<String>,
#[serde(skip)]
pub transfers: Vec<StopTransfer>,
#[serde(skip)]
pub pathways: Vec<Pathway>,
#[serde(rename = "tts_stop_name")]
pub tts_name: Option<String>,
}
impl Type for Stop {
fn object_type(&self) -> ObjectType {
ObjectType::Stop
}
}
impl Id for Stop {
fn id(&self) -> &str {
&self.id
}
}
impl fmt::Display for Stop {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.name.as_ref().unwrap_or(&String::from("")))
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct RawStopTime {
pub trip_id: String,
#[serde(
deserialize_with = "deserialize_optional_time",
serialize_with = "serialize_optional_time"
)]
pub arrival_time: Option<u32>,
#[serde(
deserialize_with = "deserialize_optional_time",
serialize_with = "serialize_optional_time"
)]
pub departure_time: Option<u32>,
pub stop_id: String,
pub stop_sequence: u32,
pub stop_headsign: Option<String>,
#[serde(default)]
pub pickup_type: PickupDropOffType,
#[serde(default)]
pub drop_off_type: PickupDropOffType,
#[serde(default)]
pub continuous_pickup: ContinuousPickupDropOff,
#[serde(default)]
pub continuous_drop_off: ContinuousPickupDropOff,
pub shape_dist_traveled: Option<f32>,
#[serde(default)]
pub timepoint: TimepointType,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct StopTime {
pub arrival_time: Option<u32>,
pub stop: Arc<Stop>,
pub departure_time: Option<u32>,
pub pickup_type: PickupDropOffType,
pub drop_off_type: PickupDropOffType,
pub stop_sequence: u32,
pub stop_headsign: Option<String>,
pub continuous_pickup: ContinuousPickupDropOff,
pub continuous_drop_off: ContinuousPickupDropOff,
pub shape_dist_traveled: Option<f32>,
pub timepoint: TimepointType,
}
impl StopTime {
pub fn from(stop_time_gtfs: RawStopTime, stop: Arc<Stop>) -> Self {
Self {
arrival_time: stop_time_gtfs.arrival_time,
departure_time: stop_time_gtfs.departure_time,
stop,
pickup_type: stop_time_gtfs.pickup_type,
drop_off_type: stop_time_gtfs.drop_off_type,
stop_sequence: stop_time_gtfs.stop_sequence,
stop_headsign: stop_time_gtfs.stop_headsign,
continuous_pickup: stop_time_gtfs.continuous_pickup,
continuous_drop_off: stop_time_gtfs.continuous_drop_off,
shape_dist_traveled: stop_time_gtfs.shape_dist_traveled,
timepoint: stop_time_gtfs.timepoint,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Route {
#[serde(rename = "route_id")]
pub id: String,
#[serde(rename = "route_short_name", default)]
pub short_name: Option<String>,
#[serde(rename = "route_long_name", default)]
pub long_name: Option<String>,
#[serde(rename = "route_desc")]
pub desc: Option<String>,
pub route_type: RouteType,
#[serde(rename = "route_url")]
pub url: Option<String>,
pub agency_id: Option<String>,
#[serde(rename = "route_sort_order")]
pub order: Option<u32>,
#[serde(
deserialize_with = "deserialize_optional_color",
serialize_with = "serialize_optional_color",
rename = "route_color",
default
)]
pub color: Option<RGB8>,
#[serde(
deserialize_with = "deserialize_optional_color",
serialize_with = "serialize_optional_color",
rename = "route_text_color",
default
)]
pub text_color: Option<RGB8>,
#[serde(default)]
pub continuous_pickup: ContinuousPickupDropOff,
#[serde(default)]
pub continuous_drop_off: ContinuousPickupDropOff,
}
impl Route {
pub fn text_color(&self) -> RGB8 {
self.text_color.unwrap_or_default()
}
pub fn color(&self) -> RGB8 {
self.color.unwrap_or_else(default_route_color)
}
}
impl Type for Route {
fn object_type(&self) -> ObjectType {
ObjectType::Route
}
}
impl Id for Route {
fn id(&self) -> &str {
&self.id
}
}
impl fmt::Display for Route {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(long_name) = self.long_name.as_ref() {
write!(f, "{long_name}")
} else if let Some(short_name) = self.short_name.as_ref() {
write!(f, "{short_name}")
} else {
write!(f, "{}", self.id)
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct RawTranslation {
pub table_name: String,
pub field_name: String,
pub language: String,
pub translation: String,
pub record_id: Option<String>,
pub record_sub_id: Option<String>,
pub field_value: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct RawTrip {
#[serde(rename = "trip_id")]
pub id: String,
pub service_id: String,
pub route_id: String,
pub shape_id: Option<String>,
pub trip_headsign: Option<String>,
pub trip_short_name: Option<String>,
pub direction_id: Option<DirectionType>,
pub block_id: Option<String>,
#[serde(default)]
pub wheelchair_accessible: Availability,
#[serde(default)]
pub bikes_allowed: BikesAllowedType,
}
impl Type for RawTrip {
fn object_type(&self) -> ObjectType {
ObjectType::Trip
}
}
impl Id for RawTrip {
fn id(&self) -> &str {
&self.id
}
}
impl fmt::Display for RawTrip {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"route id: {}, service id: {}",
self.route_id, self.service_id
)
}
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct Trip {
pub id: String,
pub service_id: String,
pub route_id: String,
pub stop_times: Vec<StopTime>,
pub shape_id: Option<String>,
pub trip_headsign: Option<String>,
pub trip_short_name: Option<String>,
pub direction_id: Option<DirectionType>,
pub block_id: Option<String>,
pub wheelchair_accessible: Availability,
pub bikes_allowed: BikesAllowedType,
pub frequencies: Vec<Frequency>,
}
impl Type for Trip {
fn object_type(&self) -> ObjectType {
ObjectType::Trip
}
}
impl Id for Trip {
fn id(&self) -> &str {
&self.id
}
}
impl fmt::Display for Trip {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"route id: {}, service id: {}",
self.route_id, self.service_id
)
}
}
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
pub struct Agency {
#[serde(rename = "agency_id")]
pub id: Option<String>,
#[serde(rename = "agency_name")]
pub name: String,
#[serde(rename = "agency_url")]
pub url: String,
#[serde(rename = "agency_timezone")]
pub timezone: String,
#[serde(rename = "agency_lang")]
pub lang: Option<String>,
#[serde(rename = "agency_phone")]
pub phone: Option<String>,
#[serde(rename = "agency_fare_url")]
pub fare_url: Option<String>,
#[serde(rename = "agency_email")]
pub email: Option<String>,
}
impl Type for Agency {
fn object_type(&self) -> ObjectType {
ObjectType::Agency
}
}
impl Id for Agency {
fn id(&self) -> &str {
match &self.id {
None => "",
Some(id) => id,
}
}
}
impl fmt::Display for Agency {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.name)
}
}
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
pub struct Shape {
#[serde(rename = "shape_id")]
pub id: String,
#[serde(rename = "shape_pt_lat", default)]
pub latitude: f64,
#[serde(rename = "shape_pt_lon", default)]
pub longitude: f64,
#[serde(rename = "shape_pt_sequence")]
pub sequence: usize,
#[serde(rename = "shape_dist_traveled")]
pub dist_traveled: Option<f32>,
}
impl Type for Shape {
fn object_type(&self) -> ObjectType {
ObjectType::Shape
}
}
impl Id for Shape {
fn id(&self) -> &str {
&self.id
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct FareAttribute {
#[serde(rename = "fare_id")]
pub id: String,
pub price: String,
#[serde(rename = "currency_type")]
pub currency: String,
pub payment_method: PaymentMethod,
pub transfers: Transfers,
pub agency_id: Option<String>,
pub transfer_duration: Option<usize>,
}
impl Id for FareAttribute {
fn id(&self) -> &str {
&self.id
}
}
impl Type for FareAttribute {
fn object_type(&self) -> ObjectType {
ObjectType::Fare
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct FareProduct {
#[serde(rename = "fare_product_id")]
pub id: String,
#[serde(rename = "fare_product_name")]
pub name: Option<String>,
pub rider_category_id: Option<String>,
pub fare_media_id: Option<String>,
pub amount: String,
pub currency: String,
}
impl Id for FareProduct {
fn id(&self) -> &str {
&self.id
}
}
impl Type for FareProduct {
fn object_type(&self) -> ObjectType {
ObjectType::Fare
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct FareMedia {
#[serde(rename = "fare_media_id")]
pub id: String,
#[serde(rename = "fare_media_name")]
pub name: Option<String>,
#[serde(rename = "fare_media_type")]
pub media_type: FareMediaType,
}
impl Id for FareMedia {
fn id(&self) -> &str {
&self.id
}
}
impl Type for FareMedia {
fn object_type(&self) -> ObjectType {
ObjectType::Fare
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct RiderCategory {
#[serde(rename = "rider_category_id")]
pub id: String,
#[serde(rename = "rider_category_name")]
pub name: String,
pub is_default_fare_category: DefaultFareCategory,
pub eligibility_url: Option<String>,
}
impl Id for RiderCategory {
fn id(&self) -> &str {
&self.id
}
}
impl Type for RiderCategory {
fn object_type(&self) -> ObjectType {
ObjectType::Fare
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct FareRule {
pub fare_id: String,
pub route_id: Option<String>,
pub origin_id: Option<String>,
pub destination_id: Option<String>,
pub contains_id: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
pub struct RawFrequency {
pub trip_id: String,
#[serde(
deserialize_with = "deserialize_time",
serialize_with = "serialize_time"
)]
pub start_time: u32,
#[serde(
deserialize_with = "deserialize_time",
serialize_with = "serialize_time"
)]
pub end_time: u32,
pub headway_secs: u32,
pub exact_times: Option<ExactTimes>,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct Frequency {
pub start_time: u32,
pub end_time: u32,
pub headway_secs: u32,
pub exact_times: Option<ExactTimes>,
}
impl Frequency {
pub fn from(frequency: &RawFrequency) -> Self {
Self {
start_time: frequency.start_time,
end_time: frequency.end_time,
headway_secs: frequency.headway_secs,
exact_times: frequency.exact_times,
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
pub struct RawTransfer {
pub from_stop_id: String,
pub to_stop_id: String,
pub transfer_type: TransferType,
pub min_transfer_time: Option<u32>,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct StopTransfer {
pub to_stop_id: String,
pub transfer_type: TransferType,
pub min_transfer_time: Option<u32>,
}
impl From<RawTransfer> for StopTransfer {
fn from(transfer: RawTransfer) -> Self {
Self {
to_stop_id: transfer.to_stop_id,
transfer_type: transfer.transfer_type,
min_transfer_time: transfer.min_transfer_time,
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
pub struct FeedInfo {
#[serde(rename = "feed_publisher_name")]
pub name: String,
#[serde(rename = "feed_publisher_url")]
pub url: String,
#[serde(rename = "feed_lang")]
pub lang: String,
pub default_lang: Option<String>,
#[serde(
deserialize_with = "deserialize_option_date",
serialize_with = "serialize_option_date",
rename = "feed_start_date",
default
)]
pub start_date: Option<NaiveDate>,
#[serde(
deserialize_with = "deserialize_option_date",
serialize_with = "serialize_option_date",
rename = "feed_end_date",
default
)]
pub end_date: Option<NaiveDate>,
#[serde(rename = "feed_version")]
pub version: Option<String>,
#[serde(rename = "feed_contact_email")]
pub contact_email: Option<String>,
#[serde(rename = "feed_contact_url")]
pub contact_url: Option<String>,
}
impl fmt::Display for FeedInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.name)
}
}
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
pub struct RawPathway {
#[serde(rename = "pathway_id")]
pub id: String,
pub from_stop_id: String,
pub to_stop_id: String,
#[serde(rename = "pathway_mode")]
pub mode: PathwayMode,
pub is_bidirectional: PathwayDirectionType,
pub length: Option<f32>,
pub traversal_time: Option<u32>,
pub stair_count: Option<i32>,
pub max_slope: Option<f32>,
pub min_width: Option<f32>,
pub signposted_as: Option<String>,
pub reversed_signposted_as: Option<String>,
}
impl Id for RawPathway {
fn id(&self) -> &str {
&self.id
}
}
impl Type for RawPathway {
fn object_type(&self) -> ObjectType {
ObjectType::Pathway
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct Pathway {
pub id: String,
pub to_stop_id: String,
pub mode: PathwayMode,
pub is_bidirectional: PathwayDirectionType,
pub length: Option<f32>,
pub traversal_time: Option<u32>,
pub stair_count: Option<i32>,
pub max_slope: Option<f32>,
pub min_width: Option<f32>,
pub signposted_as: Option<String>,
pub reversed_signposted_as: Option<String>,
}
impl Id for Pathway {
fn id(&self) -> &str {
&self.id
}
}
impl Type for Pathway {
fn object_type(&self) -> ObjectType {
ObjectType::Pathway
}
}
impl From<RawPathway> for Pathway {
fn from(raw: RawPathway) -> Self {
Self {
id: raw.id,
to_stop_id: raw.to_stop_id,
mode: raw.mode,
is_bidirectional: raw.is_bidirectional,
length: raw.length,
max_slope: raw.max_slope,
min_width: raw.min_width,
reversed_signposted_as: raw.reversed_signposted_as,
signposted_as: raw.signposted_as,
stair_count: raw.stair_count,
traversal_time: raw.traversal_time,
}
}
}
#[derive(Clone, Debug, Serialize, PartialEq)]
pub enum SourceFormat {
Directory,
Zip,
}