Conditional compilation and array improvements

This commit is contained in:
Martin Dahl 2019-10-22 21:13:30 +02:00
parent 37991a2363
commit 5d30028e37
5 changed files with 115 additions and 39 deletions

View File

@ -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");

View File

@ -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)]

View File

@ -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

View File

@ -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);

View File

@ -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::<test_msgs::msg::Arrays>::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::<test_msgs::msg::Arrays>::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::<test_msgs::msg::WStrings>::from(&msg);
println!("msg: {:?}", msg);
let msg2 = test_msgs::msg::WStrings::from_native(&native);
assert_eq!(msg.wstring_value, msg2.wstring_value);
}
}