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::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 [crate::api::InertialPosition] representing the position of the [TrafficLight] in the road network.
109    pub fn position_road_network(&self) -> crate::api::InertialPosition {
110        let inertial_position = maliput_sys::api::rules::ffi::TrafficLight_position_road_network(self.traffic_light);
111        crate::api::InertialPosition { ip: inertial_position }
112    }
113
114    /// Get the orientation of the [TrafficLight] in the road network.
115    ///
116    /// # Returns
117    /// An [crate::api::Rotation] representing the orientation of the [TrafficLight] in the road network.
118    pub fn orientation_road_network(&self) -> crate::api::Rotation {
119        let rotation = maliput_sys::api::rules::ffi::TrafficLight_orientation_road_network(self.traffic_light);
120        crate::api::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 [crate::api::InertialPosition] representing the position of the [Bulb] in the bulb group.
239    pub fn position_bulb_group(&self) -> crate::api::InertialPosition {
240        let inertial_position = maliput_sys::api::rules::ffi::Bulb_position_bulb_group(self.bulb);
241        crate::api::InertialPosition { ip: inertial_position }
242    }
243
244    /// Get the orientation of the [Bulb] in the bulb group.
245    ///
246    /// # Returns
247    /// An [crate::api::Rotation] representing the orientation of the [Bulb] in the bulb group.
248    pub fn orientation_bulb_group(&self) -> crate::api::Rotation {
249        let rotation = maliput_sys::api::rules::ffi::Bulb_orientation_bulb_group(self.bulb);
250        crate::api::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 [crate::api::InertialPosition] representing the position of the [BulbGroup] in the traffic light.
399    pub fn position_traffic_light(&self) -> crate::api::InertialPosition {
400        let inertial_position = maliput_sys::api::rules::ffi::BulbGroup_position_traffic_light(self.bulb_group);
401        crate::api::InertialPosition { ip: inertial_position }
402    }
403
404    /// Gets the orientation of the [BulbGroup] in the traffic light.
405    ///
406    /// # Returns
407    /// An [crate::api::Rotation] representing the orientation of the [BulbGroup] in the traffic light.
408    pub fn orientation_traffic_light(&self) -> crate::api::Rotation {
409        let rotation = maliput_sys::api::rules::ffi::BulbGroup_orientation_traffic_light(self.bulb_group);
410        crate::api::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    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 [crate::api::LaneSRoute] that represents the zone that the rule applies to.
801    ///
802    /// # Returns
803    /// A [crate::api::LaneSRoute] representing the zone of the rule.
804    pub fn zone(&self) -> crate::api::LaneSRoute {
805        let lane_s_route = maliput_sys::api::rules::ffi::DiscreteValueRule_zone(&self.discrete_value_rule);
806        crate::api::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/// # Rule
832///
833/// A Rule may have multiple states that affect agent behavior while it is
834/// driving through the rule's zone. The possible states of a Rule must be
835/// semantically coherent. The current state of a Rule is given by a
836/// [RuleStateProvider]. States can be:
837///
838/// - range based ([RangeValueRule]).
839/// - discrete ([DiscreteValueRule]).
840///
841/// # RangeValueRule
842///
843/// [Range]s describe a numeric range based rule.
844/// Ranges are closed and continuous, defined by a minimum and maximum quantity.
845/// When only one extreme is formally defined, the other should take a
846/// semantically correct value. For example, if a speed limit only specifies a
847/// maximum value, the minimum value is typically zero.
848pub struct RangeValueRule {
849    range_value_rule: cxx::UniquePtr<maliput_sys::api::rules::ffi::RangeValueRule>,
850}
851
852impl RangeValueRule {
853    /// Returns the Id of the rule as a string.
854    ///
855    /// # Returns
856    /// The id of the rule.
857    pub fn id(&self) -> String {
858        maliput_sys::api::rules::ffi::RangeValueRule_id(&self.range_value_rule)
859    }
860    /// Returns the type of the rule as a string.
861    /// Example: "right-of-way-rule-type-id", "direction-usage-rule-type-id"
862    ///
863    /// # Returns
864    /// The type id of the rule.
865    pub fn type_id(&self) -> String {
866        maliput_sys::api::rules::ffi::RangeValueRule_type_id(&self.range_value_rule)
867    }
868    /// Returns a [crate::api::LaneSRoute] that represents the zone that the rule applies to.
869    ///
870    /// # Returns
871    /// A [crate::api::LaneSRoute] representing the zone of the rule.
872    pub fn zone(&self) -> crate::api::LaneSRoute {
873        let lane_s_route = maliput_sys::api::rules::ffi::RangeValueRule_zone(&self.range_value_rule);
874        crate::api::LaneSRoute { lane_s_route }
875    }
876    /// Returns the states of the rule.
877    ///
878    /// # Returns
879    /// A vector of [Range]s representing the states of the rule.
880    /// If the rule has no states, an empty vector is returned.
881    pub fn states(&self) -> Vec<Range> {
882        range_values_from_cxx(self.range_value_rule.states())
883    }
884}
885
886/// Defines a Rule Type.
887///
888/// # RuleType
889///
890/// [RuleType]s provide a way of obtaining a rule type's string defined in
891/// maliput's backend. Since new rule types can be created in a custom manner,
892/// [RuleType] only holds the most common types which are already defined in
893/// the backend.
894#[derive(Display, IntoStaticStr)]
895pub enum RuleType {
896    #[strum(serialize = "Direction-Usage Rule Type")]
897    DirectionUsage,
898    #[strum(serialize = "Right-Of-Way Rule Type")]
899    RightOfWay,
900    #[strum(serialize = "Vehicle-Stop-In-Zone-Behavior Rule Type")]
901    VehicleStopInZoneBehavior,
902    #[strum(serialize = "Speed-Limit Rule Type")]
903    SpeedLimit,
904}
905
906impl RuleType {
907    /// Gets the Rule ID for the [RuleType] and `lane_id`.
908    ///
909    /// # Arguments
910    /// - `lane_id` - The lane ID to get the rule ID from.
911    ///
912    /// # Returns
913    /// A rule ID formatted the way the backend defines it.
914    pub fn get_rule_id(&self, lane_id: &str) -> String {
915        // We rely on maliput_malidrive which define the rule id as:
916        // "<rule_type>/<lane_id>"
917        self.to_string() + "/" + lane_id
918    }
919}
920
921/// Defines a base state for a rule.
922///
923/// # RuleStateBase
924///
925/// - `severity` - The severity of the rule state.
926/// - `related_rules` - A map of related rules. The key is the group name and the value is a vector of rule ids.
927/// - `related_unique_ids` - A map of related unique ids. The key is the group name and the value is a vector of unique ids.
928///
929/// See [DiscreteValueRule] and [RangeValueRule] for more information.
930pub struct RuleStateBase {
931    /// Severity of the rule's state. A non-negative quantity that specifies the
932    /// level of enforcement. The smaller it is, the more strictly the rule is
933    /// enforced. Each rule type can define its own set of severity level
934    /// semantics.
935    severity: i32,
936    related_rules: cxx::UniquePtr<cxx::CxxVector<maliput_sys::api::rules::ffi::RelatedRule>>,
937    related_unique_ids: cxx::UniquePtr<cxx::CxxVector<maliput_sys::api::rules::ffi::RelatedUniqueId>>,
938}
939
940/// A trait representing a possible state of a `Rule`.
941///
942/// A `Rule` can have multiple states that affect agent behavior. This trait
943/// provides a common interface for accessing the properties shared by all
944/// rule states, such as severity and related rules.
945///
946/// This trait is implemented by specific state types like [`DiscreteValue`]
947/// and [`Range`].
948///
949/// # Implementors
950///
951/// When implementing this trait, you must provide an implementation for the
952/// [`get_rule_state()`] method, which gives access to the underlying
953/// [`RuleStateBase`] data. The other methods have default implementations.
954pub trait RuleState {
955    /// Gets the underlying [`RuleStateBase`] that contains common state properties.
956    ///
957    /// # Returns
958    /// A reference to the [`RuleStateBase`] that contains the severity, related rules,
959    /// and related unique ids for the rule state.
960    fn get_rule_state(&self) -> &RuleStateBase;
961
962    /// Returns the severity of the rule state.
963    ///
964    /// # Returns
965    /// An `i32` representing the severity of the rule state.
966    /// 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.
967    fn severity(&self) -> i32 {
968        self.get_rule_state().severity
969    }
970
971    /// Returns a map of related rules ids. The key is the group name and the value is a vector of rule ids.
972    ///
973    /// # Returns
974    /// A map of related rules where the key is the group name and the value is a vector of rule ids.
975    fn related_rules(&self) -> std::collections::HashMap<&String, &Vec<String>> {
976        self.get_rule_state()
977            .related_rules
978            .iter()
979            .map(|rr| (&rr.group_name, &rr.rule_ids))
980            .collect::<std::collections::HashMap<&String, &Vec<String>>>()
981    }
982    /// Returns a map of related unique ids. The key is the group name and the value is a vector of unique ids.
983    ///
984    /// # Returns
985    /// A map of related unique ids where the key is the group name and the value is a vector of unique ids.
986    fn related_unique_ids(&self) -> std::collections::HashMap<&String, &Vec<String>> {
987        self.get_rule_state()
988            .related_unique_ids
989            .iter()
990            .map(|rui| (&rui.group_name, &rui.unique_ids))
991            .collect::<std::collections::HashMap<&String, &Vec<String>>>()
992    }
993}
994
995/// Defines a discrete value for a [DiscreteValueRule].
996/// It extends the [RuleStateBase] with the value of the discrete value.
997pub struct DiscreteValue {
998    rule_state: RuleStateBase,
999    value: String,
1000}
1001
1002impl RuleState for DiscreteValue {
1003    fn get_rule_state(&self) -> &RuleStateBase {
1004        &self.rule_state
1005    }
1006}
1007
1008impl DiscreteValue {
1009    /// Returns the value of the discrete value.
1010    pub fn value(&self) -> &String {
1011        &self.value
1012    }
1013}
1014
1015impl std::fmt::Debug for DiscreteValue {
1016    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1017        write!(
1018            f,
1019            "DiscreteValue {{ value: {}, severity: {}, related_rules: {:?}, related_unique_ids: {:?} }}",
1020            self.value(),
1021            self.severity(),
1022            self.related_rules(),
1023            self.related_unique_ids()
1024        )
1025    }
1026}
1027
1028/// Defines a range value for a [RangeValueRule].
1029/// It extends the [RuleStateBase] with the description, and min and max values of the range.
1030pub struct Range {
1031    rule_state: RuleStateBase,
1032    description: String,
1033    min: f64,
1034    max: f64,
1035}
1036
1037impl RuleState for Range {
1038    fn get_rule_state(&self) -> &RuleStateBase {
1039        &self.rule_state
1040    }
1041}
1042
1043impl Range {
1044    /// Returns the description of the range value.
1045    pub fn description(&self) -> &String {
1046        &self.description
1047    }
1048    /// Returns the minimum value of the range.
1049    pub fn min(&self) -> f64 {
1050        self.min
1051    }
1052    /// Returns the maximum value of the range.
1053    pub fn max(&self) -> f64 {
1054        self.max
1055    }
1056}
1057
1058/// Defines a phase in a traffic rule system.
1059///
1060/// A phase represents a specific state or configuration of traffic signals
1061/// and semantic rules within a traffic control system. Each phase has a unique
1062/// identifier and may include various traffic signal states and rule configurations
1063/// that dictate how traffic should behave during that phase.
1064pub struct Phase {
1065    phase: cxx::UniquePtr<maliput_sys::api::rules::ffi::Phase>,
1066}
1067
1068impl Phase {
1069    /// Gets the id of the [Phase].
1070    ///
1071    /// # Returns
1072    /// The id of the [Phase].
1073    pub fn id(&self) -> String {
1074        maliput_sys::api::rules::ffi::Phase_id(&self.phase)
1075    }
1076
1077    /// Gets the states of all discrete value rules for this phase.
1078    ///
1079    /// # Returns
1080    /// A `HashMap` where the key is the rule ID as a [String] and the value is the
1081    /// [DiscreteValue] state of that rule.
1082    pub fn discrete_value_rule_states(&self) -> HashMap<String, DiscreteValue> {
1083        let rule_states = maliput_sys::api::rules::ffi::Phase_discrete_value_rule_states(&self.phase);
1084        rule_states
1085            .iter()
1086            .map(|state| {
1087                (
1088                    state.rule_id.clone(),
1089                    discrete_value_from_discrete_value_cxx(&state.state),
1090                )
1091            })
1092            .collect()
1093    }
1094
1095    /// Obtains all [UniqueBulbId]s in the [Phase].
1096    ///
1097    /// # Returns
1098    /// A vector of [UniqueBulbId].
1099    pub fn unique_bulb_ids(&self) -> Vec<UniqueBulbId> {
1100        let unique_bulb_ids = maliput_sys::api::rules::ffi::Phase_unique_bulb_ids(&self.phase);
1101        unique_bulb_ids
1102            .iter()
1103            .map(|bulb_id| UniqueBulbId {
1104                unique_bulb_id: maliput_sys::api::rules::ffi::ptr_from_unique_bulb_id(bulb_id),
1105            })
1106            .collect()
1107    }
1108
1109    /// Returns the [BulbState] corresponding to a `bulb_id`.
1110    ///
1111    /// # Arguments
1112    /// * `unique_bulb_id` - The [UniqueBulbId] to get the [BulbState] from.
1113    ///
1114    /// # Returns
1115    /// The [BulbState] the `unique_bulb_id` is in, or [None] if the [UniqueBulbId] is not in this [Phase].
1116    pub fn bulb_state(&self, unique_bulb_id: &UniqueBulbId) -> Option<BulbState> {
1117        let bulb_state = maliput_sys::api::rules::ffi::Phase_bulb_state(&self.phase, &unique_bulb_id.unique_bulb_id);
1118        if bulb_state.is_null() {
1119            return None;
1120        }
1121        Some(match *bulb_state {
1122            maliput_sys::api::rules::ffi::BulbState::kOff => BulbState::Off,
1123            maliput_sys::api::rules::ffi::BulbState::kOn => BulbState::On,
1124            maliput_sys::api::rules::ffi::BulbState::kBlinking => BulbState::Blinking,
1125            _ => return None,
1126        })
1127    }
1128}
1129
1130/// Defines a phase that comes after another [Phase].
1131/// Used as a return type by:
1132///   - [PhaseRing::get_next_phases].
1133pub struct NextPhase {
1134    /// The next phase.
1135    pub next_phase: Phase,
1136    /// The default time before transitioning to the next phase. This is
1137    /// relative to when the current phase began. It is just a recommendation,
1138    /// the actual duration is determined by the PhaseProvider and may depend on
1139    /// events like a vehicle arriving at a left-turn lane or a pedestrian
1140    /// hitting a crosswalk button.
1141    pub duration_until: Option<f64>,
1142}
1143
1144/// Defines a ring of phases in a traffic rule system.
1145///
1146/// A phase ring represents a sequence of phases that a traffic control system
1147/// cycles through.
1148pub struct PhaseRing {
1149    phase_ring: cxx::UniquePtr<maliput_sys::api::rules::ffi::PhaseRing>,
1150}
1151
1152impl PhaseRing {
1153    /// Gets the id of the [PhaseRing].
1154    ///
1155    /// # Returns
1156    /// The id of the [PhaseRing].
1157    pub fn id(&self) -> String {
1158        maliput_sys::api::rules::ffi::PhaseRing_id(&self.phase_ring)
1159    }
1160
1161    /// Gets a [Phase] by its id
1162    ///
1163    /// # Arguments
1164    /// * `id` - The id of the [Phase].
1165    /// # Returns
1166    /// The [Phase] with the given id.
1167    /// If no [Phase] is found with the given id, return None.
1168    pub fn get_phase(&self, id: &String) -> Option<Phase> {
1169        let phase = maliput_sys::api::rules::ffi::PhaseRing_GetPhase(&self.phase_ring, id);
1170        if phase.is_null() {
1171            return None;
1172        }
1173        Some(Phase { phase })
1174    }
1175
1176    /// Returns the ids of all Phases in the PhaseRing.
1177    ///
1178    /// # Returns
1179    /// A vector of strings representing the ids of all Phases in the PhaseRing.
1180    pub fn phases(&self) -> Vec<String> {
1181        maliput_sys::api::rules::ffi::PhaseRing_phases_ids(&self.phase_ring)
1182    }
1183
1184    /// Returns the next phases for a given phase `id`.
1185    ///
1186    /// # Arguments
1187    /// * `id` - The id of the phase to get the next phases from.
1188    ///
1189    /// # Returns
1190    /// A `Result` containing a vector of [NextPhase]s.
1191    ///
1192    /// # Errors
1193    /// Returns a [MaliputError] if the provided `id` is not found in the [PhaseRing].
1194    pub fn get_next_phases(&self, id: &String) -> Result<Vec<NextPhase>, MaliputError> {
1195        let next_phases = maliput_sys::api::rules::ffi::PhaseRing_GetNextPhases(&self.phase_ring, id)?;
1196        Ok(next_phases
1197            .iter()
1198            .map(|np| NextPhase {
1199                next_phase: Phase {
1200                    phase: maliput_sys::api::rules::ffi::PhaseRing_GetPhase(&self.phase_ring, &np.phase_id),
1201                },
1202                duration_until: if np.duration_until.is_null() {
1203                    None
1204                } else {
1205                    Some(np.duration_until.value)
1206                },
1207            })
1208            .collect())
1209    }
1210}
1211
1212/// Defines a book of phase rings in a traffic rule system.
1213pub struct PhaseRingBook<'a> {
1214    pub(super) phase_ring_book: &'a maliput_sys::api::rules::ffi::PhaseRingBook,
1215}
1216
1217impl<'a> PhaseRingBook<'a> {
1218    /// Returns the ids of all PhaseRings in the PhaseRingBook.
1219    ///
1220    /// # Returns
1221    /// A vector of strings representing the ids of all PhaseRings in the PhaseRingBook.
1222    pub fn get_phase_rings_ids(&self) -> Vec<String> {
1223        maliput_sys::api::rules::ffi::PhaseRingBook_GetPhaseRingsId(self.phase_ring_book)
1224    }
1225
1226    /// Returns the PhaseRing with the specified `id`.
1227    ///
1228    /// # Arguments
1229    /// * `phase_ring_id` - The id of the phase ring.
1230    ///
1231    /// # Returns
1232    /// The PhaseRing with the given id or None if the id is not in the PhaseRingBook.
1233    pub fn get_phase_ring(&self, phase_ring_id: &String) -> Option<PhaseRing> {
1234        let phase_ring = maliput_sys::api::rules::ffi::PhaseRingBook_GetPhaseRing(self.phase_ring_book, phase_ring_id);
1235        if phase_ring.is_null() {
1236            return None;
1237        }
1238        Some(PhaseRing { phase_ring })
1239    }
1240
1241    /// Finds the [PhaseRing] that contains the rule with the specified `rule_id`.
1242    ///
1243    /// # Arguments
1244    /// * `rule_id` - The id of the rule.
1245    ///
1246    /// # Returns
1247    /// The [PhaseRing] that contains the rule with the given id or `None` if no [PhaseRing] is found.
1248    pub fn find_phase_ring(&self, rule_id: &String) -> Option<PhaseRing> {
1249        let phase_ring = maliput_sys::api::rules::ffi::PhaseRingBook_FindPhaseRing(self.phase_ring_book, rule_id);
1250        if phase_ring.is_null() {
1251            return None;
1252        }
1253        Some(PhaseRing { phase_ring })
1254    }
1255}
1256
1257// Auxiliary method to create a [Vec<Range>] from a [cxx::Vector<RangeValueRuleRange>].
1258fn range_values_from_cxx(
1259    range_values_cxx: &cxx::Vector<maliput_sys::api::rules::ffi::RangeValueRuleRange>,
1260) -> Vec<Range> {
1261    range_values_cxx
1262        .iter()
1263        .map(|range| Range {
1264            rule_state: RuleStateBase {
1265                severity: maliput_sys::api::rules::ffi::RangeValueRuleRange_severity(range),
1266                related_rules: maliput_sys::api::rules::ffi::RangeValueRuleRange_related_rules(range),
1267                related_unique_ids: maliput_sys::api::rules::ffi::RangeValueRuleRange_related_unique_ids(range),
1268            },
1269            description: maliput_sys::api::rules::ffi::RangeValueRuleRange_description(range),
1270            min: maliput_sys::api::rules::ffi::RangeValueRuleRange_min(range),
1271            max: maliput_sys::api::rules::ffi::RangeValueRuleRange_max(range),
1272        })
1273        .collect()
1274}
1275
1276// Auxiliary method to create a [Vec<DiscreteValue>] from a [cxx::Vector<DiscreteValueRuleDiscreteValue>].
1277fn discrete_values_from_cxx(
1278    discrete_values_cxx: &cxx::Vector<maliput_sys::api::rules::ffi::DiscreteValueRuleDiscreteValue>,
1279) -> Vec<DiscreteValue> {
1280    discrete_values_cxx
1281        .iter()
1282        .map(discrete_value_from_discrete_value_cxx)
1283        .collect()
1284}
1285
1286// Auxiliary method to create a [DiscreteValue] from a [maliput_sys::api::rules::ffi::DiscreteValueRuleDiscreteValue].
1287fn discrete_value_from_discrete_value_cxx(
1288    discrete_value: &maliput_sys::api::rules::ffi::DiscreteValueRuleDiscreteValue,
1289) -> DiscreteValue {
1290    DiscreteValue {
1291        rule_state: RuleStateBase {
1292            severity: maliput_sys::api::rules::ffi::DiscreteValueRuleDiscreteValue_severity(discrete_value),
1293            related_rules: maliput_sys::api::rules::ffi::DiscreteValueRuleDiscreteValue_related_rules(discrete_value),
1294            related_unique_ids: maliput_sys::api::rules::ffi::DiscreteValueRuleDiscreteValue_related_unique_ids(
1295                discrete_value,
1296            ),
1297        },
1298        value: maliput_sys::api::rules::ffi::DiscreteValueRuleDiscreteValue_value(discrete_value),
1299    }
1300}