diff --git a/README.md b/README.md index dcc0722..8331e57 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ What works? Changelog -------------------- #### [Unreleased] +- Message (de-)serialization helpers . - Raw message subscribers. #### [0.8.2] - 2023-12-11 diff --git a/r2r/benches/deserialization.rs b/r2r/benches/deserialization.rs index f81342b..db9bfb1 100644 --- a/r2r/benches/deserialization.rs +++ b/r2r/benches/deserialization.rs @@ -1,7 +1,7 @@ use criterion::{criterion_group, criterion_main, Criterion}; use r2r::*; -use rand::Rng; use rand::thread_rng; +use rand::Rng; const NUM_ELEMENTS: usize = 10_000; const NUM_TIMES: usize = 1_000; @@ -15,7 +15,7 @@ fn bench_ros_deserialization() { } let message = std_msgs::msg::Int32MultiArray { layout: std_msgs::msg::MultiArrayLayout::default(), - data: numbers + data: numbers, }; let bytes = message.to_serialized_bytes().unwrap(); @@ -34,7 +34,7 @@ fn bench_cdr_deserialization() { } let message = std_msgs::msg::Int32MultiArray { layout: std_msgs::msg::MultiArrayLayout::default(), - data: numbers + data: numbers, }; let bytes = message.to_serialized_bytes().unwrap(); diff --git a/r2r/examples/tokio_raw_subscriber.rs b/r2r/examples/tokio_raw_subscriber.rs index 9f238b7..a00b85a 100644 --- a/r2r/examples/tokio_raw_subscriber.rs +++ b/r2r/examples/tokio_raw_subscriber.rs @@ -1,6 +1,7 @@ use futures::future; use futures::stream::StreamExt; use r2r::QosProfile; +use r2r::WrappedTypesupport; use serde::{Deserialize, Serialize}; #[tokio::main] @@ -27,21 +28,28 @@ async fn main() -> Result<(), Box> { } }); - // Demonstrate that we can deserialize the raw bytes into this - // rust struct using the cdr crate. - #[derive(Deserialize, Serialize, PartialEq, Debug)] - struct OurOwnStdString { - data: String, // the field name can be anything... - } sub.for_each(|msg| { - println!("got raw bytes of length {}.", msg.len()); + println!("got raw bytes with size: {}. deserialize...", msg.len()); - if let Ok(data) = cdr::deserialize::(&msg) { - println!("contents: {:?}", data); - } else { - println!("Warning: cannot deserialize data."); + // We can use the ROS typesupport to perform deserialization. + let ros_str = r2r::std_msgs::msg::String::from_serialized_bytes(&msg); + + // Demonstrate that it is possible to also deserialize the raw + // bytes into a rust struct using the `cdr` crate. + #[derive(Deserialize, Serialize, PartialEq, Debug)] + struct OurOwnStdString { + data: String, // the field name can be anything... } + let cdr_str = cdr::deserialize::(&msg); + match (ros_str, cdr_str) { + (Ok(s1), Ok(s2)) => { + assert!(s1.data == s2.data); + println!("... using ros: {:?}", s1); + println!("... using cdr: {:?}", s2); + } + _ => println!("Error: cannot deserialize data."), + } future::ready(()) }) .await; diff --git a/r2r/src/msg_types.rs b/r2r/src/msg_types.rs index 989a3f8..78a9f7b 100644 --- a/r2r/src/msg_types.rs +++ b/r2r/src/msg_types.rs @@ -1,15 +1,15 @@ use crate::error::*; use r2r_msg_gen::*; use r2r_rcl::{ - rosidl_action_type_support_t, rosidl_message_type_support_t, rosidl_service_type_support_t, - rcl_serialized_message_t, + rcl_serialized_message_t, rosidl_action_type_support_t, rosidl_message_type_support_t, + rosidl_service_type_support_t, }; use serde::{Deserialize, Serialize}; use std::boxed::Box; +use std::cell::RefCell; use std::convert::TryInto; use std::fmt::Debug; use std::ops::{Deref, DerefMut}; -use std::cell::RefCell; pub mod generated_msgs { #![allow(clippy::all)] @@ -78,9 +78,12 @@ pub trait WrappedTypesupport: self.copy_to_native(unsafe { msg.as_mut().expect("not null") }); - let msg_buf: &mut rcl_serialized_message_t = &mut *msg_buf.as_ref().map_err(|err| Error::from_rcl_error(*err))?.borrow_mut(); + let msg_buf: &mut rcl_serialized_message_t = &mut *msg_buf + .as_ref() + .map_err(|err| Error::from_rcl_error(*err))? + .borrow_mut(); - let result = unsafe { + let result = unsafe { rmw_serialize( msg as *const ::std::os::raw::c_void, Self::get_ts(), @@ -112,24 +115,24 @@ pub trait WrappedTypesupport: buffer: data.as_ptr() as *mut u8, buffer_length: data.len(), buffer_capacity: data.len(), - + // Since its read only, this should never be used .. - allocator: unsafe { rcutils_get_default_allocator() } + allocator: unsafe { rcutils_get_default_allocator() }, }; // Note From the docs of rmw_deserialize, its not clear whether this reuses // any part of msg_buf. However it shouldn't matter since from_native // clones everything again anyway .. - let result = unsafe { + let result = unsafe { rmw_deserialize( &msg_buf as *const rcl_serialized_message_t, Self::get_ts(), msg as *mut std::os::raw::c_void, ) }; - + let ret_val = if result == RCL_RET_OK as i32 { - Ok(Self::from_native(unsafe{ msg.as_ref().expect("not null") })) + Ok(Self::from_native(unsafe { msg.as_ref().expect("not null") })) } else { Err(Error::from_rcl_error(result)) }; @@ -137,7 +140,6 @@ pub trait WrappedTypesupport: Self::destroy_msg(msg); ret_val - } } @@ -704,8 +706,8 @@ mod tests { #[test] fn test_serialization_fixed_size() { - let message = std_msgs::msg::Int32 { data: 10}; - + let message = std_msgs::msg::Int32 { data: 10 }; + let bytes = message.to_serialized_bytes().unwrap(); let message_2 = std_msgs::msg::Int32::from_serialized_bytes(&bytes).unwrap(); @@ -717,16 +719,15 @@ mod tests { assert_eq!(bytes, bytes_2); assert_eq!(bytes, bytes_3); - } #[test] fn test_serialization_dynamic_size() { - let message = std_msgs::msg::Int32MultiArray { + let message = std_msgs::msg::Int32MultiArray { layout: std_msgs::msg::MultiArrayLayout::default(), - data: vec![10, 20, 30] + data: vec![10, 20, 30], }; - + let bytes = message.to_serialized_bytes().unwrap(); let message_2 = std_msgs::msg::Int32MultiArray::from_serialized_bytes(&bytes).unwrap(); @@ -735,10 +736,9 @@ mod tests { let bytes_2 = message_2.to_serialized_bytes().unwrap(); let bytes_3 = message_2.to_serialized_bytes().unwrap(); - + assert_eq!(bytes, bytes_2); assert_eq!(bytes, bytes_3); - } #[cfg(r2r__test_msgs__msg__Defaults)] diff --git a/r2r_msg_gen/src/lib.rs b/r2r_msg_gen/src/lib.rs index 26c3d19..450384c 100644 --- a/r2r_msg_gen/src/lib.rs +++ b/r2r_msg_gen/src/lib.rs @@ -707,8 +707,7 @@ pub fn generate_rust_msg(module_: &str, prefix_: &str, name_: &str) -> proc_macr // (see https://github.com/rust-lang/rust/issues/115010) typ.lifetime = Some(syn::Lifetime::new("'static", proc_macro2::Span::call_site())); quote! { pub const #const_name: #typ = #value; } - } - else if let Ok(typ) = syn::parse_str::>(typ) { + } else if let Ok(typ) = syn::parse_str::>(typ) { // Value quote! { pub const #const_name: #typ = #value; } } else {