use std::convert::TryInto;
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Entity {
pub id: String,
pub trip_update: Option<TripUpdate>,
pub vehicle: Option<VehiclePosition>,
#[serde(default)]
pub is_deleted: bool,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct TripUpdate {
pub trip: TripDescriptor,
pub vehicle: Option<VehicleDescriptor>,
pub stop_time_update: Option<StopTimeUpdate>,
pub timestamp: Option<u64>,
pub delay: Option<i32>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct StopTimeUpdate {
pub stop_sequence: Option<u32>,
pub stop_id: Option<String>,
pub arrival: Option<StopTimeEvent>,
pub departure: Option<StopTimeEvent>,
#[serde(default)]
pub schedule_relationship: ScheduleRelationship,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct StopTimeEvent {
pub delay: Option<i32>,
pub time: Option<i64>,
pub uncertainty: Option<i32>,
}
#[derive(Debug, Serialize_repr, Deserialize_repr, Clone, Copy)]
#[repr(u8)]
pub enum ScheduleRelationship {
Scheduled = 0,
Skipped = 1,
NoData = 2,
}
impl Default for ScheduleRelationship {
fn default() -> Self {
Self::Scheduled
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct VehiclePosition {
pub trip: Option<TripDescriptor>,
pub vehicle: Option<VehicleDescriptor>,
pub position: Option<Position>,
pub current_stop_sequence: Option<u32>,
pub stop_id: Option<String>,
#[serde(default)]
pub current_status: VehicleStopStatus,
pub timestamp: Option<u64>,
pub congestion_level: Option<CongestionLevel>,
pub occupancy_status: Option<OccupancyStatus>,
}
#[derive(Debug, Serialize_repr, Deserialize_repr, Clone, Copy)]
#[repr(u8)]
pub enum VehicleStopStatus {
IncomingAt = 0,
StoppedAt = 1,
InTransitTo = 2,
}
impl Default for VehicleStopStatus {
fn default() -> Self {
Self::InTransitTo
}
}
#[derive(Debug, Serialize_repr, Deserialize_repr, Clone, Copy)]
#[repr(u8)]
pub enum CongestionLevel {
UnknownCongestionLevel = 0,
RunningSmoothly = 1,
StopAndGo = 2,
Congestion = 3,
SevereCongestion = 4,
}
#[derive(Debug, Serialize_repr, Deserialize_repr, Clone, Copy)]
#[repr(u8)]
pub enum OccupancyStatus {
Empty = 0,
ManySeatsAvailable = 1,
FewSeatsAvailable = 2,
StandingRoomOnly = 3,
CrushedStandingRoomOnly = 4,
Full = 5,
NotAcceptingPassengers = 6,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Position {
pub latitude: f32,
pub longitude: f32,
#[serde(default)]
#[serde(deserialize_with = "deserialize_bearing")]
pub bearing: Option<f32>,
pub odometer: Option<f64>,
pub speed: Option<f32>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct TripDescriptor {
pub trip_id: Option<String>,
pub route_id: Option<String>,
pub direction_id: Option<u32>,
pub start_time: Option<String>,
pub start_date: Option<String>,
pub schedule_relationship: Option<ScheduleRelationshipTripDescriptor>,
}
#[derive(Debug, Serialize_repr, Deserialize_repr, Clone, Copy)]
#[repr(u8)]
pub enum ScheduleRelationshipTripDescriptor {
Scheduled = 0,
Added = 1,
Unscheduled = 2,
Cancelled = 3,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct VehicleDescriptor {
pub id: Option<String>,
pub label: Option<String>,
pub license_plate: Option<String>,
}
impl Entity {
pub fn trip_id(&self) -> Option<String> {
Self::substr_to_char(self.trip_update.as_ref()?.trip.trip_id.as_ref()?, '-')
}
pub fn route_id(&self) -> Option<String> {
Self::substr_to_char(self.trip_update.as_ref()?.trip.route_id.as_ref()?, '-')
}
pub fn stop_id(&self) -> Option<String> {
Self::substr_to_char(
self.trip_update
.as_ref()?
.stop_time_update
.as_ref()?
.stop_id
.as_ref()?,
'-',
)
}
#[inline]
fn substr_to_char<T: AsRef<str>>(str: T, c: char) -> Option<String> {
let str = str.as_ref();
Some(str.chars().take(str.find(c)?).collect())
}
}
pub fn deserialize_bearing<'de, D>(deserializer: D) -> std::result::Result<Option<f32>, D::Error>
where
D: serde::Deserializer<'de>,
{
struct Bearing;
impl<'de> serde::de::Visitor<'de> for Bearing {
type Value = f32;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("float, integer or string")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
v.parse().map_err(serde::de::Error::custom)
}
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_str(&v)
}
fn visit_f32<E>(self, v: f32) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(v)
}
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
let v: i16 = v.try_into().map_err(serde::de::Error::custom)?;
Ok(v.into())
}
}
Ok(deserializer.deserialize_any(Bearing).ok())
}