Skip to main content

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}