1use crate::error::EveryMapResult;
2use crate::types::Coordinate;
3use async_trait::async_trait;
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Default, Serialize, Deserialize)]
8pub struct TrafficOptions {
9 pub radius: Option<f64>,
11 pub language: Option<String>,
13 pub include_incidents: Option<bool>,
15 #[serde(default, skip_serializing_if = "Option::is_none")]
17 pub provider_extra: Option<serde_json::Value>,
18}
19
20#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
22pub enum IncidentSeverity {
23 Low,
24 Minor,
25 Moderate,
26 Major,
27 Critical,
28 Unknown,
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct TrafficIncident {
34 pub id: Option<String>,
36 pub incident_type: Option<String>,
38 pub severity: Option<IncidentSeverity>,
40 pub description: Option<String>,
42 pub road_name: Option<String>,
44 pub start_time: Option<String>,
46 pub end_time: Option<String>,
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
52pub struct TrafficFlow {
53 pub speed: Option<f64>,
55 pub free_flow_speed: Option<f64>,
57 pub jam_factor: Option<f64>,
59 pub confidence: Option<f64>,
61 pub road_name: Option<String>,
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct TrafficResponse {
68 pub flows: Vec<TrafficFlow>,
70 pub incidents: Vec<TrafficIncident>,
72 #[serde(default, skip_serializing_if = "Option::is_none")]
74 pub raw: Option<serde_json::Value>,
75}
76
77#[async_trait]
78pub trait TrafficProvider: Send + Sync {
79 async fn get_traffic(
80 &self,
81 location: &Coordinate,
82 options: &TrafficOptions,
83 ) -> EveryMapResult<TrafficResponse>;
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 #[test]
91 fn test_traffic_options_default() {
92 let options = TrafficOptions::default();
93 assert!(options.radius.is_none());
94 assert!(options.language.is_none());
95 assert!(options.include_incidents.is_none());
96 assert!(options.provider_extra.is_none());
97 }
98
99 #[test]
100 fn test_incident_severity_serialization() {
101 assert_eq!(
102 serde_json::to_string(&IncidentSeverity::Critical).unwrap(),
103 "\"Critical\""
104 );
105 let sev: IncidentSeverity = serde_json::from_str("\"Minor\"").unwrap();
106 assert_eq!(sev, IncidentSeverity::Minor);
107 assert_eq!(
108 serde_json::to_string(&IncidentSeverity::Moderate).unwrap(),
109 "\"Moderate\""
110 );
111 let moderate: IncidentSeverity = serde_json::from_str("\"Moderate\"").unwrap();
112 assert_eq!(moderate, IncidentSeverity::Moderate);
113 }
114
115 #[test]
116 fn test_traffic_flow_construction() {
117 let flow = TrafficFlow {
118 speed: Some(80.0),
119 free_flow_speed: Some(100.0),
120 jam_factor: Some(3.5),
121 confidence: Some(0.9),
122 road_name: Some("A100".to_string()),
123 };
124 assert_eq!(flow.speed, Some(80.0));
125 assert_eq!(flow.jam_factor, Some(3.5));
126 assert_eq!(flow.road_name.as_deref(), Some("A100"));
127 }
128
129 #[test]
130 fn test_traffic_response_construction() {
131 let response = TrafficResponse {
132 flows: vec![TrafficFlow {
133 speed: Some(60.0),
134 free_flow_speed: Some(100.0),
135 jam_factor: Some(5.0),
136 confidence: Some(0.85),
137 road_name: None,
138 }],
139 incidents: vec![],
140 raw: None,
141 };
142 assert_eq!(response.flows.len(), 1);
143 assert!(response.incidents.is_empty());
144 }
145
146 #[test]
149 fn test_incident_severity_all_variants_serde() {
150 let variants = [
151 IncidentSeverity::Low,
152 IncidentSeverity::Minor,
153 IncidentSeverity::Major,
154 IncidentSeverity::Critical,
155 IncidentSeverity::Unknown,
156 ];
157 for v in &variants {
158 let json = serde_json::to_string(v).unwrap();
159 let back: IncidentSeverity = serde_json::from_str(&json).unwrap();
160 assert_eq!(*v, back, "Failed roundtrip for {:?}", v);
161 }
162 }
163
164 #[test]
165 fn test_incident_severity_all_variants_distinct() {
166 let variants = [
167 IncidentSeverity::Low,
168 IncidentSeverity::Minor,
169 IncidentSeverity::Major,
170 IncidentSeverity::Critical,
171 IncidentSeverity::Unknown,
172 ];
173 for i in 0..variants.len() {
174 for j in 0..variants.len() {
175 if i != j {
176 assert_ne!(variants[i], variants[j]);
177 }
178 }
179 }
180 }
181
182 #[test]
185 fn test_traffic_response_serde_roundtrip() {
186 let response = TrafficResponse {
187 flows: vec![TrafficFlow {
188 speed: Some(80.0),
189 free_flow_speed: Some(120.0),
190 jam_factor: Some(2.5),
191 confidence: Some(0.9),
192 road_name: Some("A9".to_string()),
193 }],
194 incidents: vec![TrafficIncident {
195 id: Some("inc-1".to_string()),
196 incident_type: Some("accident".to_string()),
197 severity: Some(IncidentSeverity::Major),
198 description: Some("Multi-vehicle accident".to_string()),
199 road_name: Some("A9".to_string()),
200 start_time: Some("2024-01-01T08:00:00".to_string()),
201 end_time: Some("2024-01-01T12:00:00".to_string()),
202 }],
203 raw: Some(serde_json::json!({"source": "here"})),
204 };
205 let json = serde_json::to_string(&response).unwrap();
206 let back: TrafficResponse = serde_json::from_str(&json).unwrap();
207 assert_eq!(back.flows.len(), 1);
208 assert_eq!(back.incidents.len(), 1);
209 assert_eq!(back.incidents[0].severity, Some(IncidentSeverity::Major));
210 assert!(back.raw.is_some());
211 }
212
213 #[test]
214 fn test_traffic_response_empty() {
215 let response = TrafficResponse {
216 flows: vec![],
217 incidents: vec![],
218 raw: None,
219 };
220 let json = serde_json::to_string(&response).unwrap();
221 let back: TrafficResponse = serde_json::from_str(&json).unwrap();
222 assert!(back.flows.is_empty());
223 assert!(back.incidents.is_empty());
224 }
225
226 #[test]
229 fn test_traffic_options_serde_roundtrip() {
230 let options = TrafficOptions {
231 radius: Some(5000.0),
232 language: Some("de".to_string()),
233 include_incidents: Some(true),
234 provider_extra: Some(serde_json::json!({"min_jam_factor": 4.0})),
235 };
236 let json = serde_json::to_string(&options).unwrap();
237 let back: TrafficOptions = serde_json::from_str(&json).unwrap();
238 assert_eq!(back.radius, Some(5000.0));
239 assert_eq!(back.include_incidents, Some(true));
240 assert!(back.provider_extra.is_some());
241 }
242
243 #[test]
246 fn test_traffic_incident_serde_roundtrip() {
247 let incident = TrafficIncident {
248 id: Some("inc-42".to_string()),
249 incident_type: Some("construction".to_string()),
250 severity: Some(IncidentSeverity::Minor),
251 description: Some("Road work, lane closed".to_string()),
252 road_name: Some("B96".to_string()),
253 start_time: Some("2024-03-01T06:00:00".to_string()),
254 end_time: Some("2024-09-01T18:00:00".to_string()),
255 };
256 let json = serde_json::to_string(&incident).unwrap();
257 let back: TrafficIncident = serde_json::from_str(&json).unwrap();
258 assert_eq!(back.id, incident.id);
259 assert_eq!(back.severity, incident.severity);
260 assert_eq!(back.description, incident.description);
261 }
262
263 #[test]
266 fn test_traffic_flow_serde_roundtrip() {
267 let flow = TrafficFlow {
268 speed: Some(0.0),
269 free_flow_speed: Some(100.0),
270 jam_factor: Some(10.0),
271 confidence: Some(0.5),
272 road_name: Some("A100".to_string()),
273 };
274 let json = serde_json::to_string(&flow).unwrap();
275 let back: TrafficFlow = serde_json::from_str(&json).unwrap();
276 assert_eq!(back.speed, Some(0.0));
277 assert_eq!(back.jam_factor, Some(10.0));
278 }
279
280 #[test]
283 fn test_traffic_flow_gridlock() {
284 let flow = TrafficFlow {
285 speed: Some(0.0),
286 free_flow_speed: Some(100.0),
287 jam_factor: Some(10.0),
288 confidence: Some(1.0),
289 road_name: None,
290 };
291 assert_eq!(flow.speed, Some(0.0));
292 assert_eq!(flow.jam_factor, Some(10.0));
293 }
294
295 #[test]
296 fn test_traffic_incident_all_none_optional_fields() {
297 let incident = TrafficIncident {
298 id: None,
299 incident_type: None,
300 severity: None,
301 description: None,
302 road_name: None,
303 start_time: None,
304 end_time: None,
305 };
306 assert!(incident.id.is_none());
307 assert!(incident.severity.is_none());
308 }
309}