From ebe9287d766bb83e6a3e985f586cc6e93af1088f Mon Sep 17 00:00:00 2001 From: Martin Dahl Date: Mon, 10 May 2021 13:36:44 +0200 Subject: [PATCH] generation of action message types --- build.rs | 21 +++++++++++++++++++-- common/src/lib.rs | 25 ++++++++++++------------- msg_gen/build.rs | 9 ++++++++- msg_gen/src/lib.rs | 26 +++++++++++++++++++++++--- src/lib.rs | 34 ++++++++++++++++++++++++++++++++++ 5 files changed, 96 insertions(+), 19 deletions(-) diff --git a/build.rs b/build.rs index 683905f..71b517f 100644 --- a/build.rs +++ b/build.rs @@ -32,7 +32,22 @@ fn main() { for (prefix, msgs) in prefixes { codegen.push_str(&format!(" pub mod {} {{\n", prefix)); - if prefix == &"srv" { + if prefix == &"action" { + for msg in msgs { + codegen.push_str("#[allow(non_snake_case)]\n"); + codegen.push_str(&format!(" pub mod {} {{\n", msg)); + codegen.push_str(" use super::super::super::*;\n"); + + codegen.push_str(&msg_gen::generate_rust_action(module, prefix, msg)); + + for s in &["Goal", "Result", "Feedback"] { + let msgname = format!("{}_{}", msg, s); + codegen.push_str(&msg_gen::generate_rust_msg(module, prefix, &msgname)); + println!("cargo:rustc-cfg=r2r__{}__{}__{}", module, prefix, msg); + } + codegen.push_str(" }\n"); + } + } else if prefix == &"srv" { for msg in msgs { codegen.push_str("#[allow(non_snake_case)]\n"); codegen.push_str(&format!(" pub mod {} {{\n", msg)); @@ -47,12 +62,14 @@ fn main() { } codegen.push_str(" }\n"); } - } else { + } else if prefix == &"msg" { codegen.push_str(" use super::super::*;\n"); for msg in msgs { codegen.push_str(&msg_gen::generate_rust_msg(module, prefix, msg)); println!("cargo:rustc-cfg=r2r__{}__{}__{}", module, prefix, msg); } + } else { + panic!("unknown prefix type: {}", prefix); } codegen.push_str(" }\n"); diff --git a/common/src/lib.rs b/common/src/lib.rs index 60697c7..324e74d 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -57,6 +57,18 @@ fn get_msgs_from_package(package: &Path) -> Vec { msgs.push(srv_name); } } + if l.starts_with("action/") && (l.ends_with(".idl") || l.ends_with(".action")) { + if let Some(file_name_str) = file_name.to_str() { + let substr = if l.ends_with(".action") { + &l[7..l.len()-7] + } else { + &l[7..l.len()-4] // .idl + }; + let action_name = format!("{}/action/{}", file_name_str, substr); + println!("found action: {}", action_name); + msgs.push(action_name); + } + } }); } } @@ -80,19 +92,6 @@ pub fn get_ros_msgs(paths: &[&Path]) -> Vec { msgs } -#[test] -fn test_msg_list() { - - let msgs = get_all_ros_msgs(); - for m in &msgs { - println!("{}", m); - } - - assert!(msgs.contains(&"std_msgs/msg/String".to_string())); - assert!(msgs.contains(&"builtin_interfaces/msg/Time".to_string())); - -} - pub fn parse_msgs(msgs: &Vec) -> Vec { let v: Vec> = msgs.iter().map(|l| l.split("/").into_iter().take(3).collect()).collect(); let v: Vec<_> = v.iter().filter(|v|v.len() == 3). diff --git a/msg_gen/build.rs b/msg_gen/build.rs index 790c3f1..baa93c8 100644 --- a/msg_gen/build.rs +++ b/msg_gen/build.rs @@ -73,7 +73,14 @@ fn main() { let val = &format!("unsafe {{ rosidl_typesupport_introspection_c__get_message_type_support_handle__{}__{}__{}_{}() }} as *const i32 as usize", &msg.module, &msg.prefix, &msg.name, s); introspecion_map.push_str(&format!("m.insert(\"{}\", {});\n", key, val)); } - } else { + } else if msg.prefix == "action" { + for s in &["Goal", "Result", "Feedback"] { + let key = &format!("{}__{}__{}_{}", &msg.module, &msg.prefix, &msg.name, s); + let val = &format!("unsafe {{ rosidl_typesupport_introspection_c__get_message_type_support_handle__{}__{}__{}_{}() }} as *const i32 as usize", &msg.module, &msg.prefix, &msg.name, s); + introspecion_map.push_str(&format!("m.insert(\"{}\", {});\n", key, val)); + } + } + else { let key = &format!("{}__{}__{}", &msg.module, &msg.prefix, &msg.name); let val = &format!("unsafe {{ rosidl_typesupport_introspection_c__get_message_type_support_handle__{}__{}__{}() }} as *const i32 as usize", &msg.module, &msg.prefix, &msg.name); introspecion_map.push_str(&format!("m.insert(\"{}\", {});\n", key, val)); diff --git a/msg_gen/src/lib.rs b/msg_gen/src/lib.rs index 488e291..16632f9 100644 --- a/msg_gen/src/lib.rs +++ b/msg_gen/src/lib.rs @@ -119,6 +119,24 @@ pub fn generate_rust_service(module_: &str, prefix_: &str, name_: &str) -> Strin ", module_, prefix_, name_) } +pub fn generate_rust_action(module_: &str, prefix_: &str, name_: &str) -> String { + format!( + " + pub struct Action(); + impl WrappedActionTypeSupport for Action {{ + type Goal = Goal; + type Result = Result; + type Feedback = Feedback; + fn get_ts() -> &'static rosidl_action_type_support_t {{ + unsafe {{ + &*rosidl_typesupport_c__get_action_type_support_handle__{}__{}__{}() + }} + }} + }} + + ", module_, prefix_, name_) +} + // TODO: this is a terrible hack :) pub fn generate_rust_msg(module_: &str, prefix_: &str, name_: &str) -> String { @@ -133,9 +151,11 @@ pub fn generate_rust_msg(module_: &str, prefix_: &str, name_: &str) -> String { assert_eq!(prefix, prefix_); assert_eq!(name, name_); - if prefix == "srv" { + if prefix == "srv" || prefix == "action" { // for srv, the message name is both the service name and _Request or _Respone // we only want to keep the last part. + // same for actions with _Goal, _Result, _Feedback + // TODO: refactor... let mut nn = name.splitn(2, "_"); let _mod_name = nn.next().expect(&format!("malformed service name {}", name)); let msg_name = nn.next().expect(&format!("malformed service name {}", name)); @@ -380,8 +400,8 @@ impl WrappedNativeMsgUntyped { let mut lines = String::new(); for msg in msgs { - // for now don't generate untyped services - if msg.prefix == "srv" { continue; } + // for now don't generate untyped services or actions + if msg.prefix == "srv" || msg.prefix == "action" { continue; } let typename = format!("{}/{}/{}", msg.module, msg.prefix, msg.name); let rustname = format!("{}::{}::{}", msg.module, msg.prefix, msg.name); diff --git a/src/lib.rs b/src/lib.rs index 5bbe86a..c632eb7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,6 +38,14 @@ pub trait WrappedServiceTypeSupport { fn get_ts() -> &'static rosidl_service_type_support_t; } +pub trait WrappedActionTypeSupport { + type Goal: WrappedTypesupport; + type Result: WrappedTypesupport; + type Feedback: WrappedTypesupport; + + fn get_ts() -> &'static rosidl_action_type_support_t; +} + #[derive(Debug)] pub struct WrappedNativeMsg @@ -1638,4 +1646,30 @@ mod tests { println!("resp {:?}", resp2); assert_eq!(resp, resp2); } + + #[cfg(r2r__example_interfaces__action__Fibonacci)] + #[test] + fn test_action_msgs() { + use example_interfaces::action::Fibonacci; + let mut goal = Fibonacci::Goal::default(); + goal.order = 5; + let gn = WrappedNativeMsg::<_>::from(&goal); + let goal2 = Fibonacci::Goal::from_native(&gn); + println!("goal2 {:?}", goal2); + assert_eq!(goal, goal2); + + let mut res = Fibonacci::Result::default(); + res.sequence = vec![1,2,3]; + let rn = WrappedNativeMsg::<_>::from(&res); + let res2 = Fibonacci::Result::from_native(&rn); + println!("res2 {:?}", res2); + assert_eq!(res, res2); + + let mut fb = Fibonacci::Feedback::default(); + fb.sequence = vec![4,3,6]; + let fbn = WrappedNativeMsg::<_>::from(&fb); + let fb2 = Fibonacci::Feedback::from_native(&fbn); + println!("feedback2 {:?}", fb2); + assert_eq!(fb, fb2); + } }