Make the order of parameters deterministic
GUI tools for working with parameters (at least Foxglove Studio, rqt and rig_reconfigure) show the parameters in the same order as returned by the ListParameters service. r2r stores the parameters in a HashMap, which iterates keys and values in arbitrary order. The result is that the GUI tools show the parameters in different order after every node invocation, which can be quite annoying. To make the order deterministic, we change the parameter storage from HashMap to IndexMap, which iterates the map in insertion order. According to the indexmap documentation, IndexMap is a drop-in replacement of HashMap so this change should not require code changes in applications using r2r. At least r2r examples and my projects needed no changes.
This commit is contained in:
parent
b46e3744b2
commit
e9f375e8f6
|
|
@ -27,6 +27,7 @@ uuid = { version = "1.2.2", features = ["serde", "v4"] }
|
||||||
futures = "0.3.25"
|
futures = "0.3.25"
|
||||||
log = "0.4.18"
|
log = "0.4.18"
|
||||||
phf = "0.11.1"
|
phf = "0.11.1"
|
||||||
|
indexmap = "2.2.6"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serde_json = "1.0.89"
|
serde_json = "1.0.89"
|
||||||
|
|
|
||||||
|
|
@ -71,8 +71,9 @@
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
// otherwise crates using r2r needs to specify the same version of uuid as
|
// otherwise crates using r2r needs to specify the same version of indexmap and uuid as
|
||||||
// this crate depend on, which seem like bad user experience.
|
// this crate depend on, which seem like bad user experience.
|
||||||
|
pub extern crate indexmap;
|
||||||
pub extern crate uuid;
|
pub extern crate uuid;
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ use futures::{
|
||||||
future::{self, join_all, FutureExt, TryFutureExt},
|
future::{self, join_all, FutureExt, TryFutureExt},
|
||||||
stream::{Stream, StreamExt},
|
stream::{Stream, StreamExt},
|
||||||
};
|
};
|
||||||
|
use indexmap::IndexMap;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
ffi::{CStr, CString},
|
ffi::{CStr, CString},
|
||||||
|
|
@ -43,7 +44,7 @@ use crate::{
|
||||||
pub struct Node {
|
pub struct Node {
|
||||||
context: Context,
|
context: Context,
|
||||||
/// ROS parameters.
|
/// ROS parameters.
|
||||||
pub params: Arc<Mutex<HashMap<String, Parameter>>>,
|
pub params: Arc<Mutex<IndexMap<String, Parameter>>>,
|
||||||
pub(crate) node_handle: Box<rcl_node_t>,
|
pub(crate) node_handle: Box<rcl_node_t>,
|
||||||
// the node owns the subscribers
|
// the node owns the subscribers
|
||||||
pub(crate) subscribers: Vec<Box<dyn Subscriber_>>,
|
pub(crate) subscribers: Vec<Box<dyn Subscriber_>>,
|
||||||
|
|
@ -198,7 +199,7 @@ impl Node {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut node = Node {
|
let mut node = Node {
|
||||||
params: Arc::new(Mutex::new(HashMap::new())),
|
params: Arc::new(Mutex::new(IndexMap::new())),
|
||||||
context: ctx,
|
context: ctx,
|
||||||
node_handle,
|
node_handle,
|
||||||
subscribers: Vec::new(),
|
subscribers: Vec::new(),
|
||||||
|
|
@ -460,7 +461,7 @@ impl Node {
|
||||||
|
|
||||||
fn handle_list_parameters(
|
fn handle_list_parameters(
|
||||||
req: ServiceRequest<rcl_interfaces::srv::ListParameters::Service>,
|
req: ServiceRequest<rcl_interfaces::srv::ListParameters::Service>,
|
||||||
params: &Arc<Mutex<HashMap<String, Parameter>>>,
|
params: &Arc<Mutex<IndexMap<String, Parameter>>>,
|
||||||
) -> future::Ready<()> {
|
) -> future::Ready<()> {
|
||||||
use rcl_interfaces::srv::ListParameters;
|
use rcl_interfaces::srv::ListParameters;
|
||||||
|
|
||||||
|
|
@ -503,7 +504,7 @@ impl Node {
|
||||||
|
|
||||||
fn handle_desc_parameters(
|
fn handle_desc_parameters(
|
||||||
req: ServiceRequest<rcl_interfaces::srv::DescribeParameters::Service>,
|
req: ServiceRequest<rcl_interfaces::srv::DescribeParameters::Service>,
|
||||||
params: &Arc<Mutex<HashMap<String, Parameter>>>,
|
params: &Arc<Mutex<IndexMap<String, Parameter>>>,
|
||||||
) -> future::Ready<()> {
|
) -> future::Ready<()> {
|
||||||
use rcl_interfaces::{msg::ParameterDescriptor, srv::DescribeParameters};
|
use rcl_interfaces::{msg::ParameterDescriptor, srv::DescribeParameters};
|
||||||
let mut descriptors = Vec::<ParameterDescriptor>::new();
|
let mut descriptors = Vec::<ParameterDescriptor>::new();
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
use crate::{Error, Result};
|
use crate::{Error, Result};
|
||||||
use std::{collections::HashMap, ffi::CStr};
|
use std::ffi::CStr;
|
||||||
|
|
||||||
use crate::msg_types::generated_msgs::rcl_interfaces;
|
use crate::msg_types::generated_msgs::rcl_interfaces;
|
||||||
|
use indexmap::IndexMap;
|
||||||
use r2r_rcl::*;
|
use r2r_rcl::*;
|
||||||
|
|
||||||
/// ROS parameter value.
|
/// ROS parameter value.
|
||||||
|
|
@ -190,7 +191,7 @@ impl Parameter {
|
||||||
/// `parameters_derive.rs` example.
|
/// `parameters_derive.rs` example.
|
||||||
pub trait RosParams {
|
pub trait RosParams {
|
||||||
fn register_parameters(
|
fn register_parameters(
|
||||||
&mut self, prefix: &str, param: Option<Parameter>, params: &mut HashMap<String, Parameter>,
|
&mut self, prefix: &str, param: Option<Parameter>, params: &mut IndexMap<String, Parameter>,
|
||||||
) -> Result<()>;
|
) -> Result<()>;
|
||||||
fn get_parameter(&mut self, param_name: &str) -> Result<ParameterValue>;
|
fn get_parameter(&mut self, param_name: &str) -> Result<ParameterValue>;
|
||||||
fn set_parameter(&mut self, param_name: &str, param_val: &ParameterValue) -> Result<()>;
|
fn set_parameter(&mut self, param_name: &str, param_val: &ParameterValue) -> Result<()>;
|
||||||
|
|
@ -202,7 +203,7 @@ macro_rules! impl_ros_params {
|
||||||
impl RosParams for $type {
|
impl RosParams for $type {
|
||||||
fn register_parameters(
|
fn register_parameters(
|
||||||
&mut self, prefix: &str, param: Option<Parameter>,
|
&mut self, prefix: &str, param: Option<Parameter>,
|
||||||
params: &mut HashMap<String, Parameter>,
|
params: &mut IndexMap<String, Parameter>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
if let Some(cli_param) = params.get(prefix) {
|
if let Some(cli_param) = params.get(prefix) {
|
||||||
// Apply parameter value if set from command line or launch file
|
// Apply parameter value if set from command line or launch file
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ pub fn derive_r2r_params(input: proc_macro::TokenStream) -> proc_macro::TokenStr
|
||||||
&mut self,
|
&mut self,
|
||||||
prefix: &str,
|
prefix: &str,
|
||||||
desc: ::std::option::Option<::r2r::Parameter>,
|
desc: ::std::option::Option<::r2r::Parameter>,
|
||||||
params: &mut ::std::collections::hash_map::HashMap<String, ::r2r::Parameter>,
|
params: &mut ::r2r::indexmap::IndexMap<String, ::r2r::Parameter>,
|
||||||
) -> ::r2r::Result<()> {
|
) -> ::r2r::Result<()> {
|
||||||
let prefix = if prefix.is_empty() {
|
let prefix = if prefix.is_empty() {
|
||||||
String::from("")
|
String::from("")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue