Adds a hack to generate constants associated to the message types.
This commit is contained in:
parent
ef0ea2a514
commit
16f73aed4b
|
|
@ -770,4 +770,14 @@ mod tests {
|
||||||
// the message should contain something (default msg)
|
// the message should contain something (default msg)
|
||||||
assert!(!json_request.to_string().is_empty());
|
assert!(!json_request.to_string().is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(r2r__action_msgs__msg__GoalStatus)]
|
||||||
|
#[test]
|
||||||
|
fn test_msg_constants() {
|
||||||
|
use action_msgs::msg::GoalStatus;
|
||||||
|
let gs = GoalStatus::default();
|
||||||
|
|
||||||
|
assert_eq!(gs.status, GoalStatus::STATUS_UNKNOWN as i8);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,16 @@ use r2r_common::RosMsg;
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::{env, fs};
|
use std::{env, fs};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
const MSG_INCLUDES_FILENAME: &str = "msg_includes.h";
|
const MSG_INCLUDES_FILENAME: &str = "msg_includes.h";
|
||||||
const INTROSPECTION_FILENAME: &str = "introspection_functions.rs";
|
const INTROSPECTION_FILENAME: &str = "introspection_functions.rs";
|
||||||
|
const CONSTANTS_FILENAME: &str = "constants.rs";
|
||||||
const BINDINGS_FILENAME: &str = "msg_bindings.rs";
|
const BINDINGS_FILENAME: &str = "msg_bindings.rs";
|
||||||
const GENERATED_FILES: &[&str] = &[
|
const GENERATED_FILES: &[&str] = &[
|
||||||
MSG_INCLUDES_FILENAME,
|
MSG_INCLUDES_FILENAME,
|
||||||
INTROSPECTION_FILENAME,
|
INTROSPECTION_FILENAME,
|
||||||
|
CONSTANTS_FILENAME,
|
||||||
BINDINGS_FILENAME,
|
BINDINGS_FILENAME,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -76,6 +79,7 @@ fn run_bindgen(msg_list: &[RosMsg]) {
|
||||||
fn generate_bindings(bindgen_dir: &Path, msg_list: &[RosMsg]) {
|
fn generate_bindings(bindgen_dir: &Path, msg_list: &[RosMsg]) {
|
||||||
let msg_includes_file = bindgen_dir.join(MSG_INCLUDES_FILENAME);
|
let msg_includes_file = bindgen_dir.join(MSG_INCLUDES_FILENAME);
|
||||||
let introspection_file = bindgen_dir.join(INTROSPECTION_FILENAME);
|
let introspection_file = bindgen_dir.join(INTROSPECTION_FILENAME);
|
||||||
|
let constants_file = bindgen_dir.join(CONSTANTS_FILENAME);
|
||||||
let bindings_file = bindgen_dir.join(BINDINGS_FILENAME);
|
let bindings_file = bindgen_dir.join(BINDINGS_FILENAME);
|
||||||
|
|
||||||
let mut includes = String::new();
|
let mut includes = String::new();
|
||||||
|
|
@ -170,6 +174,55 @@ fn generate_bindings(bindgen_dir: &Path, msg_list: &[RosMsg]) {
|
||||||
|
|
||||||
let bindings = builder.generate().expect("Unable to generate bindings");
|
let bindings = builder.generate().expect("Unable to generate bindings");
|
||||||
|
|
||||||
|
// Let's add a hack to generate constants.
|
||||||
|
let str_bindings = bindings.to_string();
|
||||||
|
// find all lines which look suspiciosly like a constant.
|
||||||
|
let mut constants: HashMap<String, Vec<(String,String)>> = HashMap::new();
|
||||||
|
for msg in msg_list {
|
||||||
|
let prefix = &format!("pub const {}__{}__{}__", &msg.module, &msg.prefix, &msg.name);
|
||||||
|
let mut lines = str_bindings.lines();
|
||||||
|
while let Some(line) = lines.next() {
|
||||||
|
if let Some(constant) = line.strip_prefix(prefix) {
|
||||||
|
if let Some((con, typ)) = constant.split_once(":") {
|
||||||
|
// These are generated automatically for arrays and strings, we don't need to expose them.
|
||||||
|
if con.ends_with("__MAX_SIZE") || con.ends_with("__MAX_STRING_SIZE") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let key = format!("{}__{}__{}", msg.module, msg.prefix, msg.name);
|
||||||
|
if let Some((t, _)) = typ.split_once("=") {
|
||||||
|
constants.entry(key).or_default().push((con.to_string(), t.trim().to_string()));
|
||||||
|
} else if let Some(next_line) = lines.next() {
|
||||||
|
// type has moved down to the next line. (bindgen has a max line width)
|
||||||
|
if let Some((t, _)) = next_line.split_once("=") {
|
||||||
|
constants.entry(key).or_default().push((con.to_string(), t.trim().to_string()));
|
||||||
|
} else {
|
||||||
|
panic!("Code generation failure. Type not found in line! {}", next_line);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("Code generation failure. Type not found in line! {}", line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// generate a constant which holds all constants.
|
||||||
|
let mut constants_map = String::from(
|
||||||
|
"\
|
||||||
|
lazy_static! {
|
||||||
|
static ref CONSTANTS_MAP: HashMap<&'static str, Vec<(String,String)>> = {
|
||||||
|
let mut m = HashMap::new();\
|
||||||
|
");
|
||||||
|
for (msg,msg_constants) in constants {
|
||||||
|
let msg_constants_str = format!("vec![{}]",
|
||||||
|
msg_constants.iter()
|
||||||
|
.map(|(c,t)| format!("(\"{c}\".to_string(), \"{t}\".to_string())"))
|
||||||
|
.collect::<Vec<String>>().join(","));
|
||||||
|
|
||||||
|
constants_map.push_str(&format!("m.insert(\"{}\", {});\n", msg, msg_constants_str));
|
||||||
|
}
|
||||||
|
constants_map.push_str("m \n }; }\n\n");
|
||||||
|
fs::write(&constants_file, constants_map).unwrap();
|
||||||
|
|
||||||
bindings
|
bindings
|
||||||
.write_to_file(bindings_file)
|
.write_to_file(bindings_file)
|
||||||
.expect("Couldn't write bindings!");
|
.expect("Couldn't write bindings!");
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
#![allow(clippy::all)]
|
#![allow(clippy::all)]
|
||||||
include!(concat!(env!("OUT_DIR"), "/msg_bindings.rs"));
|
include!(concat!(env!("OUT_DIR"), "/msg_bindings.rs"));
|
||||||
include!(concat!(env!("OUT_DIR"), "/introspection_functions.rs"));
|
include!(concat!(env!("OUT_DIR"), "/introspection_functions.rs"));
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/constants.rs"));
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
|
@ -602,6 +603,23 @@ pub fn generate_rust_msg(module_: &str, prefix_: &str, name_: &str) -> String {
|
||||||
msgname = name
|
msgname = name
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
let constants = CONSTANTS_MAP.get(key.as_str()).cloned().unwrap_or_default();
|
||||||
|
let mut constant_strings = vec![];
|
||||||
|
for (c, typ) in constants {
|
||||||
|
constant_strings.push(format!(" pub const {c}: {typ} = {key}__{c};"));
|
||||||
|
}
|
||||||
|
let impl_constants = format!("
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
impl {msgname} {{
|
||||||
|
{constants}
|
||||||
|
}}
|
||||||
|
",
|
||||||
|
msgname = name,
|
||||||
|
constants = constant_strings.join("\n")
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
let module_str = format!(
|
let module_str = format!(
|
||||||
"
|
"
|
||||||
#[derive(Clone,Debug,PartialEq,Serialize,Deserialize)]
|
#[derive(Clone,Debug,PartialEq,Serialize,Deserialize)]
|
||||||
|
|
@ -610,12 +628,14 @@ pub fn generate_rust_msg(module_: &str, prefix_: &str, name_: &str) -> String {
|
||||||
{fields}
|
{fields}
|
||||||
}}\n
|
}}\n
|
||||||
{typesupport}\n
|
{typesupport}\n
|
||||||
{default}\n\n
|
{default}\n
|
||||||
|
{constants}\n\n
|
||||||
",
|
",
|
||||||
msgname = name,
|
msgname = name,
|
||||||
fields = fields,
|
fields = fields,
|
||||||
typesupport = typesupport,
|
typesupport = typesupport,
|
||||||
default = impl_default
|
default = impl_default,
|
||||||
|
constants = impl_constants,
|
||||||
);
|
);
|
||||||
|
|
||||||
module_str
|
module_str
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue