From 5d30028e37405fcb113c308a334b5aa014298f48 Mon Sep 17 00:00:00 2001 From: Martin Dahl Date: Tue, 22 Oct 2019 21:13:30 +0200 Subject: [PATCH] Conditional compilation and array improvements --- build.rs | 2 + common/src/lib.rs | 2 +- msg_gen/src/lib.rs | 106 +++++++++++++++++++++++++++++++-------------- rcl/src/lib.rs | 2 - src/lib.rs | 42 ++++++++++++++++-- 5 files changed, 115 insertions(+), 39 deletions(-) diff --git a/build.rs b/build.rs index fe9008b..cf06740 100644 --- a/build.rs +++ b/build.rs @@ -34,6 +34,8 @@ fn main() { for msg in msgs { codegen.push_str(&generate_rust_msg(module, prefix, msg)); + + println!("cargo:rustc-cfg=r2r__{}__{}__{}", module, prefix, msg); } codegen.push_str(" }\n"); diff --git a/common/src/lib.rs b/common/src/lib.rs index ee4c16a..05ead07 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use std::env; use std::fs::{self, File}; -use std::io::{self, Read}; +use std::io::Read; use std::path::PathBuf; #[derive(Debug)] diff --git a/msg_gen/src/lib.rs b/msg_gen/src/lib.rs index f78edf7..c47a3d4 100644 --- a/msg_gen/src/lib.rs +++ b/msg_gen/src/lib.rs @@ -3,8 +3,6 @@ #![allow(non_snake_case)] #![allow(improper_ctypes)] #![allow(dead_code)] -#![allow(clippy::cast_ptr_alignment)] -#![allow(clippy::if_same_then_else)] include!(concat!(env!("OUT_DIR"), "/msg_bindings.rs")); include!(concat!(env!("OUT_DIR"), "/introspection_functions.rs")); @@ -159,7 +157,38 @@ pub fn generate_rust_msg(module_: &str, prefix_: &str, name_: &str) -> String { let field_name = field_name(CStr::from_ptr(member.name_).to_str().unwrap()); let rust_field_type = field_type(member.type_id_); - if member.is_array_ { + if member.is_array_ && member.array_size_ > 0 && !member.is_upper_bound_ { + // these are plain arrays + let ss = format!("// is_upper_bound_: {}\n", member.is_upper_bound_); + from_native.push_str(&ss); + let ss = format!("// member.array_size_ : {}\n", member.array_size_); + from_native.push_str(&ss); + if rust_field_type == "message" { + let (module, prefix, name, _, _) = introspection(member.members_); + from_native.push_str(&format!("{field_name} : {{\n", field_name = field_name)); + from_native.push_str(&format!( + "let mut temp = Vec::with_capacity(msg.{field_name}.len());\n", + field_name = field_name + )); + from_native.push_str(&format!("for s in &msg.{field_name} {{ temp.push({module}::{prefix}::{msgname}::from_native(s)); }}\n", field_name = field_name, module = module, prefix=prefix, msgname = name)); + from_native.push_str("temp },\n"); + } else if rust_field_type == "std::string::String" { + from_native.push_str(&format!( + "{field_name}: msg.{field_name}.iter().map(|s|s.to_str().to_owned()).collect(),\n", + field_name = field_name + )); + } else { + from_native.push_str(&format!( + "{field_name}: msg.{field_name}.to_vec(),\n", + field_name = field_name + )); + } + } else if member.is_array_ && (member.array_size_ == 0 || member.is_upper_bound_) { + // these are __Sequence:s + let ss = format!("// is_upper_bound_: {}\n", member.is_upper_bound_); + from_native.push_str(&ss); + let ss = format!("// member.array_size_ : {}\n", member.array_size_); + from_native.push_str(&ss); if rust_field_type == "message" { let (module, prefix, name, _, _) = introspection(member.members_); from_native.push_str(&format!("{field_name} : {{\n", field_name = field_name)); @@ -171,19 +200,10 @@ pub fn generate_rust_msg(module_: &str, prefix_: &str, name_: &str) -> String { from_native.push_str(&format!("for s in slice {{ temp.push({module}::{prefix}::{msgname}::from_native(s)); }}\n", module = module, prefix=prefix, msgname = name)); from_native.push_str("temp },\n"); } else { - if member.array_size_ > 0 { - // fixed size array, copy elements (happens to be the same now that we are using vectors...) - from_native.push_str(&format!( - "{field_name}: msg.{field_name}.to_vec(),\n", - field_name = field_name - )); - } else { - let x = 1; - from_native.push_str(&format!( - "{field_name}: msg.{field_name}.to_vec(),\n", - field_name = field_name - )); - } + from_native.push_str(&format!( + "{field_name}: msg.{field_name}.to_vec(),\n", + field_name = field_name + )); } } else if rust_field_type == "std::string::String" { from_native.push_str(&format!( @@ -209,7 +229,21 @@ pub fn generate_rust_msg(module_: &str, prefix_: &str, name_: &str) -> String { let field_name = field_name(CStr::from_ptr((*member).name_).to_str().unwrap()); let rust_field_type = field_type(member.type_id_); - if member.is_array_ { + if member.is_array_ && member.array_size_ > 0 && !member.is_upper_bound_ { + // these are plain arrays + // fixed size array, just copy but first check the size! + copy_to_native.push_str(&format!("assert_eq!(self.{field_name}.len(), {array_size}, \"Field {{}} is fixed size of {{}}!\", \"{field_name}\", {array_size});\n", field_name = field_name, array_size = member.array_size_)); + if rust_field_type == "message" { + copy_to_native.push_str(&format!("for (t,s) in msg.{field_name}.iter_mut().zip(&self.{field_name}) {{ s.copy_to_native(t);}}\n", field_name=field_name)); + } + else if rust_field_type == "std::string::String" { + copy_to_native.push_str(&format!("for (t,s) in msg.{field_name}.iter_mut().zip(&self.{field_name}) {{ t.assign(&s);}}\n", field_name=field_name)); + } else { + copy_to_native.push_str(&format!("msg.{field_name}.copy_from_slice(&self.{field_name}[..{array_size}]);\n", field_name = field_name, array_size = member.array_size_)); + } + } + else if member.is_array_ && (member.array_size_ == 0 || member.is_upper_bound_) { + // these are __Sequence:s if rust_field_type == "message" { let (_, _, _, c_struct, _) = introspection(member.members_); copy_to_native.push_str(&format!( @@ -221,20 +255,14 @@ pub fn generate_rust_msg(module_: &str, prefix_: &str, name_: &str) -> String { copy_to_native.push_str(&format!("let slice = unsafe {{ std::slice::from_raw_parts_mut(msg.{field_name}.data, msg.{field_name}.size)}};\n",field_name = field_name)); copy_to_native.push_str(&format!("for (t,s) in slice.iter_mut().zip(&self.{field_name}) {{ s.copy_to_native(t);}}\n", field_name=field_name)); } else { - if member.array_size_ > 0 && !member.is_upper_bound_ { - // fixed size array, just copy but first check the size! - copy_to_native.push_str(&format!("assert_eq!(self.{field_name}.len(), {array_size}, \"Field {{}} is fixed size of {{}}!\", \"{field_name}\", {array_size});\n", field_name = field_name, array_size = member.array_size_)); - copy_to_native.push_str(&format!("msg.{field_name}.copy_from_slice(&self.{field_name}[..{array_size}]);\n", field_name = field_name, array_size = member.array_size_)); - } else { - if member.is_upper_bound_ { - // extra assertion - copy_to_native.push_str(&format!("assert!(self.{field_name}.len() <= {array_size}, \"Field {{}} is upper bounded by {{}}!\", \"{field_name}\", {array_size});\n", field_name = field_name, array_size = member.array_size_)); - } - copy_to_native.push_str(&format!( - "msg.{field_name}.update(&self.{field_name});\n", - field_name = field_name - )); + // extra assertion + if member.is_upper_bound_ { + copy_to_native.push_str(&format!("assert!(self.{field_name}.len() <= {array_size}, \"Field {{}} is upper bounded by {{}}!\", \"{field_name}\", {array_size});\n", field_name = field_name, array_size = member.array_size_)); } + copy_to_native.push_str(&format!( + "msg.{field_name}.update(&self.{field_name});\n", + field_name = field_name + )); } } else if rust_field_type == "std::string::String" { copy_to_native.push_str(&format!( @@ -276,17 +304,29 @@ pub fn generate_rust_msg(module_: &str, prefix_: &str, name_: &str) -> String { copy_to_native = copy_to_native ); + let impl_default = format!( + " + impl Default for {msgname} {{ + fn default() -> Self {{ + let msg_native = WrappedNativeMsg::<{msgname}>::new(); + {msgname}::from_native(&msg_native) + }} + }} + ", msgname = name); + let module_str = format!( " - #[derive(Clone,Debug,Default,PartialEq,Serialize,Deserialize)] + #[derive(Clone,Debug,PartialEq,Serialize,Deserialize)] pub struct {msgname} {{\n {fields} }}\n - {typesupport}\n\n + {typesupport}\n + {default}\n\n ", msgname = name, fields = fields, - typesupport = typesupport + typesupport = typesupport, + default = impl_default ); module_str diff --git a/rcl/src/lib.rs b/rcl/src/lib.rs index 1fca534..d6063ba 100644 --- a/rcl/src/lib.rs +++ b/rcl/src/lib.rs @@ -151,5 +151,3 @@ primitive_sequence!(rosidl_generator_c__uint32, u32); primitive_sequence!(rosidl_generator_c__int32, i32); primitive_sequence!(rosidl_generator_c__uint64, u64); primitive_sequence!(rosidl_generator_c__int64, i64); - - diff --git a/src/lib.rs b/src/lib.rs index 80d22a9..cf4c75f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -860,8 +860,7 @@ mod tests { #[test] fn test_untyped_json() -> () { - use trajectory_msgs::msg::*; - let mut msg: JointTrajectoryPoint = Default::default(); + let mut msg = trajectory_msgs::msg::JointTrajectoryPoint::default(); msg.positions.push(39.0); msg.positions.push(34.0); let json = serde_json::to_value(msg.clone()).unwrap(); @@ -871,8 +870,45 @@ mod tests { let json2 = native.to_json().unwrap(); assert_eq!(json, json2); - let msg2: JointTrajectoryPoint = serde_json::from_value(json2).unwrap(); + let msg2: trajectory_msgs::msg::JointTrajectoryPoint = serde_json::from_value(json2).unwrap(); assert_eq!(msg, msg2); } + #[cfg(r2r__test_msgs__msg__Arrays)] + #[test] + fn test_test_msgs_array() -> () { + let mut msg = test_msgs::msg::Arrays::default(); + println!("msg: {:?}", msg.string_values); + msg.string_values = vec![ + "hej".to_string(), "hopp".to_string(), "stropp".to_string() + ]; + + let msg_native = WrappedNativeMsg::::from(&msg); + let msg2 = test_msgs::msg::Arrays::from_native(&msg_native); + + assert_eq!(msg, msg2); + } + + #[cfg(r2r__test_msgs__msg__Arrays)] + #[test] + #[should_panic] + fn test_test_msgs_array_too_few_elems() -> () { + let mut msg = test_msgs::msg::Arrays::default(); + println!("msg: {:?}", msg.string_values); + msg.string_values = vec![ "hej".to_string(), "hopp".to_string() ]; + let _msg_native = WrappedNativeMsg::::from(&msg); + } + + #[cfg(r2r__test_msgs__msg__WStrings)] + #[test] + fn test_test_msgs_wstring() -> () { + let mut msg = test_msgs::msg::WStrings::default(); + let rust_str = "ハローワールド"; + msg.wstring_value = rust_str.to_string(); + let native = WrappedNativeMsg::::from(&msg); + println!("msg: {:?}", msg); + let msg2 = test_msgs::msg::WStrings::from_native(&native); + assert_eq!(msg.wstring_value, msg2.wstring_value); + } + }