at_api_rs/types/
gtfs.rs

1//! Standardised GTFS types which are returned from the Auckland Transport API.
2
3use std::convert::TryInto;
4
5use serde::{Deserialize, Serialize};
6use serde_repr::{Deserialize_repr, Serialize_repr};
7
8#[derive(Debug, Serialize, Deserialize, Clone)]
9pub struct Entity {
10    pub id: String,
11    pub trip_update: Option<TripUpdate>,
12    pub vehicle: Option<VehiclePosition>,
13    #[serde(default)]
14    pub is_deleted: bool,
15    // pub alert: Option<Alert>, // unused by AT
16}
17
18#[derive(Debug, Serialize, Deserialize, Clone)]
19pub struct TripUpdate {
20    pub trip: TripDescriptor,
21    pub vehicle: Option<VehicleDescriptor>,
22    pub stop_time_update: Option<StopTimeUpdate>,
23    pub timestamp: Option<u64>,
24    pub delay: Option<i32>,
25}
26
27#[derive(Debug, Serialize, Deserialize, Clone)]
28pub struct StopTimeUpdate {
29    pub stop_sequence: Option<u32>,
30    pub stop_id: Option<String>,
31    pub arrival: Option<StopTimeEvent>,
32    pub departure: Option<StopTimeEvent>,
33    #[serde(default)]
34    pub schedule_relationship: ScheduleRelationship,
35}
36
37#[derive(Debug, Serialize, Deserialize, Clone)]
38pub struct StopTimeEvent {
39    pub delay: Option<i32>,
40    pub time: Option<i64>,
41    pub uncertainty: Option<i32>,
42}
43
44#[derive(Debug, Serialize_repr, Deserialize_repr, Clone, Copy)]
45#[repr(u8)]
46pub enum ScheduleRelationship {
47    Scheduled = 0,
48    Skipped = 1,
49    NoData = 2,
50}
51
52impl Default for ScheduleRelationship {
53    fn default() -> Self {
54        Self::Scheduled
55    }
56}
57
58#[derive(Debug, Serialize, Deserialize, Clone)]
59pub struct VehiclePosition {
60    pub trip: Option<TripDescriptor>,
61    pub vehicle: Option<VehicleDescriptor>,
62    pub position: Option<Position>,
63    pub current_stop_sequence: Option<u32>,
64    pub stop_id: Option<String>,
65    #[serde(default)]
66    pub current_status: VehicleStopStatus,
67    pub timestamp: Option<u64>,
68    pub congestion_level: Option<CongestionLevel>,
69    pub occupancy_status: Option<OccupancyStatus>,
70}
71
72#[derive(Debug, Serialize_repr, Deserialize_repr, Clone, Copy)]
73#[repr(u8)]
74pub enum VehicleStopStatus {
75    // The vehicle is just about to arrive at the stop (on a stop display, the vehicle symbol
76    // typically flashes).
77    IncomingAt = 0,
78
79    // The vehicle is standing at the stop.
80    StoppedAt = 1,
81
82    // The vehicle has departed and is in transit to the next stop.
83    InTransitTo = 2,
84}
85
86impl Default for VehicleStopStatus {
87    fn default() -> Self {
88        Self::InTransitTo
89    }
90}
91
92#[derive(Debug, Serialize_repr, Deserialize_repr, Clone, Copy)]
93#[repr(u8)]
94pub enum CongestionLevel {
95    UnknownCongestionLevel = 0,
96    RunningSmoothly = 1,
97    StopAndGo = 2,
98    Congestion = 3,
99    SevereCongestion = 4,
100}
101
102#[derive(Debug, Serialize_repr, Deserialize_repr, Clone, Copy)]
103#[repr(u8)]
104pub enum OccupancyStatus {
105    Empty = 0,
106    ManySeatsAvailable = 1,
107    FewSeatsAvailable = 2,
108    StandingRoomOnly = 3,
109    CrushedStandingRoomOnly = 4,
110    Full = 5,
111    NotAcceptingPassengers = 6,
112}
113
114#[derive(Debug, Serialize, Deserialize, Clone)]
115pub struct Position {
116    pub latitude: f32,
117    pub longitude: f32,
118    #[serde(default)]
119    #[serde(deserialize_with = "deserialize_bearing")]
120    pub bearing: Option<f32>,
121    pub odometer: Option<f64>,
122    pub speed: Option<f32>,
123}
124
125#[derive(Debug, Serialize, Deserialize, Clone)]
126pub struct TripDescriptor {
127    pub trip_id: Option<String>,
128    pub route_id: Option<String>,
129    pub direction_id: Option<u32>,
130    pub start_time: Option<String>,
131    pub start_date: Option<String>,
132    pub schedule_relationship: Option<ScheduleRelationshipTripDescriptor>,
133}
134
135#[derive(Debug, Serialize_repr, Deserialize_repr, Clone, Copy)]
136#[repr(u8)]
137pub enum ScheduleRelationshipTripDescriptor {
138    Scheduled = 0,
139    Added = 1,
140    Unscheduled = 2,
141    Cancelled = 3,
142}
143
144#[derive(Debug, Serialize, Deserialize, Clone)]
145pub struct VehicleDescriptor {
146    pub id: Option<String>,
147    pub label: Option<String>,
148    pub license_plate: Option<String>,
149}
150
151impl Entity {
152    /// Returns the trip ID with the GTFS version truncated.
153    pub fn trip_id(&self) -> Option<String> {
154        Self::substr_to_char(self.trip_update.as_ref()?.trip.trip_id.as_ref()?, '-')
155    }
156
157    /// Returns the route ID with the GTFS version truncated.
158    pub fn route_id(&self) -> Option<String> {
159        Self::substr_to_char(self.trip_update.as_ref()?.trip.route_id.as_ref()?, '-')
160    }
161
162    /// Returns the current stop ID with the GTFS version truncated.
163    pub fn stop_id(&self) -> Option<String> {
164        Self::substr_to_char(
165            self.trip_update
166                .as_ref()?
167                .stop_time_update
168                .as_ref()?
169                .stop_id
170                .as_ref()?,
171            '-',
172        )
173    }
174
175    #[inline]
176    fn substr_to_char<T: AsRef<str>>(str: T, c: char) -> Option<String> {
177        let str = str.as_ref();
178        Some(str.chars().take(str.find(c)?).collect())
179    }
180}
181
182/// Serialize, Deserializes a bearing which is sent in the realtime GTFS output from Auckland Transport.
183/// Requires a seperate deserialization function due to AT sending a float, integer, string or
184/// nothing for this field.
185pub fn deserialize_bearing<'de, D>(deserializer: D) -> std::result::Result<Option<f32>, D::Error>
186where
187    D: serde::Deserializer<'de>,
188{
189    struct Bearing;
190
191    impl<'de> serde::de::Visitor<'de> for Bearing {
192        type Value = f32;
193
194        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
195            formatter.write_str("float, integer or string")
196        }
197
198        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
199        where
200            E: serde::de::Error,
201        {
202            v.parse().map_err(serde::de::Error::custom)
203        }
204
205        fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
206        where
207            E: serde::de::Error,
208        {
209            self.visit_str(&v)
210        }
211
212        fn visit_f32<E>(self, v: f32) -> Result<Self::Value, E>
213        where
214            E: serde::de::Error,
215        {
216            Ok(v)
217        }
218
219        fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
220        where
221            E: serde::de::Error,
222        {
223            let v: i16 = v.try_into().map_err(serde::de::Error::custom)?;
224            Ok(v.into())
225        }
226    }
227
228    Ok(deserializer.deserialize_any(Bearing).ok())
229}