diff options
Diffstat (limited to '')
-rw-r--r-- | src/types.rs | 260 |
1 files changed, 132 insertions, 128 deletions
diff --git a/src/types.rs b/src/types.rs index f4947e2..22ba077 100644 --- a/src/types.rs +++ b/src/types.rs @@ -8,181 +8,185 @@ use crate::serde::*; #[derive(Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct Station { - name: String, - ds100: String, - uic: u64, - latitude: f64, - longitude: f64, - #[serde(deserialize_with = "naive_read_unixtime")] - scheduled_time: DateTime<Utc>, - #[serde(deserialize_with = "naive_read_unixtime")] - real_time: DateTime<Utc>, + name: String, + ds100: String, + uic: u64, + latitude: f64, + longitude: f64, + #[serde(deserialize_with = "naive_read_unixtime")] + scheduled_time: DateTime<Utc>, + #[serde(deserialize_with = "naive_read_unixtime")] + real_time: DateTime<Utc> } pub fn parse_optional_station<'de, D>(d: D) -> Result<Option<Station>, D::Error> where - D: Deserializer<'de>, + D: Deserializer<'de> { - let val = <serde_json::Value>::deserialize(d)?; - match serde_json::from_value(val) { - Ok(station) => Ok(Some(station)), - Err(_) => Ok(None), - } + let val = <serde_json::Value>::deserialize(d)?; + match serde_json::from_value(val) { + Ok(station) => Ok(Some(station)), + Err(_) => Ok(None) + } } #[derive(Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct Stop { - name: String, - #[serde(deserialize_with = "option_naive_read_unixtime")] - scheduled_arrival: Option<DateTime<Utc>>, - #[serde(deserialize_with = "option_naive_read_unixtime")] - real_arrival: Option<DateTime<Utc>>, - #[serde(deserialize_with = "option_naive_read_unixtime")] - scheduled_departure: Option<DateTime<Utc>>, - #[serde(deserialize_with = "option_naive_read_unixtime")] - real_departure: Option<DateTime<Utc>>, + name: String, + #[serde(deserialize_with = "option_naive_read_unixtime")] + scheduled_arrival: Option<DateTime<Utc>>, + #[serde(deserialize_with = "option_naive_read_unixtime")] + real_arrival: Option<DateTime<Utc>>, + #[serde(deserialize_with = "option_naive_read_unixtime")] + scheduled_departure: Option<DateTime<Utc>>, + #[serde(deserialize_with = "option_naive_read_unixtime")] + real_departure: Option<DateTime<Utc>> } pub trait IsStation { - fn name(&self) -> &str; - fn scheduled_arrival(&self) -> Option<&DateTime<Utc>>; - fn real_arrival(&self) -> Option<&DateTime<Utc>>; - fn ds100(&self) -> &str; - - fn to_fancy_string(&self) -> String { - format!( - "{} {} – {} ({})", - self.real_arrival() // chrono's API for timezones is expressive, but reads like c++ … - .map(|t| <DateTime<Local>>::from(*t).time().to_string()) - .unwrap_or("??:??:??".to_string()) - .blue(), - { - let delay = match (self.real_arrival(), self.scheduled_arrival()) { - (Some(a), Some(s)) => (a.time() - s.time()).num_minutes(), - _ => 0, - }; - let text = format!("({:+})", delay); - if delay > 0 { - text.red() - } else { - text.green() - } - }, - self.ds100().red(), - self.name() - ) - } + fn name(&self) -> &str; + fn scheduled_arrival(&self) -> Option<&DateTime<Utc>>; + fn real_arrival(&self) -> Option<&DateTime<Utc>>; + fn ds100(&self) -> &str; + + fn to_fancy_string(&self) -> String { + format!( + "{} {} – {} ({})", + self + .real_arrival() // chrono's API for timezones is expressive, but reads like c++ … + .map(|t| <DateTime<Local>>::from(*t).time().to_string()) + .unwrap_or("??:??:??".to_string()) + .blue(), + { + let delay = match (self.real_arrival(), self.scheduled_arrival()) { + (Some(a), Some(s)) => (a.time() - s.time()).num_minutes(), + _ => 0 + }; + let text = format!("({:+})", delay); + if delay > 0 { + text.red() + } else { + text.green() + } + }, + self.ds100().red(), + self.name() + ) + } } impl IsStation for Station { - fn name(&self) -> &str { - &self.name - } - fn scheduled_arrival(&self) -> Option<&DateTime<Utc>> { - Some(&self.scheduled_time) - } - fn real_arrival(&self) -> Option<&DateTime<Utc>> { - Some(&self.real_time) - } - - fn ds100(&self) -> &str { - &self.ds100 - } + fn name(&self) -> &str { + &self.name + } + fn scheduled_arrival(&self) -> Option<&DateTime<Utc>> { + Some(&self.scheduled_time) + } + fn real_arrival(&self) -> Option<&DateTime<Utc>> { + Some(&self.real_time) + } + + fn ds100(&self) -> &str { + &self.ds100 + } } impl IsStation for Stop { - fn name(&self) -> &str { - &self.name - } - fn scheduled_arrival(&self) -> Option<&DateTime<Utc>> { - self.scheduled_arrival.as_ref() - } - fn real_arrival(&self) -> Option<&DateTime<Utc>> { - self.real_arrival.as_ref() - } - - fn ds100(&self) -> &str { - "[??]" - } + fn name(&self) -> &str { + &self.name + } + fn scheduled_arrival(&self) -> Option<&DateTime<Utc>> { + self.scheduled_arrival.as_ref() + } + fn real_arrival(&self) -> Option<&DateTime<Utc>> { + self.real_arrival.as_ref() + } + + fn ds100(&self) -> &str { + "[??]" + } } #[derive(Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct Train { - #[serde(rename = "type")] - _type: String, - line: Option<String>, - no: String, - id: String, + #[serde(rename = "type")] + _type: String, + line: Option<String>, + no: String, + id: String } #[derive(Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct Status { - deprecated: bool, - checked_in: bool, - from_station: Station, - #[serde(deserialize_with = "parse_optional_station")] - pub to_station: Option<Station>, - intermediate_stops: Vec<Stop>, - train: Option<Train>, - action_time: u64, + deprecated: bool, + checked_in: bool, + from_station: Station, + #[serde(deserialize_with = "parse_optional_station")] + pub to_station: Option<Station>, + intermediate_stops: Vec<Stop>, + train: Option<Train>, + action_time: u64 } #[allow(dead_code)] pub struct Ds100 { - inner: String, + inner: String } pub struct Trip<'a, S: IsStation>(pub &'a Vec<S>); impl std::fmt::Display for Train { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{} {}", self._type, self.no) - } + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{} {}", self._type, self.no) + } } #[allow(unstable_name_collisions)] impl<S: IsStation> std::fmt::Display for Trip<'_, S> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if self.0.len() != 0 { - self.0 - .iter() - .map(|stop| stop.to_fancy_string()) - // .intersperse(" ↓".to_string()) - .for_each(|l| writeln!(f, " {}\n ↓", l).unwrap()); - } - Ok(()) + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if self.0.len() != 0 { + self + .0 + .iter() + .map(|stop| stop.to_fancy_string()) + // .intersperse(" ↓".to_string()) + .for_each(|l| writeln!(f, " {}\n ↓", l).unwrap()); } + Ok(()) + } } impl std::fmt::Display for Status { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self.checked_in { - false => write!( - f, - "not checked in. \n\n\ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.checked_in { + false => write!( + f, + "not checked in. \n\n\ last trip: \n {} {}", - self.from_station.to_fancy_string(), - self.to_station.as_ref().unwrap().to_fancy_string() - ), - true => write!( - f, - "checked in to: {}.\n\n\ + self.from_station.to_fancy_string(), + self.to_station.as_ref().unwrap().to_fancy_string() + ), + true => write!( + f, + "checked in to: {}.\n\n\ stops:\n {}\n ↓\n{} {}", - self.train - .as_ref() - .map(|t| t.to_string()) - .unwrap_or("".to_string()) - .green(), - self.from_station.to_fancy_string(), - Trip(&self.intermediate_stops), - self.to_station - .as_ref() - .map(|s| s.to_fancy_string()) - .unwrap_or_else(|| "🚄 Fahrt ins Blaue".blue().to_string()) - ), - } + self + .train + .as_ref() + .map(|t| t.to_string()) + .unwrap_or("".to_string()) + .green(), + self.from_station.to_fancy_string(), + Trip(&self.intermediate_stops), + self + .to_station + .as_ref() + .map(|s| s.to_fancy_string()) + .unwrap_or_else(|| "🚄 Fahrt ins Blaue".blue().to_string()) + ) } + } } |