traci_rs/types.rs
1// SPDX-License-Identifier: EPL-2.0
2//! Data structures and the [`TraciValue`] enum — translation of `libsumo/TraCIDefs.h`.
3//!
4//! In the C++ library subscription results are stored as
5//! `map<int, shared_ptr<TraCIResult>>` using runtime polymorphism. Here we use an
6//! **enum** variant approach: every concrete result type is a variant of
7//! [`TraciValue`]. This is zero-cost, exhaustively matchable, and idiomatic Rust.
8
9use std::collections::HashMap;
10use crate::constants::INVALID_DOUBLE_VALUE;
11
12// ============================================================================
13// TraciValue — the central enum replacing C++ shared_ptr<TraCIResult>
14// ============================================================================
15
16/// Every value that can be received from or sent to a SUMO TraCI server.
17///
18/// Variants map 1-to-1 to the TraCI `TYPE_*` / `POSITION_*` tags. Where the
19/// C++ library had specialised wrapper structs (e.g. `TraCILogicVectorWrapped`)
20/// they are folded directly into the corresponding variant here.
21#[derive(Debug, Clone, PartialEq)]
22pub enum TraciValue {
23 /// `TYPE_INTEGER` (0x09) — 32-bit signed integer.
24 Int(i32),
25 /// `TYPE_DOUBLE` (0x0b) — 64-bit IEEE 754 float.
26 Double(f64),
27 /// `TYPE_STRING` (0x0c).
28 String(String),
29 /// `TYPE_STRINGLIST` (0x0e).
30 StringList(Vec<String>),
31 /// `TYPE_DOUBLELIST` (0x10).
32 DoubleList(Vec<f64>),
33 /// `POSITION_2D` (0x01) — 2-D Cartesian position.
34 Pos2D { x: f64, y: f64 },
35 /// `POSITION_3D` (0x03) — 3-D Cartesian position.
36 Pos3D { x: f64, y: f64, z: f64 },
37 /// `TYPE_COLOR` (0x11) — RGBA colour.
38 Color(TraciColor),
39 /// `TYPE_POLYGON` (0x06) — list of 2-D positions.
40 Polygon(Vec<TraciPosition>),
41 /// A complete traffic-light program logic (`TL_COMPLETE_DEFINITION_RYG`).
42 LogicList(Vec<TraciLogic>),
43 /// A list of lane connections returned by `LANE_LINKS`.
44 ConnectionList(Vec<Vec<TraciConnection>>),
45 /// A `TraCIStage` structure (person stages, `FIND_ROUTE` result, …).
46 Stage(TraciStage),
47 /// Induction-loop per-vehicle data (`LAST_STEP_VEHICLE_DATA`).
48 VehicleDataList(Vec<TraciVehicleData>),
49 /// Upcoming traffic light data for a vehicle (`VAR_NEXT_TLS`).
50 NextTLSList(Vec<TraciNextTLSData>),
51 /// Best-lane information for a vehicle (`VAR_BEST_LANES`).
52 BestLanesList(Vec<TraciBestLanesData>),
53 /// A raw byte tag + bytes for forward-compatibility with unknown future types.
54 Unknown { type_id: u8, raw: Vec<u8> },
55}
56
57// ============================================================================
58// Subscription result type aliases
59// ============================================================================
60
61/// Per-object subscription results: `{ variable_id → value }`.
62pub type TraciResults = HashMap<u8, TraciValue>;
63
64/// All variable-subscription results: `{ object_id → TraciResults }`.
65pub type SubscriptionResults = HashMap<String, TraciResults>;
66
67/// All context-subscription results: `{ ego_object_id → SubscriptionResults }`.
68pub type ContextSubscriptionResults = HashMap<String, SubscriptionResults>;
69
70// ============================================================================
71// Position
72// ============================================================================
73
74/// A 2-D or 3-D position. For 2-D positions `z` is [`INVALID_DOUBLE_VALUE`].
75#[derive(Debug, Clone, PartialEq)]
76pub struct TraciPosition {
77 pub x: f64,
78 pub y: f64,
79 pub z: f64,
80}
81
82impl TraciPosition {
83 pub fn new_2d(x: f64, y: f64) -> Self {
84 Self { x, y, z: INVALID_DOUBLE_VALUE }
85 }
86
87 pub fn new_3d(x: f64, y: f64, z: f64) -> Self {
88 Self { x, y, z }
89 }
90
91 pub fn is_3d(&self) -> bool {
92 self.z != INVALID_DOUBLE_VALUE
93 }
94}
95
96impl Default for TraciPosition {
97 fn default() -> Self {
98 Self { x: INVALID_DOUBLE_VALUE, y: INVALID_DOUBLE_VALUE, z: INVALID_DOUBLE_VALUE }
99 }
100}
101
102// ============================================================================
103// Road position
104// ============================================================================
105
106/// A position on the road network (edge + lane + offset along edge).
107#[derive(Debug, Clone, PartialEq)]
108pub struct TraciRoadPosition {
109 pub edge_id: String,
110 pub pos: f64,
111 pub lane_index: i32,
112}
113
114// ============================================================================
115// Colour
116// ============================================================================
117
118/// An RGBA colour (each channel 0–255).
119#[derive(Debug, Clone, Copy, PartialEq, Eq)]
120pub struct TraciColor {
121 pub r: u8,
122 pub g: u8,
123 pub b: u8,
124 pub a: u8,
125}
126
127impl TraciColor {
128 pub fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
129 Self { r, g, b, a }
130 }
131}
132
133impl Default for TraciColor {
134 fn default() -> Self {
135 Self { r: 0, g: 0, b: 0, a: 255 }
136 }
137}
138
139// ============================================================================
140// Traffic light logic (phase programme)
141// ============================================================================
142
143/// One phase within a traffic light programme.
144#[derive(Debug, Clone, PartialEq)]
145pub struct TraciPhase {
146 pub duration: f64,
147 pub state: String,
148 pub min_dur: f64,
149 pub max_dur: f64,
150 pub next: Vec<i32>,
151 pub name: String,
152}
153
154impl Default for TraciPhase {
155 fn default() -> Self {
156 Self {
157 duration: INVALID_DOUBLE_VALUE,
158 state: String::new(),
159 min_dur: INVALID_DOUBLE_VALUE,
160 max_dur: INVALID_DOUBLE_VALUE,
161 next: Vec::new(),
162 name: String::new(),
163 }
164 }
165}
166
167/// A complete traffic-light programme.
168#[derive(Debug, Clone, PartialEq)]
169pub struct TraciLogic {
170 pub program_id: String,
171 /// Programme type (0 = static, 3 = actuated, …).
172 pub type_: i32,
173 pub current_phase_index: i32,
174 pub phases: Vec<TraciPhase>,
175 pub sub_parameter: HashMap<String, String>,
176}
177
178// ============================================================================
179// Lane connections
180// ============================================================================
181
182/// One lane-to-lane connection (output of `LANE_LINKS`).
183#[derive(Debug, Clone, PartialEq)]
184pub struct TraciConnection {
185 pub approached_lane: String,
186 pub has_prio: bool,
187 pub is_open: bool,
188 pub has_foe: bool,
189 pub approached_internal: String,
190 pub state: String,
191 pub direction: String,
192 pub length: f64,
193}
194
195/// One lane-to-lane link (output of traffic-light controlled link queries).
196#[derive(Debug, Clone, PartialEq)]
197pub struct TraciLink {
198 pub from_lane: String,
199 pub via_lane: String,
200 pub to_lane: String,
201}
202
203// ============================================================================
204// Induction-loop vehicle data
205// ============================================================================
206
207/// Per-vehicle data from an induction-loop detector (`LAST_STEP_VEHICLE_DATA`).
208#[derive(Debug, Clone, PartialEq)]
209pub struct TraciVehicleData {
210 pub id: String,
211 pub length: f64,
212 pub entry_time: f64,
213 pub leave_time: f64,
214 pub type_id: String,
215}
216
217// ============================================================================
218// Upcoming traffic light data
219// ============================================================================
220
221/// One upcoming traffic light for a vehicle (`VAR_NEXT_TLS`).
222#[derive(Debug, Clone, PartialEq)]
223pub struct TraciNextTLSData {
224 pub id: String,
225 pub tl_index: i32,
226 pub dist: f64,
227 /// The current phase state character (e.g. `'r'`, `'g'`, `'y'`).
228 pub state: char,
229}
230
231// ============================================================================
232// Best-lanes data
233// ============================================================================
234
235/// Best-lane information for a vehicle (`VAR_BEST_LANES`).
236#[derive(Debug, Clone, PartialEq)]
237pub struct TraciBestLanesData {
238 pub lane_id: String,
239 pub length: f64,
240 pub occupation: f64,
241 pub best_lane_offset: i32,
242 pub allows_continuation: bool,
243 pub continuation_lanes: Vec<String>,
244}
245
246// ============================================================================
247// Stage (person journey stages / route finding)
248// ============================================================================
249
250/// A person journey stage, or a found route (`VAR_STAGE`, `FIND_ROUTE`).
251#[derive(Debug, Clone, PartialEq)]
252pub struct TraciStage {
253 pub type_: i32,
254 pub v_type: String,
255 pub line: String,
256 pub dest_stop: String,
257 pub edges: Vec<String>,
258 pub travel_time: f64,
259 pub cost: f64,
260 pub length: f64,
261 pub intended: String,
262 pub depart: f64,
263 pub depart_pos: f64,
264 pub arrival_pos: f64,
265 pub description: String,
266}
267
268impl Default for TraciStage {
269 fn default() -> Self {
270 Self {
271 type_: crate::constants::INVALID_INT_VALUE,
272 v_type: String::new(),
273 line: String::new(),
274 dest_stop: String::new(),
275 edges: Vec::new(),
276 travel_time: INVALID_DOUBLE_VALUE,
277 cost: INVALID_DOUBLE_VALUE,
278 length: INVALID_DOUBLE_VALUE,
279 intended: String::new(),
280 depart: INVALID_DOUBLE_VALUE,
281 depart_pos: INVALID_DOUBLE_VALUE,
282 arrival_pos: INVALID_DOUBLE_VALUE,
283 description: String::new(),
284 }
285 }
286}
287
288// ============================================================================
289// Next stop data
290// ============================================================================
291
292/// Detailed data for an upcoming or past vehicle stop.
293#[derive(Debug, Clone, PartialEq)]
294pub struct TraciNextStopData {
295 pub lane: String,
296 pub start_pos: f64,
297 pub end_pos: f64,
298 pub stopping_place_id: String,
299 pub stop_flags: i32,
300 pub duration: f64,
301 pub until: f64,
302 pub intended_arrival: f64,
303 pub arrival: f64,
304 pub depart: f64,
305 pub split: String,
306 pub join: String,
307 pub act_type: String,
308 pub trip_id: String,
309 pub line: String,
310 pub speed: f64,
311}
312
313// ============================================================================
314// Taxi reservation
315// ============================================================================
316
317/// A taxi reservation as returned by `VAR_TAXI_RESERVATIONS`.
318#[derive(Debug, Clone, PartialEq)]
319pub struct TraciReservation {
320 pub id: String,
321 pub persons: Vec<String>,
322 pub group: String,
323 pub from_edge: String,
324 pub to_edge: String,
325 pub depart_pos: f64,
326 pub arrival_pos: f64,
327 pub depart: f64,
328 pub reservation_time: f64,
329 pub state: i32,
330}
331
332// ============================================================================
333// Collision data
334// ============================================================================
335
336/// Data about a single collision event.
337#[derive(Debug, Clone, PartialEq)]
338pub struct TraciCollision {
339 pub collider: String,
340 pub victim: String,
341 pub collider_type: String,
342 pub victim_type: String,
343 pub collider_speed: f64,
344 pub victim_speed: f64,
345 pub type_: String,
346 pub lane: String,
347 pub pos: f64,
348}
349
350// ============================================================================
351// Signal constraint
352// ============================================================================
353
354/// A rail signal constraint.
355#[derive(Debug, Clone, PartialEq)]
356pub struct TraciSignalConstraint {
357 pub signal_id: String,
358 pub trip_id: String,
359 pub foe_id: String,
360 pub foe_signal: String,
361 pub limit: i32,
362 pub type_: i32,
363 pub must_wait: bool,
364 pub active: bool,
365 pub param: HashMap<String, String>,
366}
367
368// ============================================================================
369// SubscribedKinematics — populated by VehicleScope::subscribe_kinematics
370// ============================================================================
371
372/// Kinematic state for a vehicle, populated by `VehicleScope::subscribe_kinematics`.
373///
374/// All fields are updated automatically on every `simulation_step()` call once
375/// a subscription has been set up.
376#[derive(Debug, Clone, PartialEq)]
377pub struct SubscribedKinematics {
378 /// 2-D Cartesian position in the SUMO network coordinate system (metres).
379 pub position: TraciPosition,
380 /// Longitudinal speed (m/s).
381 pub speed: f64,
382 /// Longitudinal acceleration (m/s²). Positive = accelerating, negative = braking.
383 pub acceleration: f64,
384 /// Heading angle (degrees, 0 = North, clockwise).
385 pub angle: f64,
386}