Cleanup untyped part 2
This commit is contained in:
parent
3d2ca44626
commit
b79146c0aa
8
build.rs
8
build.rs
|
|
@ -39,14 +39,14 @@ fn main() {
|
||||||
codegen.push_str("}\n");
|
codegen.push_str("}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
let codegen_typehacks = generate_untyped_helpers(&msgs_list);
|
let untyped_helper = generate_untyped_helper(&msgs_list);
|
||||||
|
|
||||||
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
|
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||||
let msgs_fn = out_path.join("generated_msgs.rs");
|
let msgs_fn = out_path.join("generated_msgs.rs");
|
||||||
let hacks_fn = out_path.join("generated_typehacks.rs");
|
let untyped_fn = out_path.join("generated_untyped_helper.rs");
|
||||||
|
|
||||||
let mut f = File::create(msgs_fn).unwrap();
|
let mut f = File::create(msgs_fn).unwrap();
|
||||||
write!(f, "{}", codegen).unwrap();
|
write!(f, "{}", codegen).unwrap();
|
||||||
let mut f = File::create(hacks_fn).unwrap();
|
let mut f = File::create(untyped_fn).unwrap();
|
||||||
write!(f, "{}", codegen_typehacks).unwrap();
|
write!(f, "{}", untyped_helper).unwrap();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
use r2r::*;
|
use r2r;
|
||||||
use builtin_interfaces::msg::Duration;
|
use r2r::builtin_interfaces::msg::Duration;
|
||||||
use trajectory_msgs::msg::*;
|
use r2r::trajectory_msgs::msg::*;
|
||||||
use std_msgs::msg::Int32;
|
use r2r::std_msgs::msg::Int32;
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
|
|
||||||
fn main() -> Result<(), Error> {
|
fn main() -> Result<(), Error> {
|
||||||
let ctx = Context::create()?;
|
let ctx = r2r::Context::create()?;
|
||||||
let mut node = Node::create(ctx, "testnode", "")?;
|
let mut node = r2r::Node::create(ctx, "testnode", "")?;
|
||||||
let publisher = node.create_publisher::<JointTrajectoryPoint>("/hej")?;
|
let publisher = node.create_publisher::<JointTrajectoryPoint>("/hej")?;
|
||||||
let publisher2 = node.create_publisher::<Int32>("/native_count")?;
|
let publisher2 = node.create_publisher::<Int32>("/native_count")?;
|
||||||
|
|
||||||
let mut c = 0;
|
let mut c = 0;
|
||||||
let mut positions: Vec<f64> = Vec::new();
|
let mut positions: Vec<f64> = Vec::new();
|
||||||
let cb = move |x:std_msgs::msg::String| {
|
let cb = move |x:r2r::std_msgs::msg::String| {
|
||||||
println!("at count {} got: {}", c, x.data);
|
println!("at count {} got: {}", c, x.data);
|
||||||
c = c + 1;
|
c = c + 1;
|
||||||
positions.push(c as f64);
|
positions.push(c as f64);
|
||||||
|
|
@ -21,7 +21,7 @@ fn main() -> Result<(), Error> {
|
||||||
time_from_start : Duration { sec: c, nanosec: 0 },
|
time_from_start : Duration { sec: c, nanosec: 0 },
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let mut native = WrappedNativeMsg::<Int32>::new();
|
let mut native = r2r::WrappedNativeMsg::<Int32>::new();
|
||||||
native.data = c;
|
native.data = c;
|
||||||
|
|
||||||
publisher.publish(&to_send).unwrap();
|
publisher.publish(&to_send).unwrap();
|
||||||
|
|
@ -33,7 +33,7 @@ fn main() -> Result<(), Error> {
|
||||||
println!("JTP serialized as: {}", serialized);
|
println!("JTP serialized as: {}", serialized);
|
||||||
};
|
};
|
||||||
|
|
||||||
let cb3 = move |raw_c:&WrappedNativeMsg<JointTrajectoryPoint>| {
|
let cb3 = move |raw_c:&r2r::WrappedNativeMsg<JointTrajectoryPoint>| {
|
||||||
println!("Raw c data: {:?}", raw_c.positions);
|
println!("Raw c data: {:?}", raw_c.positions);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
use r2r::*;
|
use r2r;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
|
|
||||||
fn main() -> Result<(), Error> {
|
fn main() -> Result<(), Error> {
|
||||||
let ctx = Context::create()?;
|
let ctx = r2r::Context::create()?;
|
||||||
let mut node = Node::create(ctx, "echo", "")?;
|
let mut node = r2r::Node::create(ctx, "echo", "")?;
|
||||||
|
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
let topic = args.get(1).expect("provide a topic!");
|
let topic = args.get(1).expect("provide a topic!");
|
||||||
|
|
@ -36,10 +36,17 @@ fn main() -> Result<(), Error> {
|
||||||
let echo = &format!("{}_echo", topic);
|
let echo = &format!("{}_echo", topic);
|
||||||
let echo_pub = node.create_publisher_untyped(echo, type_name)?;
|
let echo_pub = node.create_publisher_untyped(echo, type_name)?;
|
||||||
|
|
||||||
let cb = move |msg: serde_json::Value | {
|
let cb = move |msg: r2r::Result<serde_json::Value> | {
|
||||||
|
match msg {
|
||||||
|
Ok(msg) => {
|
||||||
let s = serde_json::to_string_pretty(&msg).unwrap();
|
let s = serde_json::to_string_pretty(&msg).unwrap();
|
||||||
println!("{}\n---\n", &s);
|
println!("{}\n---\n", &s);
|
||||||
echo_pub.publish(msg).unwrap();
|
echo_pub.publish(msg).unwrap();
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
println!("Could not parse msg. {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let _subref = node.subscribe_untyped(topic, type_name, Box::new(cb))?;
|
let _subref = node.subscribe_untyped(topic, type_name, Box::new(cb))?;
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,24 @@
|
||||||
use r2r::*;
|
use r2r;
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
|
|
||||||
fn main() -> Result<(), Error> {
|
fn main() -> Result<(), Error> {
|
||||||
let ctx = Context::create()?;
|
let ctx = r2r::Context::create()?;
|
||||||
|
|
||||||
let th = {
|
let th = {
|
||||||
let mut node = Node::create(ctx, "testnode", "")?;
|
let mut node = r2r::Node::create(ctx, "testnode", "")?;
|
||||||
|
|
||||||
let (tx, rx) = mpsc::channel::<String>();
|
let (tx, rx) = mpsc::channel::<String>();
|
||||||
|
|
||||||
let p = node
|
let p = node
|
||||||
.create_publisher::<std_msgs::msg::String>("/hej")
|
.create_publisher::<r2r::std_msgs::msg::String>("/hej")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let th = thread::spawn(move || loop {
|
let th = thread::spawn(move || loop {
|
||||||
println!("thread looping");
|
println!("thread looping");
|
||||||
let des = if let Ok(msg) = rx.recv() {
|
let des = if let Ok(msg) = rx.recv() {
|
||||||
let deserialized: std_msgs::msg::String = serde_json::from_str(&msg).unwrap();
|
let deserialized: r2r::std_msgs::msg::String = serde_json::from_str(&msg).unwrap();
|
||||||
println!(
|
println!(
|
||||||
"received: {}, deserialized ros msg = {:#?}",
|
"received: {}, deserialized ros msg = {:#?}",
|
||||||
msg, deserialized
|
msg, deserialized
|
||||||
|
|
@ -34,12 +34,12 @@ fn main() -> Result<(), Error> {
|
||||||
});
|
});
|
||||||
|
|
||||||
let tx1 = tx.clone();
|
let tx1 = tx.clone();
|
||||||
let cb = move |x: std_msgs::msg::String| {
|
let cb = move |x: r2r::std_msgs::msg::String| {
|
||||||
let serialized = serde_json::to_string(&x).unwrap();
|
let serialized = serde_json::to_string(&x).unwrap();
|
||||||
tx1.send(serialized).unwrap(); // pass msg on to other thread for printing
|
tx1.send(serialized).unwrap(); // pass msg on to other thread for printing
|
||||||
};
|
};
|
||||||
|
|
||||||
let cb2 = move |x: &WrappedNativeMsg<std_msgs::msg::String>| {
|
let cb2 = move |x: &r2r::WrappedNativeMsg<r2r::std_msgs::msg::String>| {
|
||||||
// use native data!
|
// use native data!
|
||||||
let s = x.data.to_str();
|
let s = x.data.to_str();
|
||||||
println!("native ros msg: {}", s);
|
println!("native ros msg: {}", s);
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,12 @@ use std::sync::mpsc;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
|
|
||||||
use r2r::*;
|
use r2r;
|
||||||
|
use r2r::std_msgs;
|
||||||
|
|
||||||
fn main() -> Result<(), Error> {
|
fn main() -> Result<(), Error> {
|
||||||
let ctx = Context::create()?;
|
let ctx = r2r::Context::create()?;
|
||||||
let mut node = Node::create(ctx, "testnode", "")?;
|
let mut node = r2r::Node::create(ctx, "testnode", "")?;
|
||||||
|
|
||||||
let publisher = node.create_publisher::<std_msgs::msg::String>("/hej")?;
|
let publisher = node.create_publisher::<std_msgs::msg::String>("/hej")?;
|
||||||
let pubint = node.create_publisher::<std_msgs::msg::Int32>("/count")?;
|
let pubint = node.create_publisher::<std_msgs::msg::Int32>("/count")?;
|
||||||
|
|
|
||||||
|
|
@ -9,55 +9,103 @@ include!(concat!(env!("OUT_DIR"), "/introspection_functions.rs"));
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use rcl::*;
|
use rcl::*;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
|
|
||||||
fn field_type(t: u8) -> String {
|
fn field_type(t: u8) -> String {
|
||||||
// lovely...
|
// lovely...
|
||||||
// move to common
|
// move to common
|
||||||
if t == (rosidl_typesupport_introspection_c__ROS_TYPE_STRING as u8) { "std::string::String".to_owned() }
|
if t == (rosidl_typesupport_introspection_c__ROS_TYPE_STRING as u8) {
|
||||||
else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_BOOLEAN as u8) { "bool".to_owned() }
|
"std::string::String".to_owned()
|
||||||
else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_CHAR as u8) { "i8".to_owned() }
|
} else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_BOOLEAN as u8) {
|
||||||
else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_WCHAR as u8) { "u16".to_owned() }
|
"bool".to_owned()
|
||||||
else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_OCTET as u8) { "u8".to_owned() }
|
} else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_CHAR as u8) {
|
||||||
else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_UINT8 as u8) { "u8".to_owned() }
|
"i8".to_owned()
|
||||||
else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_INT8 as u8) { "i8".to_owned() }
|
} else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_WCHAR as u8) {
|
||||||
else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_UINT16 as u8) { "u16".to_owned() }
|
"u16".to_owned()
|
||||||
else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_INT16 as u8) { "i16".to_owned() }
|
} else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_OCTET as u8) {
|
||||||
else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_UINT32 as u8) { "u32".to_owned() }
|
"u8".to_owned()
|
||||||
else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_INT32 as u8) { "i32".to_owned() }
|
} else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_UINT8 as u8) {
|
||||||
else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_UINT64 as u8) { "u64".to_owned() }
|
"u8".to_owned()
|
||||||
else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_INT64 as u8) { "i64".to_owned() }
|
} else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_INT8 as u8) {
|
||||||
else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_FLOAT as u8) { "f32".to_owned() }
|
"i8".to_owned()
|
||||||
else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_DOUBLE as u8) { "f64".to_owned() }
|
} else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_UINT16 as u8) {
|
||||||
else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_LONG_DOUBLE as u8) { "u128".to_owned() } // f128 does not exist in rust
|
"u16".to_owned()
|
||||||
else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_MESSAGE as u8) { "message".to_owned() }
|
} else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_INT16 as u8) {
|
||||||
|
"i16".to_owned()
|
||||||
else { panic!("ros native type not implemented: {}", t); }
|
} else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_UINT32 as u8) {
|
||||||
|
"u32".to_owned()
|
||||||
|
} else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_INT32 as u8) {
|
||||||
|
"i32".to_owned()
|
||||||
|
} else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_UINT64 as u8) {
|
||||||
|
"u64".to_owned()
|
||||||
|
} else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_INT64 as u8) {
|
||||||
|
"i64".to_owned()
|
||||||
|
} else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_FLOAT as u8) {
|
||||||
|
"f32".to_owned()
|
||||||
|
} else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_DOUBLE as u8) {
|
||||||
|
"f64".to_owned()
|
||||||
|
} else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_LONG_DOUBLE as u8) {
|
||||||
|
"u128".to_owned()
|
||||||
|
}
|
||||||
|
// f128 does not exist in rust
|
||||||
|
else if t == (rosidl_typesupport_introspection_c__ROS_TYPE_MESSAGE as u8) {
|
||||||
|
"message".to_owned()
|
||||||
|
} else {
|
||||||
|
panic!("ros native type not implemented: {}", t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn introspection<'a>(ptr: *const rosidl_message_type_support_t) -> (String, String, String, String, &'a [rosidl_typesupport_introspection_c__MessageMember]) {
|
unsafe fn introspection<'a>(
|
||||||
|
ptr: *const rosidl_message_type_support_t,
|
||||||
|
) -> (
|
||||||
|
String,
|
||||||
|
String,
|
||||||
|
String,
|
||||||
|
String,
|
||||||
|
&'a [rosidl_typesupport_introspection_c__MessageMember],
|
||||||
|
) {
|
||||||
let members = (*ptr).data as *const rosidl_typesupport_introspection_c__MessageMembers;
|
let members = (*ptr).data as *const rosidl_typesupport_introspection_c__MessageMembers;
|
||||||
let namespace = CStr::from_ptr((*members).message_namespace_).to_str().unwrap();
|
let namespace = CStr::from_ptr((*members).message_namespace_)
|
||||||
|
.to_str()
|
||||||
|
.unwrap();
|
||||||
let name = CStr::from_ptr((*members).message_name_).to_str().unwrap();
|
let name = CStr::from_ptr((*members).message_name_).to_str().unwrap();
|
||||||
let nn: Vec<&str> = namespace.split("__").into_iter().take(2).collect();
|
let nn: Vec<&str> = namespace.split("__").into_iter().take(2).collect();
|
||||||
let (module, prefix) = (nn[0], nn[1]);
|
let (module, prefix) = (nn[0], nn[1]);
|
||||||
let c_struct = format!("{module}__{prefix}__{msgname}", module = module, prefix=prefix, msgname = name);
|
let c_struct = format!(
|
||||||
let memberslice = std::slice::from_raw_parts((*members).members_, (*members).member_count_ as usize);
|
"{module}__{prefix}__{msgname}",
|
||||||
(module.to_owned(), prefix.to_owned(), name.to_owned(), c_struct, memberslice)
|
module = module,
|
||||||
|
prefix = prefix,
|
||||||
|
msgname = name
|
||||||
|
);
|
||||||
|
let memberslice =
|
||||||
|
std::slice::from_raw_parts((*members).members_, (*members).member_count_ as usize);
|
||||||
|
(
|
||||||
|
module.to_owned(),
|
||||||
|
prefix.to_owned(),
|
||||||
|
name.to_owned(),
|
||||||
|
c_struct,
|
||||||
|
memberslice,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn field_name(field_name: &str) -> String {
|
fn field_name(field_name: &str) -> String {
|
||||||
// check for reserved words
|
// check for reserved words
|
||||||
if field_name == "type" { "type_".into() } else { field_name.to_owned() }
|
if field_name == "type" {
|
||||||
|
"type_".into()
|
||||||
|
} else {
|
||||||
|
field_name.to_owned()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this is a terrible hack :)
|
// TODO: this is a terrible hack :)
|
||||||
pub fn generate_rust_msg(module_: &str, prefix_: &str, name_: &str) -> String {
|
pub fn generate_rust_msg(module_: &str, prefix_: &str, name_: &str) -> String {
|
||||||
let key = format!("{}__{}__{}", module_, prefix_, name_);
|
let key = format!("{}__{}__{}", module_, prefix_, name_);
|
||||||
let ptr = INTROSPECTION_FNS.get(key.as_str()).expect(&format!("code generation error: {}", name_));
|
let ptr = INTROSPECTION_FNS
|
||||||
|
.get(key.as_str())
|
||||||
|
.expect(&format!("code generation error: {}", name_));
|
||||||
let ptr = *ptr as *const i32 as *const rosidl_message_type_support_t;
|
let ptr = *ptr as *const i32 as *const rosidl_message_type_support_t;
|
||||||
unsafe {
|
unsafe {
|
||||||
let (module, prefix, name, c_struct, members) = introspection(ptr);
|
let (module, prefix, name, c_struct, members) = introspection(ptr);
|
||||||
|
|
@ -72,8 +120,15 @@ pub fn generate_rust_msg(module_: &str, prefix_: &str, name_: &str) -> String {
|
||||||
let rust_field_type = field_type(member.type_id_);
|
let rust_field_type = field_type(member.type_id_);
|
||||||
let rust_field_type = if rust_field_type == "message" {
|
let rust_field_type = if rust_field_type == "message" {
|
||||||
let (module, prefix, name, _, _) = introspection(member.members_);
|
let (module, prefix, name, _, _) = introspection(member.members_);
|
||||||
format!("{module}::{prefix}::{msgname}", module = module, prefix=prefix, msgname = name)
|
format!(
|
||||||
} else { rust_field_type };
|
"{module}::{prefix}::{msgname}",
|
||||||
|
module = module,
|
||||||
|
prefix = prefix,
|
||||||
|
msgname = name
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
rust_field_type
|
||||||
|
};
|
||||||
let s = if member.is_array_ {
|
let s = if member.is_array_ {
|
||||||
// if member.array_size_ > 0 {
|
// if member.array_size_ > 0 {
|
||||||
// fixed size array
|
// fixed size array
|
||||||
|
|
@ -90,7 +145,10 @@ pub fn generate_rust_msg(module_: &str, prefix_: &str, name_: &str) -> String {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut from_native = String::new();
|
let mut from_native = String::new();
|
||||||
from_native.push_str(&format!("fn from_native(msg: &Self::CStruct) -> {} {{\n", name));
|
from_native.push_str(&format!(
|
||||||
|
"fn from_native(msg: &Self::CStruct) -> {} {{\n",
|
||||||
|
name
|
||||||
|
));
|
||||||
from_native.push_str(&format!(" {} {{\n", name));
|
from_native.push_str(&format!(" {} {{\n", name));
|
||||||
|
|
||||||
for member in members {
|
for member in members {
|
||||||
|
|
@ -101,25 +159,40 @@ pub fn generate_rust_msg(module_: &str, prefix_: &str, name_: &str) -> String {
|
||||||
if rust_field_type == "message" {
|
if rust_field_type == "message" {
|
||||||
let (module, prefix, name, _, _) = introspection(member.members_);
|
let (module, prefix, name, _, _) = introspection(member.members_);
|
||||||
from_native.push_str(&format!("{field_name} : {{\n", field_name = field_name));
|
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}.size);\n",field_name = field_name));
|
from_native.push_str(&format!(
|
||||||
|
"let mut temp = Vec::with_capacity(msg.{field_name}.size);\n",
|
||||||
|
field_name = field_name
|
||||||
|
));
|
||||||
from_native.push_str(&format!("let slice = unsafe {{ std::slice::from_raw_parts(msg.{field_name}.data, msg.{field_name}.size)}};\n",field_name = field_name));
|
from_native.push_str(&format!("let slice = unsafe {{ std::slice::from_raw_parts(msg.{field_name}.data, msg.{field_name}.size)}};\n",field_name = field_name));
|
||||||
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(&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");
|
from_native.push_str("temp },\n");
|
||||||
} else {
|
} else {
|
||||||
if member.array_size_ > 0 {
|
if member.array_size_ > 0 {
|
||||||
// fixed size array, copy elements (happens to be the same now that we are using vectors...)
|
// 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));
|
from_native.push_str(&format!(
|
||||||
|
"{field_name}: msg.{field_name}.to_vec(),\n",
|
||||||
|
field_name = field_name
|
||||||
|
));
|
||||||
} else {
|
} else {
|
||||||
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" {
|
} else if rust_field_type == "std::string::String" {
|
||||||
from_native.push_str(&format!("{field_name}: msg.{field_name}.to_str().to_owned(),\n", field_name = field_name));
|
from_native.push_str(&format!(
|
||||||
|
"{field_name}: msg.{field_name}.to_str().to_owned(),\n",
|
||||||
|
field_name = field_name
|
||||||
|
));
|
||||||
} else if rust_field_type == "message" {
|
} else if rust_field_type == "message" {
|
||||||
let (module, prefix, name, _, _) = introspection(member.members_);
|
let (module, prefix, name, _, _) = introspection(member.members_);
|
||||||
from_native.push_str(&format!("{field_name}: {module}::{prefix}::{msgname}::from_native(&msg.{field_name}),\n", field_name = field_name, module = module, prefix=prefix, msgname = name));
|
from_native.push_str(&format!("{field_name}: {module}::{prefix}::{msgname}::from_native(&msg.{field_name}),\n", field_name = field_name, module = module, prefix=prefix, msgname = name));
|
||||||
} else {
|
} else {
|
||||||
from_native.push_str(&format!("{field_name}: msg.{field_name},\n", field_name = field_name));
|
from_native.push_str(&format!(
|
||||||
|
"{field_name}: msg.{field_name},\n",
|
||||||
|
field_name = field_name
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
from_native.push_str(" }\n }\n");
|
from_native.push_str(" }\n }\n");
|
||||||
|
|
@ -134,7 +207,11 @@ pub fn generate_rust_msg(module_: &str, prefix_: &str, name_: &str) -> String {
|
||||||
if member.is_array_ {
|
if member.is_array_ {
|
||||||
if rust_field_type == "message" {
|
if rust_field_type == "message" {
|
||||||
let (_, _, _, c_struct, _) = introspection(member.members_);
|
let (_, _, _, c_struct, _) = introspection(member.members_);
|
||||||
copy_to_native.push_str(&format!("unsafe {{ {c_struct}__Sequence__fini(&mut msg.{field_name}) }};\n", c_struct = c_struct, field_name = field_name));
|
copy_to_native.push_str(&format!(
|
||||||
|
"unsafe {{ {c_struct}__Sequence__fini(&mut msg.{field_name}) }};\n",
|
||||||
|
c_struct = c_struct,
|
||||||
|
field_name = field_name
|
||||||
|
));
|
||||||
copy_to_native.push_str(&format!("unsafe {{ {c_struct}__Sequence__init(&mut msg.{field_name}, self.{field_name}.len()) }};\n", c_struct = c_struct, field_name = field_name));
|
copy_to_native.push_str(&format!("unsafe {{ {c_struct}__Sequence__init(&mut msg.{field_name}, self.{field_name}.len()) }};\n", c_struct = c_struct, field_name = field_name));
|
||||||
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!("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));
|
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));
|
||||||
|
|
@ -148,20 +225,33 @@ pub fn generate_rust_msg(module_: &str, prefix_: &str, name_: &str) -> String {
|
||||||
// extra assertion
|
// 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!("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));
|
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" {
|
} else if rust_field_type == "std::string::String" {
|
||||||
copy_to_native.push_str(&format!("msg.{field_name}.assign(&self.{field_name});\n", field_name = field_name));
|
copy_to_native.push_str(&format!(
|
||||||
|
"msg.{field_name}.assign(&self.{field_name});\n",
|
||||||
|
field_name = field_name
|
||||||
|
));
|
||||||
} else if rust_field_type == "message" {
|
} else if rust_field_type == "message" {
|
||||||
copy_to_native.push_str(&format!("self.{field_name}.copy_to_native(&mut msg.{field_name});\n", field_name = field_name));
|
copy_to_native.push_str(&format!(
|
||||||
|
"self.{field_name}.copy_to_native(&mut msg.{field_name});\n",
|
||||||
|
field_name = field_name
|
||||||
|
));
|
||||||
} else {
|
} else {
|
||||||
copy_to_native.push_str(&format!("msg.{field_name} = self.{field_name};\n", field_name = field_name));
|
copy_to_native.push_str(&format!(
|
||||||
|
"msg.{field_name} = self.{field_name};\n",
|
||||||
|
field_name = field_name
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
copy_to_native.push_str("}\n");
|
copy_to_native.push_str("}\n");
|
||||||
|
|
||||||
let typesupport = format!("impl WrappedTypesupport for {msgname} {{ \n
|
let typesupport = format!(
|
||||||
|
"impl WrappedTypesupport for {msgname} {{ \n
|
||||||
type CStruct = {c_struct}; \n\n
|
type CStruct = {c_struct}; \n\n
|
||||||
fn get_ts() -> &'static rosidl_message_type_support_t {{ \n
|
fn get_ts() -> &'static rosidl_message_type_support_t {{ \n
|
||||||
unsafe {{ &*rosidl_typesupport_c__get_message_type_support_handle__{c_struct}() }}
|
unsafe {{ &*rosidl_typesupport_c__get_message_type_support_handle__{c_struct}() }}
|
||||||
|
|
@ -174,124 +264,63 @@ pub fn generate_rust_msg(module_: &str, prefix_: &str, name_: &str) -> String {
|
||||||
}}\n
|
}}\n
|
||||||
{from_native}\n\n
|
{from_native}\n\n
|
||||||
{copy_to_native}\n\n
|
{copy_to_native}\n\n
|
||||||
}}\n", msgname = name, c_struct = &c_struct, from_native=from_native, copy_to_native=copy_to_native);
|
}}\n",
|
||||||
|
msgname = name,
|
||||||
|
c_struct = &c_struct,
|
||||||
|
from_native = from_native,
|
||||||
|
copy_to_native = copy_to_native
|
||||||
|
);
|
||||||
|
|
||||||
let module_str = format!("
|
let module_str = format!(
|
||||||
|
"
|
||||||
#[derive(Clone,Debug,Default,PartialEq,Serialize,Deserialize)]
|
#[derive(Clone,Debug,Default,PartialEq,Serialize,Deserialize)]
|
||||||
pub struct {msgname} {{\n
|
pub struct {msgname} {{\n
|
||||||
{fields}
|
{fields}
|
||||||
}}\n
|
}}\n
|
||||||
{typesupport}\n\n
|
{typesupport}\n\n
|
||||||
", msgname = name, fields = fields, typesupport = typesupport);
|
",
|
||||||
|
msgname = name,
|
||||||
|
fields = fields,
|
||||||
|
typesupport = typesupport
|
||||||
|
);
|
||||||
|
|
||||||
module_str
|
module_str
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn generate_untyped_helper(msgs: &Vec<common::RosMsg>) -> String {
|
||||||
|
let open = String::from(
|
||||||
|
"
|
||||||
|
impl WrappedNativeMsgUntyped {
|
||||||
|
fn new_from(typename: &str) -> Result<Self> {
|
||||||
|
",
|
||||||
|
);
|
||||||
|
let close = String::from(
|
||||||
|
"
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Err(Error::InvalidMessageType{ msgtype: typename.into() })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
",
|
||||||
|
);
|
||||||
|
|
||||||
// this is even worse, it was added as an afterthought when I wanted to implement rostopic echo
|
let mut lines = String::new();
|
||||||
pub fn generate_untyped_helpers(msgs: &Vec<common::RosMsg>) -> String {
|
|
||||||
let mut ts_helper = format!("fn untyped_ts_helper(typename: &str) -> Result<&'static rosidl_message_type_support_t> {{");
|
|
||||||
for msg in msgs {
|
for msg in msgs {
|
||||||
ts_helper.push_str(&generate_untyped_ts_helper(&msg.module, &msg.prefix, &msg.name));
|
let typename = format!("{}/{}/{}", msg.module, msg.prefix, msg.name);
|
||||||
}
|
let rustname = format!("{}::{}::{}", msg.module, msg.prefix, msg.name);
|
||||||
ts_helper.push_str(&format!("return Err(Error::InvalidMessageType{{ msgtype: typename.into() }})\n}}"));
|
|
||||||
|
|
||||||
let mut ds_helper = format!("fn untyped_deserialize_helper(typename: &str) -> Result<fn(native: *const std::os::raw::c_void) -> serde_json::Value> {{");
|
lines.push_str(&format!(
|
||||||
for msg in msgs {
|
"
|
||||||
ds_helper.push_str(&generate_untyped_deserialize_helper(&msg.module, &msg.prefix, &msg.name));
|
|
||||||
}
|
|
||||||
ds_helper.push_str(&format!("return Err(Error::InvalidMessageType{{ msgtype: typename.into() }})\n}}"));
|
|
||||||
|
|
||||||
let mut se_helper = format!("
|
|
||||||
fn untyped_serialize_helper(typename: &str) -> Result<fn(json: serde_json::Value) -> std::result::Result<*mut std::os::raw::c_void, serde_json::error::Error>> {{");
|
|
||||||
for msg in msgs {
|
|
||||||
se_helper.push_str(&generate_untyped_serialize_helper(&msg.module, &msg.prefix, &msg.name));
|
|
||||||
}
|
|
||||||
se_helper.push_str(&format!("return Err(Error::InvalidMessageType{{ msgtype: typename.into() }})\n}}"));
|
|
||||||
|
|
||||||
let mut alloc_helper = format!("fn untyped_alloc_helper(typename: &str) -> Result<*mut std::os::raw::c_void> {{");
|
|
||||||
for msg in msgs {
|
|
||||||
alloc_helper.push_str(&generate_untyped_alloc_helper(&msg.module, &msg.prefix, &msg.name));
|
|
||||||
}
|
|
||||||
alloc_helper.push_str(&format!("return Err(Error::InvalidMessageType{{ msgtype: typename.into() }})\n}}"));
|
|
||||||
|
|
||||||
let mut dealloc_helper = format!("fn untyped_dealloc_helper(typename: &str) -> Result<fn(*mut std::os::raw::c_void)> {{");
|
|
||||||
for msg in msgs {
|
|
||||||
dealloc_helper.push_str(&generate_untyped_dealloc_helper(&msg.module, &msg.prefix, &msg.name));
|
|
||||||
}
|
|
||||||
dealloc_helper.push_str(&format!("return Err(Error::InvalidMessageType{{ msgtype: typename.into() }})\n}}"));
|
|
||||||
|
|
||||||
format!("{} \n\n {} \n\n {} \n\n {} \n\n {} \n\n", ts_helper, ds_helper, se_helper, alloc_helper, dealloc_helper)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub fn generate_untyped_ts_helper(module_: &str, prefix_: &str, name_: &str) -> String {
|
|
||||||
let typename = format!("{}/{}/{}", module_, prefix_, name_);
|
|
||||||
let rustname = format!("{}::{}::{}", module_, prefix_, name_);
|
|
||||||
|
|
||||||
format!("
|
|
||||||
if typename == \"{typename}\" {{
|
if typename == \"{typename}\" {{
|
||||||
return Ok({rustname}::get_ts());
|
return Ok(WrappedNativeMsgUntyped::new::<{rustname}>());
|
||||||
}}
|
}}
|
||||||
", typename = typename, rustname = rustname)
|
",
|
||||||
|
typename = typename,
|
||||||
|
rustname = rustname
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_untyped_deserialize_helper(module_: &str, prefix_: &str, name_: &str) -> String {
|
format!("{}{}{}", open, lines, close)
|
||||||
let typename = format!("{}/{}/{}", module_, prefix_, name_);
|
|
||||||
let rustname = format!("{}::{}::{}", module_, prefix_, name_);
|
|
||||||
|
|
||||||
format!("
|
|
||||||
if typename == \"{typename}\" {{
|
|
||||||
let x = | native: *const std::os::raw::c_void | {{
|
|
||||||
let ptr = native as *const <{rustname} as WrappedTypesupport>::CStruct;
|
|
||||||
let msg = unsafe {{ {rustname}::from_native(&*ptr) }};
|
|
||||||
serde_json::to_value(&msg).unwrap() // should never crash, we serialize from a known struct
|
|
||||||
}};
|
|
||||||
return Ok(x);
|
|
||||||
}}", typename = typename, rustname = rustname)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generate_untyped_serialize_helper(module_: &str, prefix_: &str, name_: &str) -> String {
|
|
||||||
let typename = format!("{}/{}/{}", module_, prefix_, name_);
|
|
||||||
let rustname = format!("{}::{}::{}", module_, prefix_, name_);
|
|
||||||
|
|
||||||
format!("
|
|
||||||
if typename == \"{typename}\" {{
|
|
||||||
let x = | json: serde_json::Value | {{
|
|
||||||
serde_json::from_value(json).map(|msg: {rustname}| {{
|
|
||||||
let native = {rustname}::create_msg();
|
|
||||||
unsafe {{ msg.copy_to_native(&mut *native); }}
|
|
||||||
native as *mut std::os::raw::c_void }})
|
|
||||||
}};
|
|
||||||
return Ok(x);
|
|
||||||
}}", typename = typename, rustname = rustname)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub fn generate_untyped_alloc_helper(module_: &str, prefix_: &str, name_: &str) -> String {
|
|
||||||
let typename = format!("{}/{}/{}", module_, prefix_, name_);
|
|
||||||
let rustname = format!("{}::{}::{}", module_, prefix_, name_);
|
|
||||||
|
|
||||||
format!("
|
|
||||||
if typename == \"{typename}\" {{
|
|
||||||
return Ok({rustname}::create_msg() as *mut std::os::raw::c_void);
|
|
||||||
}}
|
|
||||||
", typename = typename, rustname = rustname)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub fn generate_untyped_dealloc_helper(module_: &str, prefix_: &str, name_: &str) -> String {
|
|
||||||
let typename = format!("{}/{}/{}", module_, prefix_, name_);
|
|
||||||
let rustname = format!("{}::{}::{}", module_, prefix_, name_);
|
|
||||||
|
|
||||||
format!("
|
|
||||||
if typename == \"{typename}\" {{
|
|
||||||
let y = | native: *mut std::os::raw::c_void | {{
|
|
||||||
let native_msg = native as *mut <{rustname} as WrappedTypesupport>::CStruct;
|
|
||||||
{rustname}::destroy_msg(native_msg);
|
|
||||||
}};
|
|
||||||
return Ok(y);
|
|
||||||
}}", typename = typename, rustname = rustname)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
84
src/lib.rs
84
src/lib.rs
|
|
@ -1,5 +1,5 @@
|
||||||
include!(concat!(env!("OUT_DIR"), "/generated_msgs.rs"));
|
include!(concat!(env!("OUT_DIR"), "/generated_msgs.rs"));
|
||||||
include!(concat!(env!("OUT_DIR"), "/generated_typehacks.rs"));
|
include!(concat!(env!("OUT_DIR"), "/generated_untyped_helper.rs"));
|
||||||
|
|
||||||
#[macro_use] extern crate failure_derive;
|
#[macro_use] extern crate failure_derive;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
@ -15,9 +15,9 @@ use rcl::*;
|
||||||
mod error;
|
mod error;
|
||||||
use error::*;
|
use error::*;
|
||||||
|
|
||||||
type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
pub trait WrappedTypesupport {
|
pub trait WrappedTypesupport: Serialize + serde::de::DeserializeOwned {
|
||||||
type CStruct;
|
type CStruct;
|
||||||
|
|
||||||
fn get_ts() -> &'static rosidl_message_type_support_t;
|
fn get_ts() -> &'static rosidl_message_type_support_t;
|
||||||
|
|
@ -47,16 +47,7 @@ pub struct WrappedNativeMsgUntyped {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WrappedNativeMsgUntyped {
|
impl WrappedNativeMsgUntyped {
|
||||||
fn new_from(typename: &str) -> Result<Self> {
|
fn new<T>() -> Self where T: WrappedTypesupport {
|
||||||
if typename == "std_msgs/msg/String" {
|
|
||||||
Ok(WrappedNativeMsgUntyped::new::<std_msgs::msg::String>())
|
|
||||||
} else
|
|
||||||
{ return Err(Error::InvalidMessageType{ msgtype: typename.into() }) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WrappedNativeMsgUntyped {
|
|
||||||
fn new<T>() -> Self where T: WrappedTypesupport + Serialize + serde::de::DeserializeOwned {
|
|
||||||
let destroy = | native: *mut std::os::raw::c_void | {
|
let destroy = | native: *mut std::os::raw::c_void | {
|
||||||
let native_msg = native as *mut T::CStruct;
|
let native_msg = native as *mut T::CStruct;
|
||||||
T::destroy_msg(native_msg);
|
T::destroy_msg(native_msg);
|
||||||
|
|
@ -87,10 +78,18 @@ impl WrappedNativeMsgUntyped {
|
||||||
json.map_err(|serde_err|Error::SerdeError { err: serde_err.to_string() })
|
json.map_err(|serde_err|Error::SerdeError { err: serde_err.to_string() })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_json(&self, json: serde_json::Value) -> Result<()> {
|
fn from_json(&mut self, json: serde_json::Value) -> Result<()> {
|
||||||
(self.msg_from_json)(self.msg, json).
|
(self.msg_from_json)(self.msg, json).
|
||||||
map_err(|serde_err|Error::SerdeError { err: serde_err.to_string() })
|
map_err(|serde_err|Error::SerdeError { err: serde_err.to_string() })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn void_ptr(&self) -> *const std::os::raw::c_void {
|
||||||
|
self.msg as *const _ as *const std::os::raw::c_void
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn void_ptr_mut(&mut self) -> *mut std::os::raw::c_void {
|
||||||
|
self.msg as *mut _ as *mut std::os::raw::c_void
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for WrappedNativeMsgUntyped {
|
impl Drop for WrappedNativeMsgUntyped {
|
||||||
|
|
@ -180,10 +179,8 @@ where
|
||||||
|
|
||||||
struct WrappedSubUntyped {
|
struct WrappedSubUntyped {
|
||||||
rcl_handle: rcl_subscription_t,
|
rcl_handle: rcl_subscription_t,
|
||||||
callback: Box<dyn FnMut(serde_json::Value) -> ()>,
|
rcl_msg: WrappedNativeMsgUntyped,
|
||||||
serialize: Box<dyn FnMut(*const std::os::raw::c_void) -> serde_json::Value>,
|
callback: Box<dyn FnMut(Result<serde_json::Value>) -> ()>,
|
||||||
dealloc: Box<dyn FnMut(*mut std::os::raw::c_void) -> ()>,
|
|
||||||
rcl_msg: *mut std::os::raw::c_void,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Sub for WrappedSub<T>
|
impl<T> Sub for WrappedSub<T>
|
||||||
|
|
@ -243,19 +240,18 @@ impl Sub for WrappedSubUntyped
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rcl_msg(&mut self) -> *mut std::os::raw::c_void {
|
fn rcl_msg(&mut self) -> *mut std::os::raw::c_void {
|
||||||
self.rcl_msg
|
self.rcl_msg.void_ptr_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_cb(&mut self) -> () {
|
fn run_cb(&mut self) -> () {
|
||||||
let string = (self.serialize)(self.rcl_msg);
|
let json = self.rcl_msg.to_json();
|
||||||
(self.callback)(string);
|
(self.callback)(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn destroy(&mut self, node: &mut rcl_node_t) {
|
fn destroy(&mut self, node: &mut rcl_node_t) {
|
||||||
unsafe {
|
unsafe {
|
||||||
rcl_subscription_fini(&mut self.rcl_handle, node);
|
rcl_subscription_fini(&mut self.rcl_handle, node);
|
||||||
}
|
}
|
||||||
(self.dealloc)(self.rcl_msg); // manually delete message
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -454,19 +450,15 @@ impl Node {
|
||||||
&mut self,
|
&mut self,
|
||||||
topic: &str,
|
topic: &str,
|
||||||
topic_type: &str,
|
topic_type: &str,
|
||||||
callback: Box<dyn FnMut(serde_json::Value) -> ()>,
|
callback: Box<dyn FnMut(Result<serde_json::Value>) -> ()>,
|
||||||
) -> Result<&rcl_subscription_t> {
|
) -> Result<&rcl_subscription_t> {
|
||||||
let ts = untyped_ts_helper(topic_type)?;
|
let msg = WrappedNativeMsgUntyped::new_from(topic_type)?;
|
||||||
let de = untyped_deserialize_helper(topic_type)?;
|
let subscription_handle = self.create_subscription_helper(topic, msg.ts)?;
|
||||||
let subscription_handle = self.create_subscription_helper(topic, ts)?;
|
|
||||||
let dealloc = untyped_dealloc_helper(topic_type)?;
|
|
||||||
|
|
||||||
let ws = WrappedSubUntyped {
|
let ws = WrappedSubUntyped {
|
||||||
rcl_handle: subscription_handle,
|
rcl_handle: subscription_handle,
|
||||||
rcl_msg: untyped_alloc_helper(topic_type)?,
|
rcl_msg: msg,
|
||||||
callback: callback,
|
callback: callback,
|
||||||
serialize: Box::new(de),
|
|
||||||
dealloc: Box::new(dealloc),
|
|
||||||
};
|
};
|
||||||
self.subs.push(Box::new(ws));
|
self.subs.push(Box::new(ws));
|
||||||
Ok(self.subs.last().unwrap().handle()) // hmm...
|
Ok(self.subs.last().unwrap().handle()) // hmm...
|
||||||
|
|
@ -505,7 +497,7 @@ impl Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_publisher_untyped(&mut self, topic: &str, topic_type: &str) -> Result<PublisherUntyped> {
|
pub fn create_publisher_untyped(&mut self, topic: &str, topic_type: &str) -> Result<PublisherUntyped> {
|
||||||
let ts = untyped_ts_helper(topic_type)?;
|
let dummy = WrappedNativeMsgUntyped::new_from(topic_type)?; // TODO, get ts without allocating msg
|
||||||
let mut publisher_handle = unsafe { rcl_get_zero_initialized_publisher() };
|
let mut publisher_handle = unsafe { rcl_get_zero_initialized_publisher() };
|
||||||
let topic_c_string = CString::new(topic).map_err(|_|Error::RCL_RET_INVALID_ARGUMENT)?;
|
let topic_c_string = CString::new(topic).map_err(|_|Error::RCL_RET_INVALID_ARGUMENT)?;
|
||||||
|
|
||||||
|
|
@ -515,7 +507,7 @@ impl Node {
|
||||||
rcl_publisher_init(
|
rcl_publisher_init(
|
||||||
&mut publisher_handle,
|
&mut publisher_handle,
|
||||||
self.node_handle.as_mut(),
|
self.node_handle.as_mut(),
|
||||||
ts,
|
dummy.ts,
|
||||||
topic_c_string.as_ptr(),
|
topic_c_string.as_ptr(),
|
||||||
&publisher_options,
|
&publisher_options,
|
||||||
)
|
)
|
||||||
|
|
@ -707,22 +699,17 @@ impl PublisherUntyped {
|
||||||
// upgrade to actual ref. if still alive
|
// upgrade to actual ref. if still alive
|
||||||
let publisher = self.handle.upgrade().ok_or(Error::RCL_RET_PUBLISHER_INVALID)?;
|
let publisher = self.handle.upgrade().ok_or(Error::RCL_RET_PUBLISHER_INVALID)?;
|
||||||
|
|
||||||
// figure out which serializer to use, publish, then destroy
|
let mut native_msg = WrappedNativeMsgUntyped::new_from(&self.type_)?;
|
||||||
let se = untyped_serialize_helper(&self.type_)?;
|
native_msg.from_json(msg)?;
|
||||||
let dealloc = untyped_dealloc_helper(&self.type_)?;
|
|
||||||
|
|
||||||
// copy rust msg to native and publish it
|
|
||||||
let native_ptr = se(msg).map_err(|e| Error::SerdeError { err: e.to_string() })?;
|
|
||||||
let result = unsafe {
|
let result = unsafe {
|
||||||
rcl_publish(
|
rcl_publish(
|
||||||
publisher.as_ref(),
|
publisher.as_ref(),
|
||||||
native_ptr,
|
native_msg.void_ptr(),
|
||||||
std::ptr::null_mut(),
|
std::ptr::null_mut(),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
dealloc(native_ptr);
|
|
||||||
|
|
||||||
if result == RCL_RET_OK as i32 {
|
if result == RCL_RET_OK as i32 {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -883,9 +870,20 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn refactor_untyped() {
|
fn test_untyped_json() -> () {
|
||||||
let ptr = native as *const <builtin_interfaces::msg::Duration as WrappedTypesupport>::CStruct;
|
use trajectory_msgs::msg::*;
|
||||||
let msg = unsafe { builtin_interfaces::msg::Duration::from_native(&*ptr) };
|
let mut msg: JointTrajectoryPoint = Default::default();
|
||||||
|
msg.positions.push(39.0);
|
||||||
|
msg.positions.push(34.0);
|
||||||
|
let json = serde_json::to_value(msg.clone()).unwrap();
|
||||||
|
|
||||||
|
let mut native = WrappedNativeMsgUntyped::new_from("trajectory_msgs/msg/JointTrajectoryPoint").unwrap();
|
||||||
|
native.from_json(json.clone()).unwrap();
|
||||||
|
let json2 = native.to_json().unwrap();
|
||||||
|
assert_eq!(json, json2);
|
||||||
|
|
||||||
|
let msg2: JointTrajectoryPoint = serde_json::from_value(json2).unwrap();
|
||||||
|
assert_eq!(msg, msg2);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,13 @@ use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
|
|
||||||
use r2r::*;
|
use r2r;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
// Let's create and drop a lot of node and publishers for a while to see that we can cope.
|
// Let's create and drop a lot of node and publishers for a while to see that we can cope.
|
||||||
fn doesnt_crash() -> Result<(), Error> {
|
fn doesnt_crash() -> Result<(), Error> {
|
||||||
// a global shared context.
|
// a global shared context.
|
||||||
let ctx = Context::create()?;
|
let ctx = r2r::Context::create()?;
|
||||||
|
|
||||||
for c in 0..10 {
|
for c in 0..10 {
|
||||||
let mut ths = Vec::new();
|
let mut ths = Vec::new();
|
||||||
|
|
@ -16,14 +16,14 @@ fn doesnt_crash() -> Result<(), Error> {
|
||||||
// create concurrent nodes that max out the cpu
|
// create concurrent nodes that max out the cpu
|
||||||
let ctx = ctx.clone();
|
let ctx = ctx.clone();
|
||||||
ths.push(thread::spawn(move || {
|
ths.push(thread::spawn(move || {
|
||||||
let mut node = Node::create(ctx, &format!("testnode{}", i), "").unwrap();
|
let mut node = r2r::Node::create(ctx, &format!("testnode{}", i), "").unwrap();
|
||||||
|
|
||||||
// each with 10 publishers
|
// each with 10 publishers
|
||||||
for _j in 0..10 {
|
for _j in 0..10 {
|
||||||
let p = node
|
let p = node
|
||||||
.create_publisher::<std_msgs::msg::String>(&format!("/r2r{}", i))
|
.create_publisher::<r2r::std_msgs::msg::String>(&format!("/r2r{}", i))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let to_send = std_msgs::msg::String {
|
let to_send = r2r::std_msgs::msg::String {
|
||||||
data: format!("[node{}]: {}", i, c),
|
data: format!("[node{}]: {}", i, c),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue