Skip to content

Commit

Permalink
Add rust API for DiscreteValue and Range. (#120)
Browse files Browse the repository at this point in the history
Signed-off-by: Franco Cipollone <[email protected]>
  • Loading branch information
francocipollone committed Jun 11, 2024
1 parent e43b3db commit bfa8a91
Show file tree
Hide file tree
Showing 4 changed files with 330 additions and 2 deletions.
7 changes: 5 additions & 2 deletions maliput-sys/src/api/rules/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ pub mod ffi {
/// This is needed because maps can't be binded directly.
struct RelatedUniqueId {
pub group_name: String,
pub unique_id: Vec<String>,
pub unique_ids: Vec<String>,
}

#[repr(i32)]
Expand Down Expand Up @@ -187,7 +187,10 @@ pub mod ffi {
fn RangeValueRuleRange_description(range: &RangeValueRuleRange) -> String;
fn RangeValueRuleRange_min(range: &RangeValueRuleRange) -> f64;
fn RangeValueRuleRange_max(range: &RangeValueRuleRange) -> f64;

fn RangeValueRuleRange_severity(range: &RangeValueRuleRange) -> i32;
fn RangeValueRuleRange_related_rules(range: &RangeValueRuleRange) -> UniquePtr<CxxVector<RelatedRule>>;
fn RangeValueRuleRange_related_unique_ids(range: &RangeValueRuleRange)
-> UniquePtr<CxxVector<RelatedUniqueId>>;
// RangeValueRule::Range bindings definitions.
type RangeValueRule;
fn RangeValueRule_id(rule: &RangeValueRule) -> String;
Expand Down
139 changes: 139 additions & 0 deletions maliput/src/api/rules/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,27 @@ impl DiscreteValueRule {
pub fn type_id(&self) -> String {
maliput_sys::api::rules::ffi::DiscreteValueRule_type_id(&self.discrete_value_rule)
}
/// Returns a [LaneSRoute] that represents the zone that the rule applies to.
pub fn zone(&self) {
unimplemented!("Not yet implemented")
}
/// Returns the states of the rule.
pub fn states(&self) -> Vec<DiscreteValue> {
let states_cpp = &self.discrete_value_rule.states();
states_cpp
.into_iter()
.map(|dv| DiscreteValue {
rule_state: RuleStateBase {
severity: maliput_sys::api::rules::ffi::DiscreteValueRuleDiscreteValue_severity(dv),
related_rules: maliput_sys::api::rules::ffi::DiscreteValueRuleDiscreteValue_related_rules(dv),
related_unique_ids: maliput_sys::api::rules::ffi::DiscreteValueRuleDiscreteValue_related_unique_ids(
dv,
),
},
value: maliput_sys::api::rules::ffi::DiscreteValueRuleDiscreteValue_value(dv),
})
.collect::<Vec<DiscreteValue>>()
}
}

/// ## Rule
Expand Down Expand Up @@ -580,4 +601,122 @@ impl RangeValueRule {
pub fn type_id(&self) -> String {
maliput_sys::api::rules::ffi::RangeValueRule_type_id(&self.range_value_rule)
}
/// Returns a [LaneSRoute] that represents the zone that the rule applies to.
pub fn zone(&self) {
unimplemented!("Not yet implemented")
}
/// Returns the states of the rule.
pub fn states(&self) -> Vec<Range> {
let states_cpp = &self.range_value_rule.states();
states_cpp
.into_iter()
.map(|r| Range {
rule_state: RuleStateBase {
severity: maliput_sys::api::rules::ffi::RangeValueRuleRange_severity(r),
related_rules: maliput_sys::api::rules::ffi::RangeValueRuleRange_related_rules(r),
related_unique_ids: maliput_sys::api::rules::ffi::RangeValueRuleRange_related_unique_ids(r),
},
description: maliput_sys::api::rules::ffi::RangeValueRuleRange_description(r),
min: maliput_sys::api::rules::ffi::RangeValueRuleRange_min(r),
max: maliput_sys::api::rules::ffi::RangeValueRuleRange_max(r),
})
.collect::<Vec<Range>>()
}
}

/// Defines a base state for a rule.
///
/// ## RuleStateBase
///
/// - `severity` - The severity of the rule state.
/// - `related_rules` - A map of related rules. The key is the group name and the value is a vector of rule ids.
/// - `related_unique_ids` - A map of related unique ids. The key is the group name and the value is a vector of unique ids.
///
/// See [DiscreteValueRule] and [RangeValueRule] for more information.
pub struct RuleStateBase {
severity: i32,
related_rules: cxx::UniquePtr<cxx::CxxVector<maliput_sys::api::rules::ffi::RelatedRule>>,
related_unique_ids: cxx::UniquePtr<cxx::CxxVector<maliput_sys::api::rules::ffi::RelatedUniqueId>>,
}

/// Defines the interface for a rule state.
/// ## To implement by the trait user.
/// - `get_rule_state` - Returns the base state of the rule.
/// To be implemented by the concrete rule state.
pub trait RuleState {
/// Returns the base state of the rule.
/// To be implemented by the concrete rule state.
fn get_rule_state(&self) -> &RuleStateBase;

/// Returns the severity of the rule state.
fn severity(&self) -> i32 {
self.get_rule_state().severity
}

/// Returns a map of related unique ids. The key is the group name and the value is a vector of unique ids.
fn related_rules(&self) -> std::collections::HashMap<&String, &Vec<String>> {
self.get_rule_state()
.related_rules
.iter()
.map(|rr| (&rr.group_name, &rr.rule_ids))
.collect::<std::collections::HashMap<&String, &Vec<String>>>()
}
/// Returns a map of related unique ids. The key is the group name and the value is a vector of unique ids.
fn related_unique_ids(&self) -> std::collections::HashMap<&String, &Vec<String>> {
self.get_rule_state()
.related_unique_ids
.iter()
.map(|rui| (&rui.group_name, &rui.unique_ids))
.collect::<std::collections::HashMap<&String, &Vec<String>>>()
}
}

/// Defines a discrete value for a [DiscreteValueRule].
/// It extends the [RuleStateBase] with the value of the discrete value.
pub struct DiscreteValue {
rule_state: RuleStateBase,
value: String,
}

impl RuleState for DiscreteValue {
fn get_rule_state(&self) -> &RuleStateBase {
&self.rule_state
}
}

impl DiscreteValue {
/// Returns the value of the discrete value.
pub fn value(&self) -> &String {
&self.value
}
}

/// Defines a range value for a [RangeValueRule].
/// It extends the [RuleStateBase] with the description, and min and max values of the range.
pub struct Range {
rule_state: RuleStateBase,
description: String,
min: f64,
max: f64,
}

impl RuleState for Range {
fn get_rule_state(&self) -> &RuleStateBase {
&self.rule_state
}
}

impl Range {
/// Returns the description of the range value.
pub fn description(&self) -> &String {
&self.description
}
/// Returns the minimum value of the range.
pub fn min(&self) -> f64 {
self.min
}
/// Returns the maximum value of the range.
pub fn max(&self) -> f64 {
self.max
}
}
123 changes: 123 additions & 0 deletions maliput/tests/discrete_value_rule_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// BSD 3-Clause License
//
// Copyright (c) 2024, Woven by Toyota.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
mod common;

// LoopRoadPedestrianCrosswalk map is being used to test the discrete value rule API and its components.
// YAML information about the RoadRulebook can be found at:
// https://github.com/maliput/maliput_malidrive/blob/352601969b1363cc13fe2008c198a3d95843bf5b/resources/LoopRoadPedestrianCrosswalk.yaml#L64

#[test]
fn discrete_value_rule_test_api() {
use maliput::api::rules::RuleState;

let road_network = common::create_loop_road_pedestrian_crosswalk_road_network_with_books();

let book = road_network.rulebook();
let expected_rule_id = String::from("Right-Of-Way Rule Type/WestToEastSouth");
let expected_type_id = String::from("Right-Of-Way Rule Type");
let rule = book.get_discrete_value_rule(&expected_rule_id);
assert_eq!(rule.id(), expected_rule_id);
assert_eq!(rule.type_id(), expected_type_id);

let states = rule.states();
assert_eq!(states.len(), 2); // Go and Stop

// Find DiscreteValue with value "Go"
let expected_value = "Go";
let go_discrete_value = states.iter().find(|state| state.value() == expected_value).unwrap();
assert_eq!(go_discrete_value.value(), expected_value);

let severity = go_discrete_value.severity();
assert_eq!(severity, 0);

let related_rules = go_discrete_value.related_rules();
assert_eq!(related_rules.len(), 1);
let related_rule_group = String::from("Vehicle-Stop-In-Zone-Behavior Rule Type");
let related_rules_for_vehicle_stop_behavior_group = related_rules
.get(&related_rule_group)
.expect("Related rule group not found");
assert_eq!(related_rules_for_vehicle_stop_behavior_group.len(), 1);
assert_eq!(
related_rules_for_vehicle_stop_behavior_group
.first()
.expect("Related rule not found"),
"Vehicle-Stop-In-Zone-Behavior Rule Type/WestToEastSouth"
);

let related_unique_ids = go_discrete_value.related_unique_ids();
assert_eq!(related_unique_ids.len(), 1);
let related_unique_id_group = String::from("Bulb Group");
let related_unique_ids_for_bulb_group = related_unique_ids
.get(&related_unique_id_group)
.expect("Related unique id group not found");
assert_eq!(related_unique_ids_for_bulb_group.len(), 1);
assert_eq!(
related_unique_ids_for_bulb_group
.first()
.expect("Related unique id not found"),
"WestFacingSouth-WestFacingBulbsSouth"
);

// Find DiscreteValue with value "Stop"
let expected_value = "Stop";
let stop_discrete_value = states.iter().find(|state| state.value() == expected_value).unwrap();
assert_eq!(stop_discrete_value.value(), expected_value);

let severity = go_discrete_value.severity();
assert_eq!(severity, 0);

let related_rules = stop_discrete_value.related_rules();
assert_eq!(related_rules.len(), 1);
let related_rule_group = String::from("Vehicle-Stop-In-Zone-Behavior Rule Type");
let related_rules_for_vehicle_stop_behavior_group = related_rules
.get(&related_rule_group)
.expect("Related rule group not found");
assert_eq!(related_rules_for_vehicle_stop_behavior_group.len(), 1);
assert_eq!(
related_rules_for_vehicle_stop_behavior_group
.first()
.expect("Related rule not found"),
"Vehicle-Stop-In-Zone-Behavior Rule Type/WestToEastSouth"
);

let related_unique_ids = stop_discrete_value.related_unique_ids();
assert_eq!(related_unique_ids.len(), 1);
let related_unique_id_group = String::from("Bulb Group");
let related_unique_ids_for_bulb_group = related_unique_ids
.get(&related_unique_id_group)
.expect("Related unique id group not found");
assert_eq!(related_unique_ids_for_bulb_group.len(), 1);
assert_eq!(
related_unique_ids_for_bulb_group
.first()
.expect("Related unique id not found"),
"WestFacingSouth-WestFacingBulbsSouth"
);
}
63 changes: 63 additions & 0 deletions maliput/tests/range_value_rule_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// BSD 3-Clause License
//
// Copyright (c) 2024, Woven by Toyota.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
mod common;

// LoopRoadPedestrianCrosswalk map is being used to test the discrete value rule API and its components.
// YAML information about the RoadRulebook can be found at:
// https://github.com/maliput/maliput_malidrive/blob/352601969b1363cc13fe2008c198a3d95843bf5b/resources/LoopRoadPedestrianCrosswalk.yaml#L64

#[test]
fn range_value_rule_test_api() {
use maliput::api::rules::RuleState;

let road_network = common::create_loop_road_pedestrian_crosswalk_road_network_with_books();

let book = road_network.rulebook();
let expected_rule_id = String::from("Speed-Limit Rule Type/1_0_1_1");
let expected_type_id = String::from("Speed-Limit Rule Type");
let rule = book.get_range_value_rule(&expected_rule_id);
assert_eq!(rule.id(), expected_rule_id);
assert_eq!(rule.type_id(), expected_type_id);

let states = rule.states();
assert_eq!(states.len(), 1); // Only one speed limit state
let speed_limit_state = states.first().expect("State not found");
assert_eq!(speed_limit_state.description(), "m/s");
assert_eq!(speed_limit_state.min(), 0.);
assert_eq!(speed_limit_state.max(), 11.11111111111111);

let severity = speed_limit_state.severity();
assert_eq!(severity, 0);

let related_rules = speed_limit_state.related_rules();
assert_eq!(related_rules.len(), 0);
let related_unique_ids = speed_limit_state.related_unique_ids();
assert_eq!(related_unique_ids.len(), 0);
}

0 comments on commit bfa8a91

Please sign in to comment.