maliput/api/rules/
mod.rs

1// BSD 3-Clause License
2//
3// Copyright (c) 2024, Woven by Toyota.
4// All rights reserved.
5//
6// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions are met:
8//
9// * Redistributions of source code must retain the above copyright notice, this
10//   list of conditions and the following disclaimer.
11//
12// * Redistributions in binary form must reproduce the above copyright notice,
13//   this list of conditions and the following disclaimer in the documentation
14//   and/or other materials provided with the distribution.
15//
16// * Neither the name of the copyright holder nor the names of its
17//   contributors may be used to endorse or promote products derived from
18//   this software without specific prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31use std::collections::HashMap;
32
33use crate::{api::RoadPosition, common::MaliputError};
34use strum_macros::{Display, IntoStaticStr};
35
36/// Interface for accessing the [TrafficLight] in the [super::RoadNetwork]
37pub struct TrafficLightBook<'a> {
38    pub(super) traffic_light_book: &'a maliput_sys::api::rules::ffi::TrafficLightBook,
39}
40
41impl<'a> TrafficLightBook<'a> {
42    /// Gets all the [TrafficLight]s in the [TrafficLightBook]
43    ///
44    /// # Returns
45    /// A vector of [TrafficLight]s
46    pub fn traffic_lights(&self) -> Vec<TrafficLight<'_>> {
47        let traffic_lights_cpp = maliput_sys::api::rules::ffi::TrafficLightBook_TrafficLights(self.traffic_light_book);
48        traffic_lights_cpp
49            .into_iter()
50            .map(|tl| TrafficLight {
51                traffic_light: unsafe { tl.traffic_light.as_ref().expect("") },
52            })
53            .collect::<Vec<TrafficLight>>()
54    }
55
56    /// Gets a [TrafficLight] by its id.
57    ///
58    /// # Arguments
59    /// * `id` - The id of the [TrafficLight].
60    ///
61    /// # Returns
62    /// The [TrafficLight] with the given id.
63    /// If no [TrafficLight] is found with the given id, return None.
64    pub fn get_traffic_light(&self, id: &String) -> Option<TrafficLight<'_>> {
65        let traffic_light = maliput_sys::api::rules::ffi::TrafficLightBook_GetTrafficLight(self.traffic_light_book, id);
66        if traffic_light.is_null() {
67            return None;
68        }
69        Some(TrafficLight {
70            traffic_light: unsafe {
71                traffic_light
72                    .as_ref()
73                    .expect("Unable to get underlying traffic light pointer")
74            },
75        })
76    }
77}
78
79/// Models a traffic light. A traffic light is a physical signaling device
80/// typically located at road intersections. It contains one or more groups of
81/// light bulbs with varying colors and shapes. The lighting patterns of the
82/// bulbs signify right-of-way rule information to the agents navigating the
83/// intersection (e.g., vehicles, bicyclists, pedestrians, etc.). Typically, an
84/// intersection will be managed by multiple traffic lights.
85///
86/// Note that traffic lights are physical manifestations of underlying
87/// right-of-way rules and thus naturally have lower signal-to-noise ratio
88/// relative to the underlying rules. Thus, oracular agents should directly use
89/// the underlying right-of-way rules instead of traffic lights when navigating
90/// intersections. TrafficLight exists for testing autonomous vehicles that do
91/// not have access to right-of-way rules.
92pub struct TrafficLight<'a> {
93    pub traffic_light: &'a maliput_sys::api::rules::ffi::TrafficLight,
94}
95
96impl<'a> TrafficLight<'a> {
97    /// Get the id of the [TrafficLight].
98    ///
99    /// # Returns
100    /// The id of the [TrafficLight].
101    pub fn id(&self) -> String {
102        maliput_sys::api::rules::ffi::TrafficLight_id(self.traffic_light)
103    }
104
105    /// Get the position of the [TrafficLight] in the road network.
106    ///
107    /// # Returns
108    /// An [super::InertialPosition] representing the position of the [TrafficLight] in the road network.
109    pub fn position_road_network(&self) -> super::InertialPosition {
110        let inertial_position = maliput_sys::api::rules::ffi::TrafficLight_position_road_network(self.traffic_light);
111        super::InertialPosition { ip: inertial_position }
112    }
113
114    /// Get the orientation of the [TrafficLight] in the road network.
115    ///
116    /// # Returns
117    /// An [super::Rotation] representing the orientation of the [TrafficLight] in the road network.
118    pub fn orientation_road_network(&self) -> super::Rotation {
119        let rotation = maliput_sys::api::rules::ffi::TrafficLight_orientation_road_network(self.traffic_light);
120        super::Rotation { r: rotation }
121    }
122
123    /// Get the bulb groups of the [TrafficLight].
124    ///
125    /// # Returns
126    /// A vector of [BulbGroup]s in the [TrafficLight].
127    /// If the [TrafficLight] has no bulb groups, return an empty vector.
128    pub fn bulb_groups(&self) -> Vec<BulbGroup<'_>> {
129        let bulb_groups_cpp = maliput_sys::api::rules::ffi::TrafficLight_bulb_groups(self.traffic_light);
130        bulb_groups_cpp
131            .into_iter()
132            .map(|bg| BulbGroup {
133                bulb_group: unsafe { bg.bulb_group.as_ref().expect("") },
134            })
135            .collect::<Vec<BulbGroup>>()
136    }
137
138    /// Get a [BulbGroup] by its id.
139    ///
140    /// # Arguments
141    /// * `id` - The id of the [BulbGroup].
142    ///
143    /// # Returns
144    /// The [BulbGroup] with the given id.
145    /// If no [BulbGroup] is found with the given id, return None.
146    pub fn get_bulb_group(&self, id: &String) -> Option<BulbGroup<'_>> {
147        let bulb_group = maliput_sys::api::rules::ffi::TrafficLight_GetBulbGroup(self.traffic_light, id);
148        if bulb_group.is_null() {
149            return None;
150        }
151        Some(BulbGroup {
152            bulb_group: unsafe {
153                bulb_group
154                    .as_ref()
155                    .expect("Unable to get underlying bulb group pointer")
156            },
157        })
158    }
159}
160
161#[derive(Debug, Copy, Clone, PartialEq, Eq)]
162/// Defines the possible bulb colors.
163pub enum BulbColor {
164    Red,
165    Yellow,
166    Green,
167}
168
169#[derive(Debug, Copy, Clone, PartialEq, Eq)]
170/// Defines the possible bulb types.
171pub enum BulbType {
172    Round,
173    Arrow,
174}
175
176#[derive(Debug, Copy, Clone, PartialEq, Eq)]
177/// Defines the possible bulb types.
178pub enum BulbState {
179    Off,
180    On,
181    Blinking,
182}
183
184/// Models a bulb within a bulb group.
185pub struct Bulb<'a> {
186    pub bulb: &'a maliput_sys::api::rules::ffi::Bulb,
187}
188
189impl Bulb<'_> {
190    /// Returns this Bulb instance's unique identifier.
191    ///
192    /// # Returns
193    /// A [UniqueBulbId] representing the unique identifier of the [Bulb].
194    pub fn unique_id(&self) -> UniqueBulbId {
195        UniqueBulbId {
196            unique_bulb_id: maliput_sys::api::rules::ffi::Bulb_unique_id(self.bulb),
197        }
198    }
199
200    /// Get the id of the [Bulb].
201    ///
202    /// # Returns
203    /// The id of the [Bulb].
204    pub fn id(&self) -> String {
205        maliput_sys::api::rules::ffi::Bulb_id(self.bulb)
206    }
207
208    /// Get the color of the [Bulb].
209    ///
210    /// # Returns
211    /// The [BulbColor].
212    pub fn color(&self) -> BulbColor {
213        let color = self.bulb.color();
214        match *color {
215            maliput_sys::api::rules::ffi::BulbColor::kRed => BulbColor::Red,
216            maliput_sys::api::rules::ffi::BulbColor::kYellow => BulbColor::Yellow,
217            maliput_sys::api::rules::ffi::BulbColor::kGreen => BulbColor::Green,
218            _ => panic!("Invalid bulb color"),
219        }
220    }
221
222    /// Get the type of the [Bulb].
223    ///
224    /// # Returns
225    /// The [BulbType].
226    pub fn bulb_type(&self) -> BulbType {
227        let bulb_type = maliput_sys::api::rules::ffi::Bulb_type(self.bulb);
228        match *bulb_type {
229            maliput_sys::api::rules::ffi::BulbType::kRound => BulbType::Round,
230            maliput_sys::api::rules::ffi::BulbType::kArrow => BulbType::Arrow,
231            _ => panic!("Invalid bulb type"),
232        }
233    }
234
235    /// Get the position of the [Bulb] in the bulb group.
236    ///
237    /// # Returns
238    /// An [super::InertialPosition] representing the position of the [Bulb] in the bulb group.
239    pub fn position_bulb_group(&self) -> super::InertialPosition {
240        let inertial_position = maliput_sys::api::rules::ffi::Bulb_position_bulb_group(self.bulb);
241        super::InertialPosition { ip: inertial_position }
242    }
243
244    /// Get the orientation of the [Bulb] in the bulb group.
245    ///
246    /// # Returns
247    /// An [super::Rotation] representing the orientation of the [Bulb] in the bulb group.
248    pub fn orientation_bulb_group(&self) -> super::Rotation {
249        let rotation = maliput_sys::api::rules::ffi::Bulb_orientation_bulb_group(self.bulb);
250        super::Rotation { r: rotation }
251    }
252
253    /// Returns the arrow's orientation. Only applicable if [Bulb::bulb_type] returns [BulbType::Arrow].
254    ///
255    /// # Returns
256    /// An `Option<f64>` representing the orientation of the arrow in radians.
257    pub fn arrow_orientation_rad(&self) -> Option<f64> {
258        let arrow_orientation = maliput_sys::api::rules::ffi::Bulb_arrow_orientation_rad(self.bulb);
259        if arrow_orientation.is_null() {
260            return None;
261        }
262        Some(arrow_orientation.value)
263    }
264
265    /// Gets the possible states of the [Bulb].
266    ///
267    /// # Returns
268    /// A vector of [BulbState]s representing the possible states of the [Bulb].
269    pub fn states(&self) -> Vec<BulbState> {
270        let states_cpp = maliput_sys::api::rules::ffi::Bulb_states(self.bulb);
271        states_cpp
272            .into_iter()
273            .map(Bulb::_from_cpp_state_to_rust_state)
274            .collect::<Vec<BulbState>>()
275    }
276
277    /// Gets the default state of the [Bulb].
278    ///
279    /// # Returns
280    /// A [BulbState] representing the default state of the [Bulb].
281    pub fn get_default_state(&self) -> BulbState {
282        let default_state = self.bulb.GetDefaultState();
283        Bulb::_from_cpp_state_to_rust_state(&default_state)
284    }
285
286    /// Check if the given state is possible valid for the [Bulb].
287    ///
288    /// # Arguments
289    /// * `state` - The [BulbState] to check.
290    ///
291    /// # Returns
292    /// A boolean indicating whether the given state is valid for the [Bulb].
293    pub fn is_valid_state(&self, state: &BulbState) -> bool {
294        self.bulb.IsValidState(&Bulb::_from_rust_state_to_cpp_state(state))
295    }
296
297    /// Returns the bounding box of the bulb.
298    ///
299    /// # Returns
300    /// A tuple containing the minimum and maximum points of the bounding box.
301    pub fn bounding_box(&self) -> (crate::math::Vector3, crate::math::Vector3) {
302        let min = maliput_sys::api::rules::ffi::Bulb_bounding_box_min(self.bulb);
303        let max = maliput_sys::api::rules::ffi::Bulb_bounding_box_max(self.bulb);
304        (crate::math::Vector3 { v: min }, crate::math::Vector3 { v: max })
305    }
306
307    /// Returns the parent [BulbGroup] of the bulb.
308    ///
309    /// # Returns
310    /// The parent [BulbGroup] of the bulb.
311    /// If the bulb is not part of any group, return None.
312    pub fn bulb_group(&self) -> BulbGroup<'_> {
313        BulbGroup {
314            bulb_group: unsafe {
315                maliput_sys::api::rules::ffi::Bulb_bulb_group(self.bulb)
316                    .as_ref()
317                    .expect("Unable to get underlying bulb group pointer. The Bulb might not be part of any BulbGroup.")
318            },
319        }
320    }
321
322    /// Convert from the C++ BulbState to the Rust BulbState
323    /// It is expected to be used only internally.
324    ///
325    /// # Arguments
326    /// * `cpp_bulb_state` - The C++ BulbState
327    ///
328    /// # Returns
329    /// The Rust BulbState
330    ///
331    /// # Panics
332    /// If the C++ BulbState is invalid.
333    fn _from_cpp_state_to_rust_state(cpp_bulb_state: &maliput_sys::api::rules::ffi::BulbState) -> BulbState {
334        match *cpp_bulb_state {
335            maliput_sys::api::rules::ffi::BulbState::kOff => BulbState::Off,
336            maliput_sys::api::rules::ffi::BulbState::kOn => BulbState::On,
337            maliput_sys::api::rules::ffi::BulbState::kBlinking => BulbState::Blinking,
338            _ => panic!("Invalid bulb state"),
339        }
340    }
341
342    /// Convert from the Rust BulbState to the C++ BulbState
343    /// It is expected to be used only internally.
344    ///
345    /// # Arguments
346    /// * `rust_bulb_state` - The Rust BulbState
347    ///
348    /// # Returns
349    /// The C++ BulbState
350    fn _from_rust_state_to_cpp_state(rust_bulb_state: &BulbState) -> maliput_sys::api::rules::ffi::BulbState {
351        match rust_bulb_state {
352            BulbState::Off => maliput_sys::api::rules::ffi::BulbState::kOff,
353            BulbState::On => maliput_sys::api::rules::ffi::BulbState::kOn,
354            BulbState::Blinking => maliput_sys::api::rules::ffi::BulbState::kBlinking,
355        }
356    }
357}
358
359/// Models a group of bulbs within a traffic light. All of the bulbs within a
360/// group should share the same approximate orientation. However, this is not
361/// programmatically enforced.
362/// About the bulb group pose:
363/// - The position of the bulb group is defined as the linear offset of this bulb group's frame
364///   relative to the frame of the traffic light that contains it. The origin of
365///   this bulb group's frame should approximate the bulb group's CoM.
366/// - The orientation of the bulb group is defined as the rotational offset of this bulb
367///   group's frame relative to the frame of the traffic light that contains it.
368///   The +Z axis should align with the bulb group's "up" direction, and the +X
369///   axis should point in the direction that the bulb group is facing.
370///   Following a right-handed coordinate frame, the +Y axis should point left
371///   when facing the +X direction.
372pub struct BulbGroup<'a> {
373    pub bulb_group: &'a maliput_sys::api::rules::ffi::BulbGroup,
374}
375
376impl BulbGroup<'_> {
377    /// Returns this BulbGroup instance's unique identifier.
378    ///
379    /// # Returns
380    /// A [UniqueBulbGroupId] representing the unique identifier of the [BulbGroup].
381    pub fn unique_id(&self) -> UniqueBulbGroupId {
382        UniqueBulbGroupId {
383            unique_bulb_group_id: maliput_sys::api::rules::ffi::BulbGroup_unique_id(self.bulb_group),
384        }
385    }
386
387    /// Gets the id of the [BulbGroup].
388    ///
389    /// # Returns
390    /// The id of the [BulbGroup].
391    pub fn id(&self) -> String {
392        maliput_sys::api::rules::ffi::BulbGroup_id(self.bulb_group)
393    }
394
395    /// Gets the position of the [BulbGroup] in the traffic light.
396    ///
397    /// # Returns
398    /// An [super::InertialPosition] representing the position of the [BulbGroup] in the traffic light.
399    pub fn position_traffic_light(&self) -> super::InertialPosition {
400        let inertial_position = maliput_sys::api::rules::ffi::BulbGroup_position_traffic_light(self.bulb_group);
401        super::InertialPosition { ip: inertial_position }
402    }
403
404    /// Gets the orientation of the [BulbGroup] in the traffic light.
405    ///
406    /// # Returns
407    /// An [super::Rotation] representing the orientation of the [BulbGroup] in the traffic light.
408    pub fn orientation_traffic_light(&self) -> super::Rotation {
409        let rotation = maliput_sys::api::rules::ffi::BulbGroup_orientation_traffic_light(self.bulb_group);
410        super::Rotation { r: rotation }
411    }
412
413    /// Returns the bulbs in the bulb group.
414    ///
415    /// # Returns
416    /// A vector of [Bulb]s in the bulb group.
417    pub fn bulbs(&self) -> Vec<Bulb<'_>> {
418        let bulbs_cpp = maliput_sys::api::rules::ffi::BulbGroup_bulbs(self.bulb_group);
419        bulbs_cpp
420            .into_iter()
421            .map(|b| Bulb {
422                bulb: unsafe { b.bulb.as_ref().expect("") },
423            })
424            .collect::<Vec<Bulb>>()
425    }
426
427    /// Gets a [Bulb] by its id
428    ///
429    /// # Arguments
430    /// * `id` - The id of the [Bulb].
431    ///
432    /// # Returns
433    /// The [Bulb] with the given id.
434    /// If no [Bulb] is found with the given id, return None.
435    pub fn get_bulb(&self, id: &String) -> Option<Bulb<'_>> {
436        let bulb = maliput_sys::api::rules::ffi::BulbGroup_GetBulb(self.bulb_group, id);
437        if bulb.is_null() {
438            return None;
439        }
440        Some(Bulb {
441            bulb: unsafe { bulb.as_ref().expect("Unable to get underlying bulb pointer") },
442        })
443    }
444
445    /// Returns the parent [TrafficLight] of the bulb group.
446    ///
447    /// # Returns
448    /// The parent [TrafficLight] of the bulb group.
449    pub fn traffic_light(&self) -> TrafficLight<'_> {
450        TrafficLight {
451            traffic_light: unsafe {
452                maliput_sys::api::rules::ffi::BulbGroup_traffic_light(self.bulb_group)
453                    .as_ref()
454                    .expect("Unable to get underlying traffic light pointer. The BulbGroup might not be registered to a TrafficLight.")
455            },
456        }
457    }
458}
459
460/// Uniquely identifies a bulb in the `Inertial` space. This consists of the
461/// concatenation of the bulb's ID, the ID of the bulb group that contains the
462/// bulb, and the the ID of the traffic light that contains the bulb group.
463///
464/// String representation of this ID is:
465/// "`traffic_light_id().string()`-`bulb_group_id.string()`-`bulb_id.string()`"
466pub struct UniqueBulbId {
467    pub(crate) unique_bulb_id: cxx::UniquePtr<maliput_sys::api::rules::ffi::UniqueBulbId>,
468}
469
470impl UniqueBulbId {
471    /// Get the traffic light id of the [UniqueBulbId].
472    ///
473    /// # Returns
474    /// The traffic light id of the [UniqueBulbId].
475    pub fn traffic_light_id(&self) -> String {
476        maliput_sys::api::rules::ffi::UniqueBulbId_traffic_light_id(&self.unique_bulb_id)
477    }
478
479    /// Get the bulb group id of the [UniqueBulbId].
480    ///
481    /// # Returns
482    /// The bulb group id of the [UniqueBulbId].
483    pub fn bulb_group_id(&self) -> String {
484        maliput_sys::api::rules::ffi::UniqueBulbId_bulb_group_id(&self.unique_bulb_id)
485    }
486
487    /// Get the bulb id of the [UniqueBulbId].
488    ///
489    /// # Returns
490    /// The bulb id of the [UniqueBulbId].
491    pub fn bulb_id(&self) -> String {
492        maliput_sys::api::rules::ffi::UniqueBulbId_bulb_id(&self.unique_bulb_id)
493    }
494
495    /// Get the string representation of the [UniqueBulbId].
496    ///
497    /// # Returns
498    /// The string representation of the [UniqueBulbId].
499    pub fn string(&self) -> String {
500        self.unique_bulb_id.string().to_string()
501    }
502}
503
504/// Uniquely identifies a bulb group in the `Inertial` space. This consists of
505/// the concatenation of the ID of the bulb group, and the ID of the traffic
506/// light that contains the bulb group.
507///
508/// String representation of this ID is:
509/// "`traffic_light_id().string()`-`bulb_group_id.string()`"
510pub struct UniqueBulbGroupId {
511    unique_bulb_group_id: cxx::UniquePtr<maliput_sys::api::rules::ffi::UniqueBulbGroupId>,
512}
513
514impl UniqueBulbGroupId {
515    /// Get the traffic light id of the [UniqueBulbGroupId].
516    ///
517    /// # Returns
518    /// The traffic light id of the [UniqueBulbGroupId].
519    pub fn traffic_light_id(&self) -> String {
520        maliput_sys::api::rules::ffi::UniqueBulbGroupId_traffic_light_id(&self.unique_bulb_group_id)
521    }
522
523    /// Get the bulb group id of the [UniqueBulbGroupId].
524    ///
525    /// # Returns
526    /// The bulb group id of the [UniqueBulbGroupId].
527    pub fn bulb_group_id(&self) -> String {
528        maliput_sys::api::rules::ffi::UniqueBulbGroupId_bulb_group_id(&self.unique_bulb_group_id)
529    }
530
531    /// Get the string representation of the [UniqueBulbGroupId].
532    ///
533    /// # Returns
534    /// The string representation of the [UniqueBulbGroupId].
535    pub fn string(&self) -> String {
536        self.unique_bulb_group_id.string().to_string()
537    }
538}
539
540/// Interface for querying types of rules. It includes both Discrete and Range value rules. It
541/// provides a registry of the various rule types.
542pub struct RuleRegistry<'a> {
543    pub(super) rule_registry: &'a maliput_sys::api::rules::ffi::RuleRegistry,
544}
545
546/// Represents the rule values the [RuleRegistry] can contain by their Discrete or Range type.
547pub enum RuleValuesByType {
548    DiscreteValues(Vec<DiscreteValue>),
549    Ranges(Vec<Range>),
550}
551
552impl<'a> RuleRegistry<'a> {
553    /// Returns all [DiscreteValue] rule type IDs.
554    ///
555    /// # Returns
556    /// A vector of [String]s representing rule type IDs that correspond to different
557    /// [DiscreteValue]s in the [RuleRegistry].
558    pub fn get_discrete_value_rule_types(&self) -> Vec<String> {
559        let discrete_value_types =
560            maliput_sys::api::rules::ffi::RuleRegistry_DiscreteValueRuleTypes(self.rule_registry);
561        let discrete_value_types = discrete_value_types
562            .as_ref()
563            .expect("Unable to get underlying discrete value rule types pointer.");
564        discrete_value_types.iter().map(|dvt| dvt.type_id.clone()).collect()
565    }
566
567    /// Returns all [DiscreteValue]s corresponding to the specified `rule_type_id`.
568    ///
569    /// This methods works in tandem with [RuleRegistry::get_discrete_value_rule_types].
570    ///
571    /// # Arguments
572    /// * `rule_type_id` - The id of the rule type.
573    ///
574    /// # Returns
575    /// A vector of [DiscreteValue]s or [None] if the `rule_type_id` doesn't match any type id in
576    /// the [RuleRegistry].
577    pub fn discrete_values_by_type(&self, rule_type_id: String) -> Option<Vec<DiscreteValue>> {
578        let discrete_value_types =
579            maliput_sys::api::rules::ffi::RuleRegistry_DiscreteValueRuleTypes(self.rule_registry);
580        let discrete_value_types = discrete_value_types
581            .as_ref()
582            .expect("Unable to get underlying discrete value rule types pointer.");
583        discrete_value_types
584            .iter()
585            .find(|dvt| dvt.type_id == rule_type_id)
586            .map(|dvt| discrete_values_from_cxx(&dvt.values))
587    }
588
589    /// Returns all [Range] rule type IDs.
590    ///
591    /// # Returns
592    /// A vector of [String]s representing rule type IDs that correspond to different [Range]s in
593    /// the [RuleRegistry].
594    pub fn get_range_rule_types(&self) -> Vec<String> {
595        let range_value_types = maliput_sys::api::rules::ffi::RuleRegistry_RangeValueRuleTypes(self.rule_registry);
596        let range_value_types = range_value_types
597            .as_ref()
598            .expect("Unable to get underlying range rule types pointer.");
599        range_value_types.iter().map(|rvt| rvt.type_id.clone()).collect()
600    }
601
602    /// Returns all [Range]s corresponding to the specified `rule_type_id`.
603    ///
604    /// This methods works in tandem with [RuleRegistry::get_range_rule_types].
605    ///
606    /// # Arguments
607    /// * `rule_type_id` - The id of the rule type.
608    ///
609    /// # Returns
610    /// A vector of [Range]s or [None] if the `rule_type_id` doesn't match any type id in the
611    /// [RuleRegistry].
612    pub fn range_values_by_type(&self, rule_type_id: String) -> Option<Vec<Range>> {
613        let range_value_types = maliput_sys::api::rules::ffi::RuleRegistry_RangeValueRuleTypes(self.rule_registry);
614        let range_value_types = range_value_types
615            .as_ref()
616            .expect("Unable to get underlying range rule types pointer.");
617        range_value_types
618            .iter()
619            .find(|rvt| rvt.type_id == rule_type_id)
620            .map(|rvt| range_values_from_cxx(&rvt.values))
621    }
622
623    /// Returns all possible states for a given `rule_type_id`.
624    ///
625    /// # Arguments
626    /// * `rule_type_id` - The id of the rule type.
627    ///
628    /// # Returns
629    /// An `Option` containing a [RuleValuesByType] enum with either a vector of [Range]s or a
630    /// vector of [DiscreteValue]s. Returns `None` if the `rule_type_id` is not found.
631    pub fn get_possible_states_of_rule_type(&self, rule_type_id: String) -> Option<RuleValuesByType> {
632        if let Some(ranges) = self.range_values_by_type(rule_type_id.clone()) {
633            Some(RuleValuesByType::Ranges(ranges))
634        } else {
635            self.discrete_values_by_type(rule_type_id)
636                .map(RuleValuesByType::DiscreteValues)
637        }
638    }
639}
640
641/// Abstraction for holding the output of [RoadRulebook::rules()] and [RoadRulebook::find_rules()]
642/// methods.
643/// This struct contains a map of [DiscreteValueRule]s and [RangeValueRule]s.
644/// The keys of the map are the ids of the rules.
645/// The values of the map are the rules.
646pub struct QueryResults {
647    pub discrete_value_rules: std::collections::HashMap<String, DiscreteValueRule>,
648    pub range_value_rules: std::collections::HashMap<String, RangeValueRule>,
649}
650
651/// Interface for querying "rules of the road". This interface
652/// provides access to static information about a road network (i.e.,
653/// information determined prior to the beginning of a simulation). Some
654/// rule types may refer to additional dynamic information which will be
655/// provided by other interfaces.
656pub struct RoadRulebook<'a> {
657    pub(super) road_rulebook: &'a maliput_sys::api::rules::ffi::RoadRulebook,
658}
659
660impl<'a> RoadRulebook<'a> {
661    /// Returns the DiscreteValueRule with the specified `id`.
662    ///
663    /// # Arguments
664    /// * `rule_id` - The id of the rule.
665    ///
666    /// # Returns
667    /// The DiscreteValueRule with the given id or None if the id is not in the Rulebook.
668    pub fn get_discrete_value_rule(&self, rule_id: &String) -> Option<DiscreteValueRule> {
669        let discrete_value_rule =
670            maliput_sys::api::rules::ffi::RoadRulebook_GetDiscreteValueRule(self.road_rulebook, rule_id);
671        if discrete_value_rule.is_null() {
672            return None;
673        }
674        Some(DiscreteValueRule { discrete_value_rule })
675    }
676    /// Returns the RangeValueRule with the specified `id`.
677    ///
678    /// # Arguments
679    /// * `rule_id` - The id of the rule.
680    ///
681    /// # Returns
682    /// The RangeValueRule with the given id or None if the id is not in the Rulebook.
683    pub fn get_range_value_rule(&self, rule_id: &String) -> Option<RangeValueRule> {
684        let range_value_rule =
685            maliput_sys::api::rules::ffi::RoadRulebook_GetRangeValueRule(self.road_rulebook, rule_id);
686        if range_value_rule.is_null() {
687            return None;
688        }
689        Some(RangeValueRule { range_value_rule })
690    }
691
692    /// Returns all the rules in the road rulebook.
693    ///
694    /// # Returns
695    /// A [QueryResults] containing all the rules in the road rulebook.
696    pub fn rules(&self) -> QueryResults {
697        let query_results_cpp = maliput_sys::api::rules::ffi::RoadRulebook_Rules(self.road_rulebook);
698        let discrete_value_rules_id =
699            maliput_sys::api::rules::ffi::QueryResults_discrete_value_rules(&query_results_cpp);
700        let range_value_rules_id = maliput_sys::api::rules::ffi::QueryResults_range_value_rules(&query_results_cpp);
701        let mut dvr_map = std::collections::HashMap::new();
702        for rule_id in discrete_value_rules_id {
703            // It is okay to unwrap here since we are iterating valid IDs obtained above.
704            let rule = self.get_discrete_value_rule(&rule_id).unwrap();
705            dvr_map.insert(rule.id(), rule);
706        }
707        let mut rvr_map = std::collections::HashMap::new();
708        for rule_id in range_value_rules_id {
709            // It is okay to unwrap here since we are iterating valid IDs obtained above.
710            let rule = self.get_range_value_rule(&rule_id).unwrap();
711            rvr_map.insert(rule.id(), rule);
712        }
713        QueryResults {
714            discrete_value_rules: dvr_map,
715            range_value_rules: rvr_map,
716        }
717    }
718
719    /// Finds rules that apply to the given lane s ranges.
720    ///
721    /// # Arguments
722    /// * `ranges` - A vector of [super::LaneSRange]s to find rules for.
723    /// * `tolerance` - A tolerance value to use when finding rules.
724    ///
725    /// # Returns
726    /// A [QueryResults] containing the rules that apply to the given lane s ranges.
727    /// If no rules are found, an empty [QueryResults] is returned.
728    ///
729    /// # Errors
730    /// Returns a [MaliputError] if the underlying C++ function fails.
731    pub fn find_rules(&self, ranges: &Vec<super::LaneSRange>, tolerance: f64) -> Result<QueryResults, MaliputError> {
732        let mut ranges_cpp = Vec::new();
733        for range in ranges {
734            ranges_cpp.push(maliput_sys::api::rules::ffi::ConstLaneSRangeRef {
735                lane_s_range: &range.lane_s_range,
736            });
737        }
738        let query_results_cpp =
739            maliput_sys::api::rules::ffi::RoadRulebook_FindRules(self.road_rulebook, &ranges_cpp, tolerance)?;
740
741        let discrete_value_rules_id =
742            maliput_sys::api::rules::ffi::QueryResults_discrete_value_rules(&query_results_cpp);
743        let range_value_rules_id = maliput_sys::api::rules::ffi::QueryResults_range_value_rules(&query_results_cpp);
744        let mut dvr_map = std::collections::HashMap::new();
745        for rule_id in discrete_value_rules_id {
746            if let Some(rule) = self.get_discrete_value_rule(&rule_id) {
747                dvr_map.insert(rule.id(), rule);
748            }
749        }
750        let mut rvr_map = std::collections::HashMap::new();
751        for rule_id in range_value_rules_id {
752            if let Some(rule) = self.get_range_value_rule(&rule_id) {
753                rvr_map.insert(rule.id(), rule);
754            }
755        }
756        Ok(QueryResults {
757            discrete_value_rules: dvr_map,
758            range_value_rules: rvr_map,
759        })
760    }
761}
762
763/// # Rule
764///
765/// A Rule may have multiple states that affect agent behavior while it is
766/// driving through the rule's zone. The possible states of a Rule must be
767/// semantically coherent. The current state of a Rule is given by a
768/// [RuleStateProvider]. States can be:
769///
770/// - range based ([RangeValueRule]).
771/// - discrete ([DiscreteValueRule]).
772///
773/// # DiscreteValueRule
774///
775/// [DiscreteValue]s are defined by a string value.
776/// Semantics of this rule are based on _all_ possible values that this
777/// [DiscreteValueRule::type_id] could have (as specified by RuleRegistry::FindRuleByType()),
778/// not only the subset of values that a specific instance of this rule can
779/// be in.
780pub struct DiscreteValueRule {
781    discrete_value_rule: cxx::UniquePtr<maliput_sys::api::rules::ffi::DiscreteValueRule>,
782}
783
784impl DiscreteValueRule {
785    /// Returns the Id of the rule as a string.
786    ///
787    /// # Returns
788    /// The id of the rule.
789    pub fn id(&self) -> String {
790        maliput_sys::api::rules::ffi::DiscreteValueRule_id(&self.discrete_value_rule)
791    }
792    /// Returns the type of the rule as a string.
793    /// Example: "right-of-way-rule-type-id", "direction-usage-rule-type-id"
794    ///
795    /// # Returns
796    /// The type id of the rule.
797    pub fn type_id(&self) -> String {
798        maliput_sys::api::rules::ffi::DiscreteValueRule_type_id(&self.discrete_value_rule)
799    }
800    /// Returns a [super::LaneSRoute] that represents the zone that the rule applies to.
801    ///
802    /// # Returns
803    /// A [super::LaneSRoute] representing the zone of the rule.
804    pub fn zone(&self) -> super::LaneSRoute {
805        let lane_s_route = maliput_sys::api::rules::ffi::DiscreteValueRule_zone(&self.discrete_value_rule);
806        super::LaneSRoute { lane_s_route }
807    }
808    /// Returns the states of the rule.
809    ///
810    /// # Returns
811    /// A vector of [DiscreteValue]s representing the states of the rule.
812    /// If the rule has no states, an empty vector is returned.
813    pub fn states(&self) -> Vec<DiscreteValue> {
814        discrete_values_from_cxx(self.discrete_value_rule.states())
815    }
816}
817
818impl std::fmt::Debug for DiscreteValueRule {
819    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
820        write!(
821            f,
822            "DiscreteValueRule {{ id: {}, type_id: {}, zone: {:?}, states: {:?} }}",
823            self.id(),
824            self.type_id(),
825            self.zone(),
826            self.states()
827        )
828    }
829}
830
831/// Holds a `Rule` ID and the current state of that `Rule`.
832/// It is usually used as a return type for [super::Intersection::discrete_value_rule_states].
833pub struct DiscreteValueRuleState {
834    /// Rule ID.
835    pub rule_id: String,
836    /// Current state of the rule.
837    pub state: DiscreteValue,
838}
839
840/// # Rule
841///
842/// A Rule may have multiple states that affect agent behavior while it is
843/// driving through the rule's zone. The possible states of a Rule must be
844/// semantically coherent. The current state of a Rule is given by a
845/// [RuleStateProvider]. States can be:
846///
847/// - range based ([RangeValueRule]).
848/// - discrete ([DiscreteValueRule]).
849///
850/// # RangeValueRule
851///
852/// [Range]s describe a numeric range based rule.
853/// Ranges are closed and continuous, defined by a minimum and maximum quantity.
854/// When only one extreme is formally defined, the other should take a
855/// semantically correct value. For example, if a speed limit only specifies a
856/// maximum value, the minimum value is typically zero.
857pub struct RangeValueRule {
858    range_value_rule: cxx::UniquePtr<maliput_sys::api::rules::ffi::RangeValueRule>,
859}
860
861impl RangeValueRule {
862    /// Returns the Id of the rule as a string.
863    ///
864    /// # Returns
865    /// The id of the rule.
866    pub fn id(&self) -> String {
867        maliput_sys::api::rules::ffi::RangeValueRule_id(&self.range_value_rule)
868    }
869    /// Returns the type of the rule as a string.
870    /// Example: "right-of-way-rule-type-id", "direction-usage-rule-type-id"
871    ///
872    /// # Returns
873    /// The type id of the rule.
874    pub fn type_id(&self) -> String {
875        maliput_sys::api::rules::ffi::RangeValueRule_type_id(&self.range_value_rule)
876    }
877    /// Returns a [super::LaneSRoute] that represents the zone that the rule applies to.
878    ///
879    /// # Returns
880    /// A [super::LaneSRoute] representing the zone of the rule.
881    pub fn zone(&self) -> super::LaneSRoute {
882        let lane_s_route = maliput_sys::api::rules::ffi::RangeValueRule_zone(&self.range_value_rule);
883        super::LaneSRoute { lane_s_route }
884    }
885    /// Returns the states of the rule.
886    ///
887    /// # Returns
888    /// A vector of [Range]s representing the states of the rule.
889    /// If the rule has no states, an empty vector is returned.
890    pub fn states(&self) -> Vec<Range> {
891        range_values_from_cxx(self.range_value_rule.states())
892    }
893}
894
895/// Defines a Rule Type.
896///
897/// # RuleType
898///
899/// [RuleType]s provide a way of obtaining a rule type's string defined in
900/// maliput's backend. Since new rule types can be created in a custom manner,
901/// [RuleType] only holds the most common types which are already defined in
902/// the backend.
903#[derive(Display, IntoStaticStr)]
904pub enum RuleType {
905    #[strum(serialize = "Direction-Usage Rule Type")]
906    DirectionUsage,
907    #[strum(serialize = "Right-Of-Way Rule Type")]
908    RightOfWay,
909    #[strum(serialize = "Vehicle-Stop-In-Zone-Behavior Rule Type")]
910    VehicleStopInZoneBehavior,
911    #[strum(serialize = "Speed-Limit Rule Type")]
912    SpeedLimit,
913}
914
915impl RuleType {
916    /// Gets the Rule ID for the [RuleType] and `lane_id`.
917    ///
918    /// # Arguments
919    /// - `lane_id` - The lane ID to get the rule ID from.
920    ///
921    /// # Returns
922    /// A rule ID formatted the way the backend defines it.
923    pub fn get_rule_id(&self, lane_id: &str) -> String {
924        // We rely on maliput_malidrive which define the rule id as:
925        // "<rule_type>/<lane_id>"
926        self.to_string() + "/" + lane_id
927    }
928}
929
930/// Defines a base state for a rule.
931///
932/// # RuleStateBase
933///
934/// - `severity` - The severity of the rule state.
935/// - `related_rules` - A map of related rules. The key is the group name and the value is a vector of rule ids.
936/// - `related_unique_ids` - A map of related unique ids. The key is the group name and the value is a vector of unique ids.
937///
938/// See [DiscreteValueRule] and [RangeValueRule] for more information.
939pub struct RuleStateBase {
940    /// Severity of the rule's state. A non-negative quantity that specifies the
941    /// level of enforcement. The smaller it is, the more strictly the rule is
942    /// enforced. Each rule type can define its own set of severity level
943    /// semantics.
944    severity: i32,
945    related_rules: cxx::UniquePtr<cxx::CxxVector<maliput_sys::api::rules::ffi::RelatedRule>>,
946    related_unique_ids: cxx::UniquePtr<cxx::CxxVector<maliput_sys::api::rules::ffi::RelatedUniqueId>>,
947}
948
949/// A trait representing a possible state of a `Rule`.
950///
951/// A `Rule` can have multiple states that affect agent behavior. This trait
952/// provides a common interface for accessing the properties shared by all
953/// rule states, such as severity and related rules.
954///
955/// This trait is implemented by specific state types like [`DiscreteValue`]
956/// and [`Range`].
957///
958/// # Implementors
959///
960/// When implementing this trait, you must provide an implementation for the
961/// [`get_rule_state()`] method, which gives access to the underlying
962/// [`RuleStateBase`] data. The other methods have default implementations.
963pub trait RuleState {
964    /// Gets the underlying [`RuleStateBase`] that contains common state properties.
965    ///
966    /// # Returns
967    /// A reference to the [`RuleStateBase`] that contains the severity, related rules,
968    /// and related unique ids for the rule state.
969    fn get_rule_state(&self) -> &RuleStateBase;
970
971    /// Returns the severity of the rule state.
972    ///
973    /// # Returns
974    /// An `i32` representing the severity of the rule state.
975    /// The severity is a numeric value that indicates the importance or urgency of the rule. The lower the value, the more strictly the rule is enforced.
976    fn severity(&self) -> i32 {
977        self.get_rule_state().severity
978    }
979
980    /// Returns a map of related rules ids. The key is the group name and the value is a vector of rule ids.
981    ///
982    /// # Returns
983    /// A map of related rules where the key is the group name and the value is a vector of rule ids.
984    fn related_rules(&self) -> std::collections::HashMap<&String, &Vec<String>> {
985        self.get_rule_state()
986            .related_rules
987            .iter()
988            .map(|rr| (&rr.group_name, &rr.rule_ids))
989            .collect::<std::collections::HashMap<&String, &Vec<String>>>()
990    }
991    /// Returns a map of related unique ids. The key is the group name and the value is a vector of unique ids.
992    ///
993    /// # Returns
994    /// A map of related unique ids where the key is the group name and the value is a vector of unique ids.
995    fn related_unique_ids(&self) -> std::collections::HashMap<&String, &Vec<String>> {
996        self.get_rule_state()
997            .related_unique_ids
998            .iter()
999            .map(|rui| (&rui.group_name, &rui.unique_ids))
1000            .collect::<std::collections::HashMap<&String, &Vec<String>>>()
1001    }
1002}
1003
1004/// Defines a discrete value for a [DiscreteValueRule].
1005/// It extends the [RuleStateBase] with the value of the discrete value.
1006pub struct DiscreteValue {
1007    rule_state: RuleStateBase,
1008    value: String,
1009}
1010
1011impl RuleState for DiscreteValue {
1012    fn get_rule_state(&self) -> &RuleStateBase {
1013        &self.rule_state
1014    }
1015}
1016
1017impl DiscreteValue {
1018    /// Returns the value of the discrete value.
1019    pub fn value(&self) -> &String {
1020        &self.value
1021    }
1022}
1023
1024impl std::fmt::Debug for DiscreteValue {
1025    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1026        write!(
1027            f,
1028            "DiscreteValue {{ value: {}, severity: {}, related_rules: {:?}, related_unique_ids: {:?} }}",
1029            self.value(),
1030            self.severity(),
1031            self.related_rules(),
1032            self.related_unique_ids()
1033        )
1034    }
1035}
1036
1037/// Defines a range value for a [RangeValueRule].
1038/// It extends the [RuleStateBase] with the description, and min and max values of the range.
1039pub struct Range {
1040    rule_state: RuleStateBase,
1041    description: String,
1042    min: f64,
1043    max: f64,
1044}
1045
1046impl RuleState for Range {
1047    fn get_rule_state(&self) -> &RuleStateBase {
1048        &self.rule_state
1049    }
1050}
1051
1052impl Range {
1053    /// Returns the description of the range value.
1054    pub fn description(&self) -> &String {
1055        &self.description
1056    }
1057    /// Returns the minimum value of the range.
1058    pub fn min(&self) -> f64 {
1059        self.min
1060    }
1061    /// Returns the maximum value of the range.
1062    pub fn max(&self) -> f64 {
1063        self.max
1064    }
1065}
1066
1067/// Defines a phase in a traffic rule system.
1068///
1069/// A phase represents a specific state or configuration of traffic signals
1070/// and semantic rules within a traffic control system. Each phase has a unique
1071/// identifier and may include various traffic signal states and rule configurations
1072/// that dictate how traffic should behave during that phase.
1073pub struct Phase {
1074    phase: cxx::UniquePtr<maliput_sys::api::rules::ffi::Phase>,
1075}
1076
1077impl Phase {
1078    /// Gets the id of the [Phase].
1079    ///
1080    /// # Returns
1081    /// The id of the [Phase].
1082    pub fn id(&self) -> String {
1083        maliput_sys::api::rules::ffi::Phase_id(&self.phase)
1084    }
1085
1086    /// Gets the states of all discrete value rules for this phase.
1087    ///
1088    /// # Returns
1089    /// A `HashMap` where the key is the rule ID as a [String] and the value is the
1090    /// [DiscreteValue] state of that rule.
1091    pub fn discrete_value_rule_states(&self) -> HashMap<String, DiscreteValue> {
1092        let rule_states = maliput_sys::api::rules::ffi::Phase_discrete_value_rule_states(&self.phase);
1093        rule_states
1094            .iter()
1095            .map(|state| {
1096                (
1097                    state.rule_id.clone(),
1098                    discrete_value_from_discrete_value_cxx(&state.state),
1099                )
1100            })
1101            .collect()
1102    }
1103
1104    /// Obtains all [UniqueBulbId]s in the [Phase].
1105    ///
1106    /// # Returns
1107    /// A vector of [UniqueBulbId].
1108    pub fn unique_bulb_ids(&self) -> Vec<UniqueBulbId> {
1109        let unique_bulb_ids = maliput_sys::api::rules::ffi::Phase_unique_bulb_ids(&self.phase);
1110        unique_bulb_ids
1111            .iter()
1112            .map(|bulb_id| UniqueBulbId {
1113                unique_bulb_id: maliput_sys::api::rules::ffi::ptr_from_unique_bulb_id(bulb_id),
1114            })
1115            .collect()
1116    }
1117
1118    /// Returns the [BulbState] corresponding to a `bulb_id`.
1119    ///
1120    /// # Arguments
1121    /// * `unique_bulb_id` - The [UniqueBulbId] to get the [BulbState] from.
1122    ///
1123    /// # Returns
1124    /// The [BulbState] the `unique_bulb_id` is in, or [None] if the [UniqueBulbId] is not in this [Phase].
1125    pub fn bulb_state(&self, unique_bulb_id: &UniqueBulbId) -> Option<BulbState> {
1126        let bulb_state = maliput_sys::api::rules::ffi::Phase_bulb_state(&self.phase, &unique_bulb_id.unique_bulb_id);
1127        if bulb_state.is_null() {
1128            return None;
1129        }
1130        Some(match *bulb_state {
1131            maliput_sys::api::rules::ffi::BulbState::kOff => BulbState::Off,
1132            maliput_sys::api::rules::ffi::BulbState::kOn => BulbState::On,
1133            maliput_sys::api::rules::ffi::BulbState::kBlinking => BulbState::Blinking,
1134            _ => return None,
1135        })
1136    }
1137}
1138
1139/// Defines a phase that comes after another [Phase].
1140/// Used as a return type by:
1141///   - [PhaseRing::get_next_phases].
1142pub struct NextPhase {
1143    /// The next phase.
1144    pub next_phase: Phase,
1145    /// The default time before transitioning to the next phase. This is
1146    /// relative to when the current phase began. It is just a recommendation,
1147    /// the actual duration is determined by the PhaseProvider and may depend on
1148    /// events like a vehicle arriving at a left-turn lane or a pedestrian
1149    /// hitting a crosswalk button.
1150    pub duration_until: Option<f64>,
1151}
1152
1153/// Defines a ring of phases in a traffic rule system.
1154///
1155/// A phase ring represents a sequence of phases that a traffic control system
1156/// cycles through.
1157pub struct PhaseRing {
1158    phase_ring: cxx::UniquePtr<maliput_sys::api::rules::ffi::PhaseRing>,
1159}
1160
1161impl PhaseRing {
1162    /// Gets the id of the [PhaseRing].
1163    ///
1164    /// # Returns
1165    /// The id of the [PhaseRing].
1166    pub fn id(&self) -> String {
1167        maliput_sys::api::rules::ffi::PhaseRing_id(&self.phase_ring)
1168    }
1169
1170    /// Gets a [Phase] by its id
1171    ///
1172    /// # Arguments
1173    /// * `id` - The id of the [Phase].
1174    /// # Returns
1175    /// The [Phase] with the given id.
1176    /// If no [Phase] is found with the given id, return None.
1177    pub fn get_phase(&self, id: &String) -> Option<Phase> {
1178        let phase = maliput_sys::api::rules::ffi::PhaseRing_GetPhase(&self.phase_ring, id);
1179        if phase.is_null() {
1180            return None;
1181        }
1182        Some(Phase { phase })
1183    }
1184
1185    /// Returns the ids of all Phases in the PhaseRing.
1186    ///
1187    /// # Returns
1188    /// A vector of strings representing the ids of all Phases in the PhaseRing.
1189    pub fn phases(&self) -> Vec<String> {
1190        maliput_sys::api::rules::ffi::PhaseRing_phases_ids(&self.phase_ring)
1191    }
1192
1193    /// Returns the next phases for a given phase `id`.
1194    ///
1195    /// # Arguments
1196    /// * `id` - The id of the phase to get the next phases from.
1197    ///
1198    /// # Returns
1199    /// A `Result` containing a vector of [NextPhase]s.
1200    ///
1201    /// # Errors
1202    /// Returns a [MaliputError] if the provided `id` is not found in the [PhaseRing].
1203    pub fn get_next_phases(&self, id: &String) -> Result<Vec<NextPhase>, MaliputError> {
1204        let next_phases = maliput_sys::api::rules::ffi::PhaseRing_GetNextPhases(&self.phase_ring, id)?;
1205        Ok(next_phases
1206            .iter()
1207            .map(|np| NextPhase {
1208                next_phase: Phase {
1209                    phase: maliput_sys::api::rules::ffi::PhaseRing_GetPhase(&self.phase_ring, &np.phase_id),
1210                },
1211                duration_until: if np.duration_until.is_null() {
1212                    None
1213                } else {
1214                    Some(np.duration_until.value)
1215                },
1216            })
1217            .collect())
1218    }
1219}
1220
1221/// Defines a book of phase rings in a traffic rule system.
1222pub struct PhaseRingBook<'a> {
1223    pub(super) phase_ring_book: &'a maliput_sys::api::rules::ffi::PhaseRingBook,
1224}
1225
1226impl<'a> PhaseRingBook<'a> {
1227    /// Returns the ids of all PhaseRings in the PhaseRingBook.
1228    ///
1229    /// # Returns
1230    /// A vector of strings representing the ids of all PhaseRings in the PhaseRingBook.
1231    pub fn get_phase_rings_ids(&self) -> Vec<String> {
1232        maliput_sys::api::rules::ffi::PhaseRingBook_GetPhaseRingsId(self.phase_ring_book)
1233    }
1234
1235    /// Returns the PhaseRing with the specified `id`.
1236    ///
1237    /// # Arguments
1238    /// * `phase_ring_id` - The id of the phase ring.
1239    ///
1240    /// # Returns
1241    /// The PhaseRing with the given id or None if the id is not in the PhaseRingBook.
1242    pub fn get_phase_ring(&self, phase_ring_id: &String) -> Option<PhaseRing> {
1243        let phase_ring = maliput_sys::api::rules::ffi::PhaseRingBook_GetPhaseRing(self.phase_ring_book, phase_ring_id);
1244        if phase_ring.is_null() {
1245            return None;
1246        }
1247        Some(PhaseRing { phase_ring })
1248    }
1249
1250    /// Finds the [PhaseRing] that contains the rule with the specified `rule_id`.
1251    ///
1252    /// # Arguments
1253    /// * `rule_id` - The id of the rule.
1254    ///
1255    /// # Returns
1256    /// The [PhaseRing] that contains the rule with the given id or `None` if no [PhaseRing] is found.
1257    pub fn find_phase_ring(&self, rule_id: &String) -> Option<PhaseRing> {
1258        let phase_ring = maliput_sys::api::rules::ffi::PhaseRingBook_FindPhaseRing(self.phase_ring_book, rule_id);
1259        if phase_ring.is_null() {
1260            return None;
1261        }
1262        Some(PhaseRing { phase_ring })
1263    }
1264}
1265
1266/// Defines a next state of a generic type.
1267pub struct NextState<T> {
1268    /// The next state.
1269    pub next_state: T,
1270    /// The default time before transitioning to the next state. This is
1271    /// relative to when the current state began. It is just a recommendation,
1272    /// the actual duration is determined by the StateProvider and may depend on
1273    /// events like a vehicle arriving at a left-turn lane or a pedestrian
1274    /// hitting a crosswalk button.
1275    pub duration_until: Option<f64>,
1276}
1277
1278/// Holds the current and possible next state of a system.
1279/// It is usually returned by the different types of state providers.
1280pub struct StateProviderQuery<T> {
1281    /// The current state.
1282    pub state: T,
1283    /// The next state.
1284    pub next: Option<NextState<T>>,
1285}
1286
1287/// Alias for the [StateProviderQuery] returned by [PhaseProvider::get_phase].
1288pub type PhaseStateProviderQuery = StateProviderQuery<String>;
1289
1290/// Defines a phase provider.
1291///
1292/// A phase provider is able to get the current phase from a phase-based system.
1293pub struct PhaseProvider<'a> {
1294    pub(super) phase_provider: &'a maliput_sys::api::rules::ffi::PhaseProvider,
1295}
1296
1297impl<'a> PhaseProvider<'a> {
1298    /// Returns the [PhaseStateProviderQuery] for the specified `phase_ring_id`.
1299    ///
1300    /// The states are represented with Strings containing the IDs of each [Phase].
1301    ///
1302    /// # Arguments
1303    /// * `phase_ring_id` - The id of the phase ring.
1304    ///
1305    /// # Returns
1306    /// An `Option` containing the [PhaseStateProviderQuery] for the given `phase_ring_id`.
1307    /// Returns `None` if no phase provider is found for the given id.
1308    pub fn get_phase(&self, phase_ring_id: &String) -> Option<PhaseStateProviderQuery> {
1309        let phase_state = maliput_sys::api::rules::ffi::PhaseProvider_GetPhase(self.phase_provider, phase_ring_id);
1310        if phase_state.is_null() {
1311            return None;
1312        }
1313
1314        let next_state = maliput_sys::api::rules::ffi::PhaseStateProvider_next(&phase_state);
1315        let next_phase = if next_state.is_null() {
1316            None
1317        } else {
1318            Some(NextState {
1319                next_state: next_state.phase_id.clone(),
1320                duration_until: if next_state.duration_until.is_null() {
1321                    None
1322                } else {
1323                    Some(next_state.duration_until.value)
1324                },
1325            })
1326        };
1327
1328        Some(StateProviderQuery {
1329            state: maliput_sys::api::rules::ffi::PhaseStateProvider_state(&phase_state),
1330            next: next_phase,
1331        })
1332    }
1333}
1334
1335/// Provides the dynamic state of [DiscreteValueRule]s.
1336///
1337/// While a [RoadRulebook] provides the static definitions of rules, a
1338/// `DiscreteValueRuleStateProvider` provides the current state of those rules
1339/// at runtime. This allows for querying what state a rule is currently in,
1340/// which is essential for dynamic systems where rule states can change over
1341/// time (e.g., traffic light phases changing).
1342pub struct DiscreteValueRuleStateProvider<'a> {
1343    pub(super) state_provider: &'a maliput_sys::api::rules::ffi::DiscreteValueRuleStateProvider,
1344}
1345
1346impl<'a> DiscreteValueRuleStateProvider<'a> {
1347    /// Gets a state from the provider based on it's `rule_id`.
1348    ///
1349    /// # Arguments
1350    /// * `rule_id` - A Rule ID.
1351    ///
1352    /// # Returns
1353    /// An Option containing the [StateProviderQuery] with a [DiscreteValue] if the `rule_id` matches with any rule.
1354    /// Otherwise, None is returned.
1355    pub fn get_state_by_rule_id(&self, rule_id: &String) -> Option<StateProviderQuery<DiscreteValue>> {
1356        let query_state =
1357            maliput_sys::api::rules::ffi::DiscreteValueRuleStateProvider_GetStateById(self.state_provider, rule_id);
1358        Self::next_state_from_cxx_query(query_state)
1359    }
1360
1361    /// Gets a state from the provider if there is a `rule_type` in the received `road_position`.
1362    ///
1363    /// # Arguments
1364    /// * `road_position` - A position in the road geometry.
1365    /// * `rule_type` - A Rule Type.
1366    /// * `tolerance` - The tolerance in which to look for the Rule of type `rule_type` around the `road_position`.
1367    ///
1368    /// # Returns
1369    /// An Option containing the [StateProviderQuery] with a [DiscreteValue] if `rule_type` matches with any rule's type near `road_position`.
1370    /// Otherwise, None is returned.
1371    pub fn get_state_by_rule_type(
1372        &self,
1373        road_position: &RoadPosition,
1374        rule_type: RuleType,
1375        tolerance: f64,
1376    ) -> Option<StateProviderQuery<DiscreteValue>> {
1377        let query_state = maliput_sys::api::rules::ffi::DiscreteValueRuleStateProvider_GetStateByType(
1378            self.state_provider,
1379            &road_position.rp,
1380            &rule_type.to_string(),
1381            tolerance,
1382        );
1383        Self::next_state_from_cxx_query(query_state)
1384    }
1385
1386    // Internal helper to avoid code duplication.
1387    fn next_state_from_cxx_query(
1388        query_state: cxx::UniquePtr<maliput_sys::api::rules::ffi::DiscreteValueRuleStateProviderQuery>,
1389    ) -> Option<StateProviderQuery<DiscreteValue>> {
1390        if query_state.is_null() {
1391            return None;
1392        }
1393        let next_state = maliput_sys::api::rules::ffi::DiscreteValueRuleStateProviderQuery_next(&query_state);
1394        Some(StateProviderQuery {
1395            state: discrete_value_from_discrete_value_cxx(
1396                &maliput_sys::api::rules::ffi::DiscreteValueRuleStateProviderQuery_state(&query_state),
1397            ),
1398            next: if next_state.is_null() {
1399                None
1400            } else {
1401                Some(NextState {
1402                    next_state: discrete_value_from_discrete_value_cxx(&next_state.state),
1403                    duration_until: if next_state.duration_until.is_null() {
1404                        None
1405                    } else {
1406                        Some(next_state.duration_until.value)
1407                    },
1408                })
1409            },
1410        })
1411    }
1412}
1413
1414/// Provides the dynamic state of [RangeValueRule]s.
1415///
1416/// While a [RoadRulebook] provides the static definitions of rules, a
1417/// `RangeValueRuleStateProvider` provides the current state of those rules
1418/// at runtime. This allows for querying what state a rule is currently in,
1419/// which is essential for dynamic systems where rule states can change over
1420/// time (e.g., variable speed limits based on types of roads).
1421pub struct RangeValueRuleStateProvider<'a> {
1422    pub(super) state_provider: &'a maliput_sys::api::rules::ffi::RangeValueRuleStateProvider,
1423}
1424
1425impl<'a> RangeValueRuleStateProvider<'a> {
1426    /// Gets a state from the provider based on it's `rule_id`.
1427    ///
1428    /// # Arguments
1429    /// * `rule_id` - A Rule ID.
1430    ///
1431    /// # Returns
1432    /// An Option containing the [StateProviderQuery] with a [Range] if the `rule_id` matches with any rule.
1433    /// Otherwise, None is returned.
1434    pub fn get_state_by_rule_id(&self, rule_id: &String) -> Option<StateProviderQuery<Range>> {
1435        let query_state =
1436            maliput_sys::api::rules::ffi::RangeValueRuleStateProvider_GetStateById(self.state_provider, rule_id);
1437        Self::next_state_from_cxx_query(query_state)
1438    }
1439
1440    /// Gets a state from the provider if there is a `rule_type` in the received `road_position`.
1441    ///
1442    /// # Arguments
1443    /// * `road_position` - A position in the road geometry.
1444    /// * `rule_type` - A Rule Type.
1445    /// * `tolerance` - The tolerance in which to look for the Rule of type `rule_type` around the `road_position`.
1446    ///
1447    /// # Returns
1448    /// An Option containing the [StateProviderQuery] with a [Range] if `rule_type` matches with any rule's type near `road_position`.
1449    /// Otherwise, None is returned.
1450    pub fn get_state_by_rule_type(
1451        &self,
1452        road_position: &RoadPosition,
1453        rule_type: RuleType,
1454        tolerance: f64,
1455    ) -> Option<StateProviderQuery<Range>> {
1456        let query_state = maliput_sys::api::rules::ffi::RangeValueRuleStateProvider_GetStateByType(
1457            self.state_provider,
1458            &road_position.rp,
1459            &rule_type.to_string(),
1460            tolerance,
1461        );
1462        Self::next_state_from_cxx_query(query_state)
1463    }
1464
1465    // Internal helper to avoid code duplication.
1466    fn next_state_from_cxx_query(
1467        query_state: cxx::UniquePtr<maliput_sys::api::rules::ffi::RangeValueRuleStateProviderQuery>,
1468    ) -> Option<StateProviderQuery<Range>> {
1469        if query_state.is_null() {
1470            return None;
1471        }
1472        let next_state = maliput_sys::api::rules::ffi::RangeValueRuleStateProviderQuery_next(&query_state);
1473        Some(StateProviderQuery {
1474            state: range_value_from_range_value_cxx(
1475                &maliput_sys::api::rules::ffi::RangeValueRuleStateProviderQuery_state(&query_state),
1476            ),
1477            next: if next_state.is_null() {
1478                None
1479            } else {
1480                Some(NextState {
1481                    next_state: range_value_from_range_value_cxx(&next_state.state),
1482                    duration_until: if next_state.duration_until.is_null() {
1483                        None
1484                    } else {
1485                        Some(next_state.duration_until.value)
1486                    },
1487                })
1488            },
1489        })
1490    }
1491}
1492
1493// Auxiliary method to create a [Vec<Range>] from a [cxx::Vector<RangeValueRuleRange>].
1494fn range_values_from_cxx(
1495    range_values_cxx: &cxx::Vector<maliput_sys::api::rules::ffi::RangeValueRuleRange>,
1496) -> Vec<Range> {
1497    range_values_cxx
1498        .iter()
1499        .map(|range| Range {
1500            rule_state: RuleStateBase {
1501                severity: maliput_sys::api::rules::ffi::RangeValueRuleRange_severity(range),
1502                related_rules: maliput_sys::api::rules::ffi::RangeValueRuleRange_related_rules(range),
1503                related_unique_ids: maliput_sys::api::rules::ffi::RangeValueRuleRange_related_unique_ids(range),
1504            },
1505            description: maliput_sys::api::rules::ffi::RangeValueRuleRange_description(range),
1506            min: maliput_sys::api::rules::ffi::RangeValueRuleRange_min(range),
1507            max: maliput_sys::api::rules::ffi::RangeValueRuleRange_max(range),
1508        })
1509        .collect()
1510}
1511
1512// Auxiliary method to create a [Vec<DiscreteValue>] from a [cxx::Vector<DiscreteValueRuleDiscreteValue>].
1513fn discrete_values_from_cxx(
1514    discrete_values_cxx: &cxx::Vector<maliput_sys::api::rules::ffi::DiscreteValueRuleDiscreteValue>,
1515) -> Vec<DiscreteValue> {
1516    discrete_values_cxx
1517        .iter()
1518        .map(discrete_value_from_discrete_value_cxx)
1519        .collect()
1520}
1521
1522// Auxiliary method to create a [DiscreteValue] from a [maliput_sys::api::rules::ffi::DiscreteValueRuleDiscreteValue].
1523pub(crate) fn discrete_value_from_discrete_value_cxx(
1524    discrete_value: &maliput_sys::api::rules::ffi::DiscreteValueRuleDiscreteValue,
1525) -> DiscreteValue {
1526    DiscreteValue {
1527        rule_state: RuleStateBase {
1528            severity: maliput_sys::api::rules::ffi::DiscreteValueRuleDiscreteValue_severity(discrete_value),
1529            related_rules: maliput_sys::api::rules::ffi::DiscreteValueRuleDiscreteValue_related_rules(discrete_value),
1530            related_unique_ids: maliput_sys::api::rules::ffi::DiscreteValueRuleDiscreteValue_related_unique_ids(
1531                discrete_value,
1532            ),
1533        },
1534        value: maliput_sys::api::rules::ffi::DiscreteValueRuleDiscreteValue_value(discrete_value),
1535    }
1536}
1537
1538// Auxiliary method to create a [Range] from a [maliput_sys::api::rules::ffi::RangeValueRuleRange].
1539fn range_value_from_range_value_cxx(range: &maliput_sys::api::rules::ffi::RangeValueRuleRange) -> Range {
1540    Range {
1541        rule_state: RuleStateBase {
1542            severity: maliput_sys::api::rules::ffi::RangeValueRuleRange_severity(range),
1543            related_rules: maliput_sys::api::rules::ffi::RangeValueRuleRange_related_rules(range),
1544            related_unique_ids: maliput_sys::api::rules::ffi::RangeValueRuleRange_related_unique_ids(range),
1545        },
1546        description: maliput_sys::api::rules::ffi::RangeValueRuleRange_description(range),
1547        min: maliput_sys::api::rules::ffi::RangeValueRuleRange_min(range),
1548        max: maliput_sys::api::rules::ffi::RangeValueRuleRange_max(range),
1549    }
1550}