1use crate::error::*;
2use r2r_msg_gen::*;
3use r2r_rcl::{
4 rcl_serialized_message_t, rosidl_action_type_support_t, rosidl_message_type_support_t,
5 rosidl_service_type_support_t,
6};
7use serde::{Deserialize, Serialize};
8use std::{
9 boxed::Box,
10 cell::RefCell,
11 convert::TryInto,
12 fmt::Debug,
13 ops::{Deref, DerefMut},
14};
15
16pub mod generated_msgs {
17 #![allow(clippy::all)]
18 use super::*;
19 include!(concat!(env!("OUT_DIR"), "/_r2r_generated_msgs.rs"));
20 include!(concat!(env!("OUT_DIR"), "/_r2r_generated_untyped_helper.rs"));
21 include!(concat!(env!("OUT_DIR"), "/_r2r_generated_service_helper.rs"));
22 include!(concat!(env!("OUT_DIR"), "/_r2r_generated_action_helper.rs"));
23}
24
25use generated_msgs::{builtin_interfaces, unique_identifier_msgs};
26
27fn vec_to_uuid_bytes<T>(v: Vec<T>) -> [T; 16] {
28 v.try_into().unwrap_or_else(|v: Vec<T>| {
29 panic!("Expected a Vec of length {} but it was {}", 16, v.len())
30 })
31}
32
33pub(crate) fn uuid_msg_to_uuid(msg: &unique_identifier_msgs::msg::UUID) -> uuid::Uuid {
35 let bytes = vec_to_uuid_bytes(msg.uuid.clone());
36 uuid::Uuid::from_bytes(bytes)
37}
38
39thread_local! {
41 pub static SERIALIZED_MESSAGE_CACHE: std::result::Result<RefCell<rcl_serialized_message_t>, i32> = {
42 use r2r_rcl::*;
43
44 let mut msg_buf: rcl_serialized_message_t = unsafe { rcutils_get_zero_initialized_uint8_array() };
45
46 let ret = unsafe {
47 rcutils_uint8_array_init(
48 &mut msg_buf as *mut rcl_serialized_message_t,
49 0,
50 &rcutils_get_default_allocator(),
51 )
52 };
53
54 if ret != RCL_RET_OK as i32 {
55 Err(ret)
56 } else {
57 Ok(RefCell::new(msg_buf))
58 }
59
60 };
61}
62
63pub trait WrappedTypesupport:
64 Serialize + for<'de> Deserialize<'de> + Default + Debug + Clone
65{
66 type CStruct;
67
68 fn get_ts() -> &'static rosidl_message_type_support_t;
69 fn create_msg() -> *mut Self::CStruct;
70 fn destroy_msg(msg: *mut Self::CStruct);
71 fn from_native(msg: &Self::CStruct) -> Self;
72 fn copy_to_native(&self, msg: &mut Self::CStruct);
73
74 fn to_serialized_bytes(&self) -> Result<Vec<u8>> {
76 use r2r_rcl::*;
77
78 SERIALIZED_MESSAGE_CACHE.with(|msg_buf| {
79 let msg = Self::create_msg();
80
81 self.copy_to_native(unsafe { msg.as_mut().expect("not null") });
82
83 let msg_buf: &mut rcl_serialized_message_t = &mut msg_buf
84 .as_ref()
85 .map_err(|err| Error::from_rcl_error(*err))?
86 .borrow_mut();
87
88 let result = unsafe {
89 rmw_serialize(
90 msg as *const ::std::os::raw::c_void,
91 Self::get_ts(),
92 msg_buf as *mut rcl_serialized_message_t,
93 )
94 };
95
96 let data_bytes = if msg_buf.buffer == std::ptr::null_mut() {
97 Vec::new()
98 } else {
99 unsafe {
100 std::slice::from_raw_parts(msg_buf.buffer, msg_buf.buffer_length).to_vec()
101 }
102 };
103
104 Self::destroy_msg(msg);
105
106 if result == RCL_RET_OK as i32 {
107 Ok(data_bytes)
108 } else {
109 Err(Error::from_rcl_error(result))
110 }
111 })
112 }
113
114 fn from_serialized_bytes(data: &[u8]) -> Result<Self> {
116 use r2r_rcl::*;
117
118 let msg = Self::create_msg();
119
120 let msg_buf = rcl_serialized_message_t {
121 buffer: data.as_ptr() as *mut u8,
122 buffer_length: data.len(),
123 buffer_capacity: data.len(),
124
125 allocator: unsafe { rcutils_get_default_allocator() },
127 };
128
129 let result = unsafe {
133 rmw_deserialize(
134 &msg_buf as *const rcl_serialized_message_t,
135 Self::get_ts(),
136 msg as *mut std::os::raw::c_void,
137 )
138 };
139
140 let ret_val = if result == RCL_RET_OK as i32 {
141 Ok(Self::from_native(unsafe { msg.as_ref().expect("not null") }))
142 } else {
143 Err(Error::from_rcl_error(result))
144 };
145
146 Self::destroy_msg(msg);
147
148 ret_val
149 }
150}
151
152pub trait WrappedServiceTypeSupport: Debug + Clone {
153 type Request: WrappedTypesupport;
154 type Response: WrappedTypesupport;
155
156 fn get_ts() -> &'static rosidl_service_type_support_t;
157}
158
159pub trait WrappedActionTypeSupport: Debug + Clone {
160 type Goal: WrappedTypesupport;
161 type Result: WrappedTypesupport;
162 type Feedback: WrappedTypesupport;
163
164 type FeedbackMessage: WrappedTypesupport;
166 type SendGoal: WrappedServiceTypeSupport;
167 type GetResult: WrappedServiceTypeSupport;
168
169 fn get_ts() -> &'static rosidl_action_type_support_t;
170
171 fn make_goal_request_msg(
172 goal_id: unique_identifier_msgs::msg::UUID, goal: Self::Goal,
173 ) -> <<Self as WrappedActionTypeSupport>::SendGoal as WrappedServiceTypeSupport>::Request;
174 fn make_goal_response_msg(
175 accepted: bool, stamp: builtin_interfaces::msg::Time,
176 ) -> <<Self as WrappedActionTypeSupport>::SendGoal as WrappedServiceTypeSupport>::Response;
177 fn make_feedback_msg(
178 goal_id: unique_identifier_msgs::msg::UUID, feedback: Self::Feedback,
179 ) -> Self::FeedbackMessage;
180 fn make_result_request_msg(
181 goal_id: unique_identifier_msgs::msg::UUID,
182 ) -> <<Self as WrappedActionTypeSupport>::GetResult as WrappedServiceTypeSupport>::Request;
183 fn make_result_response_msg(
184 status: i8, result: Self::Result,
185 ) -> <<Self as WrappedActionTypeSupport>::GetResult as WrappedServiceTypeSupport>::Response;
186 fn destructure_goal_request_msg(
187 msg: <<Self as WrappedActionTypeSupport>::SendGoal as WrappedServiceTypeSupport>::Request,
188 ) -> (unique_identifier_msgs::msg::UUID, Self::Goal);
189 fn destructure_goal_response_msg(
190 msg: <<Self as WrappedActionTypeSupport>::SendGoal as WrappedServiceTypeSupport>::Response,
191 ) -> (bool, builtin_interfaces::msg::Time);
192 fn destructure_feedback_msg(
193 msg: Self::FeedbackMessage,
194 ) -> (unique_identifier_msgs::msg::UUID, Self::Feedback);
195 fn destructure_result_response_msg(
196 msg: <<Self as WrappedActionTypeSupport>::GetResult as WrappedServiceTypeSupport>::Response,
197 ) -> (i8, Self::Result);
198 fn destructure_result_request_msg(
199 msg: <<Self as WrappedActionTypeSupport>::GetResult as WrappedServiceTypeSupport>::Request,
200 ) -> unique_identifier_msgs::msg::UUID;
201}
202
203pub struct WrappedNativeMsg<T>
207where
208 T: WrappedTypesupport,
209{
210 pub msg: *mut T::CStruct,
211 pub is_loaned: bool,
212 deallocator: Option<Box<dyn FnOnce(*mut T::CStruct)>>,
213}
214
215pub trait VoidPtr {
216 fn void_ptr(&self) -> *const std::os::raw::c_void;
217 fn void_ptr_mut(&mut self) -> *mut std::os::raw::c_void;
218}
219
220#[derive(Debug)]
221pub struct WrappedNativeMsgUntyped {
222 pub ts: &'static rosidl_message_type_support_t,
223 msg: *mut std::os::raw::c_void,
224 destroy: fn(*mut std::os::raw::c_void),
225 msg_to_json: fn(
226 native: *const std::os::raw::c_void,
227 ) -> std::result::Result<serde_json::Value, serde_json::error::Error>,
228 msg_from_json: fn(
229 native: *mut std::os::raw::c_void,
230 json: serde_json::Value,
231 ) -> std::result::Result<(), serde_json::error::Error>,
232}
233
234unsafe impl Send for UntypedServiceSupport {}
235pub struct UntypedServiceSupport {
236 pub ts: &'static rosidl_service_type_support_t,
237 pub make_request_msg: fn() -> WrappedNativeMsgUntyped,
238 pub make_response_msg: fn() -> WrappedNativeMsgUntyped,
239}
240
241impl UntypedServiceSupport {
242 fn new<T>() -> Self
243 where
244 T: WrappedServiceTypeSupport,
245 {
246 let make_request_msg = WrappedNativeMsgUntyped::new::<T::Request>;
247 let make_response_msg = WrappedNativeMsgUntyped::new::<T::Response>;
248
249 UntypedServiceSupport {
250 ts: T::get_ts(),
251 make_request_msg,
252 make_response_msg,
253 }
254 }
255}
256
257unsafe impl Send for UntypedActionSupport {}
259pub struct UntypedActionSupport {
260 pub(crate) ts: &'static rosidl_action_type_support_t,
261
262 pub(crate) make_goal_request_msg: Box<
263 dyn Fn(unique_identifier_msgs::msg::UUID, serde_json::Value) -> WrappedNativeMsgUntyped,
264 >,
265 pub(crate) make_goal_response_msg: Box<dyn Fn() -> WrappedNativeMsgUntyped>,
266 pub(crate) destructure_goal_response_msg:
267 Box<dyn Fn(WrappedNativeMsgUntyped) -> (bool, builtin_interfaces::msg::Time)>,
268
269 pub(crate) make_feedback_msg: fn() -> WrappedNativeMsgUntyped,
270 pub(crate) destructure_feedback_msg: Box<
271 dyn Fn(
272 WrappedNativeMsgUntyped,
273 ) -> (unique_identifier_msgs::msg::UUID, Result<serde_json::Value>),
274 >,
275
276 pub(crate) make_result_request_msg:
277 Box<dyn Fn(unique_identifier_msgs::msg::UUID) -> WrappedNativeMsgUntyped>,
278 pub(crate) make_result_response_msg: Box<dyn Fn() -> WrappedNativeMsgUntyped>,
279 pub(crate) destructure_result_response_msg:
280 Box<dyn Fn(WrappedNativeMsgUntyped) -> (i8, Result<serde_json::Value>)>,
281}
282
283impl UntypedActionSupport {
284 fn new<T>() -> Self
285 where
286 T: WrappedActionTypeSupport,
287 {
288 let make_goal_request_msg = Box::new(|goal_id, goal| {
292 let goal_msg: T::Goal =
293 serde_json::from_value(goal).expect("TODO: move this error handling");
294 let request_msg = T::make_goal_request_msg(goal_id, goal_msg);
295 let json = serde_json::to_value(request_msg).expect("TODO: move this error handling");
296 let native_untyped = WrappedNativeMsgUntyped::new::<
297 <<T as WrappedActionTypeSupport>::SendGoal as WrappedServiceTypeSupport>::Request,
298 >();
299 native_untyped
300 .from_json(json)
301 .expect("TODO: move this error handling");
302 native_untyped
303 });
304
305 let make_goal_response_msg = Box::new(|| {
306 WrappedNativeMsgUntyped::new::<
307 <<T as WrappedActionTypeSupport>::SendGoal as WrappedServiceTypeSupport>::Response,
308 >()
309 });
310
311 let destructure_goal_response_msg = Box::new(|msg: WrappedNativeMsgUntyped| {
312 let msg = unsafe {
313 <<<T as WrappedActionTypeSupport>::SendGoal as WrappedServiceTypeSupport>::Response>
314 ::from_native(&*(msg.msg as *const <<<T as WrappedActionTypeSupport>::SendGoal as
315 WrappedServiceTypeSupport>::Response as WrappedTypesupport>::CStruct))
316 };
317 T::destructure_goal_response_msg(msg)
318 });
319
320 let make_feedback_msg = WrappedNativeMsgUntyped::new::<T::FeedbackMessage>;
321
322 let destructure_feedback_msg = Box::new(|msg: WrappedNativeMsgUntyped| {
323 let msg = unsafe {
324 T::FeedbackMessage::from_native(
325 &*(msg.msg as *const <T::FeedbackMessage as WrappedTypesupport>::CStruct),
326 )
327 };
328 let (uuid, feedback) = T::destructure_feedback_msg(msg);
329 let json = serde_json::to_value(feedback).map_err(|serde_err| Error::SerdeError {
330 err: serde_err.to_string(),
331 });
332 (uuid, json)
333 });
334
335 let make_result_request_msg = Box::new(|uuid_msg: unique_identifier_msgs::msg::UUID| {
336 let request_msg = T::make_result_request_msg(uuid_msg);
337 let json = serde_json::to_value(request_msg).expect("TODO: move this error handling");
338
339 let native_untyped = WrappedNativeMsgUntyped::new::<
340 <<T as WrappedActionTypeSupport>::GetResult as WrappedServiceTypeSupport>::Request,
341 >();
342
343 native_untyped
344 .from_json(json)
345 .expect("TODO: move this error handling");
346 native_untyped
347 });
348
349 let make_result_response_msg = Box::new(|| {
350 WrappedNativeMsgUntyped::new::<
351 <<T as WrappedActionTypeSupport>::GetResult as WrappedServiceTypeSupport>::Response,
352 >()
353 });
354
355 let destructure_result_response_msg = Box::new(|msg: WrappedNativeMsgUntyped| {
356 let msg = unsafe {
357 <<<T as WrappedActionTypeSupport>::GetResult as WrappedServiceTypeSupport>::Response>
358 ::from_native(&*(msg.msg as *const <<<T as WrappedActionTypeSupport>::GetResult as
359 WrappedServiceTypeSupport>::Response as WrappedTypesupport>::CStruct))
360 };
361 let (status, result) = T::destructure_result_response_msg(msg);
362 let json = serde_json::to_value(result).map_err(|serde_err| Error::SerdeError {
363 err: serde_err.to_string(),
364 });
365 (status, json)
366 });
367
368 UntypedActionSupport {
369 ts: T::get_ts(),
370 make_goal_request_msg,
371 make_goal_response_msg,
372 destructure_goal_response_msg,
373 make_feedback_msg,
374 destructure_feedback_msg,
375 make_result_request_msg,
376 make_result_response_msg,
377 destructure_result_response_msg,
378 }
382 }
383}
384
385impl WrappedNativeMsgUntyped {
386 fn new<T>() -> Self
387 where
388 T: WrappedTypesupport,
389 {
390 let destroy = |native: *mut std::os::raw::c_void| {
391 let native_msg = native as *mut T::CStruct;
392 T::destroy_msg(native_msg);
393 };
394
395 let msg_to_json = |native: *const std::os::raw::c_void| {
396 let msg = unsafe { T::from_native(&*(native as *const T::CStruct)) };
397 serde_json::to_value(&msg)
398 };
399
400 let msg_from_json = |native: *mut std::os::raw::c_void, json: serde_json::Value| {
401 serde_json::from_value(json).map(|msg: T| unsafe {
402 msg.copy_to_native(&mut *(native as *mut T::CStruct));
403 })
404 };
405
406 WrappedNativeMsgUntyped {
407 ts: T::get_ts(),
408 msg: T::create_msg() as *mut std::os::raw::c_void,
409 destroy,
410 msg_to_json,
411 msg_from_json,
412 }
413 }
414
415 pub fn from_serialized_bytes(&mut self, data: &[u8]) -> Result<()> {
416 use r2r_rcl::*;
418
419 let msg_buf = rcl_serialized_message_t {
420 buffer: data.as_ptr() as *mut u8,
421 buffer_length: data.len(),
422 buffer_capacity: data.len(),
423
424 allocator: unsafe { rcutils_get_default_allocator() },
426 };
427
428 let result = unsafe {
432 rmw_deserialize(&msg_buf as *const rcl_serialized_message_t, self.ts, self.msg)
433 };
434
435 if result == RCL_RET_OK as i32 {
436 Ok(())
437 } else {
438 Err(Error::from_rcl_error(result))
439 }
440 }
441
442 pub fn to_json(&self) -> Result<serde_json::Value> {
443 let json = (self.msg_to_json)(self.msg);
444 json.map_err(|serde_err| Error::SerdeError {
445 err: serde_err.to_string(),
446 })
447 }
448
449 pub fn from_json(&self, json: serde_json::Value) -> Result<()> {
450 (self.msg_from_json)(self.msg, json).map_err(|serde_err| Error::SerdeError {
451 err: serde_err.to_string(),
452 })
453 }
454}
455
456impl VoidPtr for WrappedNativeMsgUntyped {
457 fn void_ptr(&self) -> *const std::os::raw::c_void {
458 self.msg as *const _ as *const std::os::raw::c_void
459 }
460
461 fn void_ptr_mut(&mut self) -> *mut std::os::raw::c_void {
462 self.msg as *mut _ as *mut std::os::raw::c_void
463 }
464}
465
466impl Drop for WrappedNativeMsgUntyped {
467 fn drop(&mut self) {
468 (self.destroy)(self.msg);
469 }
470}
471
472impl<T> WrappedNativeMsg<T>
473where
474 T: WrappedTypesupport + 'static,
475{
476 pub fn new() -> Self {
477 WrappedNativeMsg {
478 msg: T::create_msg(),
479 deallocator: Some(Box::new(T::destroy_msg)),
480 is_loaned: false,
481 }
482 }
483
484 pub fn from(msg: &T) -> Self {
485 let mut native_msg = Self::new();
486 msg.copy_to_native(&mut native_msg);
487 native_msg
488 }
489
490 pub fn from_loaned(
491 msg: *mut T::CStruct, deallocator: Box<dyn FnOnce(*mut <T as WrappedTypesupport>::CStruct)>,
492 ) -> Self {
493 WrappedNativeMsg {
494 msg,
495 deallocator: Some(deallocator),
496 is_loaned: true,
497 }
498 }
499
500 pub fn release(&mut self) {
501 self.deallocator.take();
502 }
503}
504
505impl<T> Default for WrappedNativeMsg<T>
506where
507 T: WrappedTypesupport + 'static,
508{
509 fn default() -> Self {
510 Self::new()
511 }
512}
513
514impl<T: 'static> VoidPtr for WrappedNativeMsg<T>
515where
516 T: WrappedTypesupport,
517{
518 fn void_ptr(&self) -> *const std::os::raw::c_void {
519 self.msg as *const _ as *const std::os::raw::c_void
520 }
521
522 fn void_ptr_mut(&mut self) -> *mut std::os::raw::c_void {
523 self.msg as *mut _ as *mut std::os::raw::c_void
524 }
525}
526
527impl<T> Drop for WrappedNativeMsg<T>
528where
529 T: WrappedTypesupport,
530{
531 fn drop(&mut self) {
532 if let Some(deallocator) = self.deallocator.take() {
533 (deallocator)(self.msg);
534 }
535 }
536}
537
538impl<T> Deref for WrappedNativeMsg<T>
539where
540 T: WrappedTypesupport,
541{
542 type Target = T::CStruct;
543
544 fn deref(&self) -> &Self::Target {
545 unsafe { &(*self.msg) }
546 }
547}
548
549impl<T> DerefMut for WrappedNativeMsg<T>
550where
551 T: WrappedTypesupport,
552{
553 fn deref_mut(&mut self) -> &mut Self::Target {
554 unsafe { &mut (*self.msg) }
555 }
556}
557
558#[cfg(test)]
559mod tests {
560 use super::{generated_msgs::*, *};
561 use r2r_rcl::*;
562
563 #[test]
564 fn test_ros_str() {
565 let hej = "hej hopp";
566 let mut msg = WrappedNativeMsg::<std_msgs::msg::String>::new();
567 msg.data.assign(hej);
568 assert_eq!(msg.data.to_str(), hej);
569 }
570
571 #[test]
572 fn test_copy_fields() {
573 let msg_orig = std_msgs::msg::String { data: "hej".into() };
574 let rosmsg = WrappedNativeMsg::<std_msgs::msg::String>::from(&msg_orig);
575 let msg2 = std_msgs::msg::String::from_native(&rosmsg);
576 assert_eq!(msg_orig, msg2);
577 }
578
579 #[test]
580 fn test_introspection_string() {
581 unsafe {
582 use std::ffi::CStr;
583
584 let x = rosidl_typesupport_introspection_c__get_message_type_support_handle__std_msgs__msg__String();
585 let members = (*x).data as *const rosidl_typesupport_introspection_c__MessageMembers;
586 println!("{:#?}", *members);
587
588 assert_eq!((*members).member_count_, 1);
589
590 let s = CStr::from_ptr((*members).message_namespace_)
591 .to_str()
592 .unwrap();
593 assert_eq!(s, "std_msgs__msg");
594
595 let s = CStr::from_ptr((*members).message_name_).to_str().unwrap();
596 assert_eq!(s, "String");
597
598 let member = (*members).members_;
599 println!("member: {:#?}", *member);
600 let field_name = CStr::from_ptr((*member).name_).to_str().unwrap();
601 let type_id = (*member).type_id_;
602 let is_array = (*member).is_array_;
603 assert_eq!(field_name, "data");
604 assert_eq!(type_id, 16u8); assert!(!is_array);
606 }
607 }
608
609 #[test]
610 #[should_panic] fn test_fixedsizearray() {
612 unsafe {
613 let x = rosidl_typesupport_introspection_c__get_message_type_support_handle__geometry_msgs__msg__AccelWithCovariance();
614 let members = (*x).data as *const rosidl_typesupport_introspection_c__MessageMembers;
615 println!("{:#?}", *members);
616
617 let memberslice =
618 std::slice::from_raw_parts((*members).members_, (*members).member_count_ as usize);
619 for member in memberslice {
620 println!("member: {:#?}", *member);
621 }
622
623 let msg_native = WrappedNativeMsg::<geometry_msgs::msg::AccelWithCovariance>::new();
624 let mut msg = geometry_msgs::msg::AccelWithCovariance::from_native(&msg_native);
625 println!("{:#?}", msg);
626 msg.covariance[0] = 10.0;
627 msg.covariance[10] = 10.0;
628 msg.covariance[35] = 99.0;
629 msg.covariance.push(4444.0);
630 let msg_native2 =
631 WrappedNativeMsg::<geometry_msgs::msg::AccelWithCovariance>::from(&msg);
632 let msg2 = geometry_msgs::msg::AccelWithCovariance::from_native(&msg_native2);
633 println!("{:#?}", msg2);
634 }
635 }
636
637 #[test]
638 #[should_panic] fn test_capped_sequence() {
640 unsafe {
642 let x = rosidl_typesupport_introspection_c__get_message_type_support_handle__shape_msgs__msg__SolidPrimitive();
643 let members = (*x).data as *const rosidl_typesupport_introspection_c__MessageMembers;
644 println!("{:#?}", *members);
645
646 let memberslice =
647 std::slice::from_raw_parts((*members).members_, (*members).member_count_ as usize);
648 for member in memberslice {
649 println!("member: {:#?}", *member);
650 }
651
652 let msg_native = WrappedNativeMsg::<shape_msgs::msg::SolidPrimitive>::new();
653 let mut msg = shape_msgs::msg::SolidPrimitive::from_native(&msg_native);
654 println!("{:#?}", msg);
655 msg.dimensions.push(1.0);
656 msg.dimensions.push(1.0);
657 msg.dimensions.push(1.0);
658 msg.dimensions.push(1.0); let _msg_native2 = WrappedNativeMsg::<shape_msgs::msg::SolidPrimitive>::from(&msg);
660 }
661 }
662
663 #[test]
664 fn test_generation_string_use() {
665 let msg = std_msgs::msg::String { data: "hej".into() };
666 let msg2 = msg.clone();
667 let msg_native = WrappedNativeMsg::<std_msgs::msg::String>::from(&msg2);
668 let msg2 = std_msgs::msg::String::from_native(&msg_native);
669 assert_eq!(msg, msg2)
670 }
671
672 #[test]
673 fn test_generation_bool_use() {
674 let msg = std_msgs::msg::Bool { data: true };
675 let msg_native = WrappedNativeMsg::<std_msgs::msg::Bool>::from(&msg);
676 let msg2 = std_msgs::msg::Bool::from_native(&msg_native);
677 assert_eq!(msg, msg2);
678 }
679
680 #[test]
681 fn test_float_sequence() {
682 use trajectory_msgs::msg::*;
683 let native = WrappedNativeMsg::<JointTrajectoryPoint>::new();
684 let mut msg = JointTrajectoryPoint::from_native(&native);
685 msg.positions.push(39.0);
686 msg.positions.push(34.0);
687 let new_native = WrappedNativeMsg::<JointTrajectoryPoint>::from(&msg);
688 let new_msg = JointTrajectoryPoint::from_native(&new_native);
689 println!("{:#?}", new_msg);
690 assert_eq!(msg, new_msg);
691 }
692
693 #[test]
694 fn test_deault() {
695 use trajectory_msgs::msg::*;
696 let mut msg: JointTrajectoryPoint = Default::default();
697 msg.positions.push(39.0);
698 msg.positions.push(34.0);
699 let mut new_native = WrappedNativeMsg::<JointTrajectoryPoint>::from(&msg);
700 unsafe { *new_native.positions.data = 88.9 };
701 let new_msg = JointTrajectoryPoint::from_native(&new_native);
702 println!("{:#?}", new_msg);
703 assert_ne!(msg, new_msg);
704 }
705
706 #[test]
707 fn test_untyped_json() {
708 let mut msg = trajectory_msgs::msg::JointTrajectoryPoint::default();
709 msg.positions.push(39.0);
710 msg.positions.push(34.0);
711 let json = serde_json::to_value(msg.clone()).unwrap();
712
713 let native =
714 WrappedNativeMsgUntyped::new_from("trajectory_msgs/msg/JointTrajectoryPoint").unwrap();
715 native.from_json(json.clone()).unwrap();
716 let json2 = native.to_json().unwrap();
717 assert_eq!(json, json2);
718
719 let msg2: trajectory_msgs::msg::JointTrajectoryPoint =
720 serde_json::from_value(json2).unwrap();
721 assert_eq!(msg, msg2);
722 }
723
724 #[test]
725 fn test_from_loaned() {
726 type MsgType = trajectory_msgs::msg::JointTrajectoryPoint;
727 type CMsgType = <MsgType as WrappedTypesupport>::CStruct;
728
729 let borrowed_msg = MsgType::create_msg();
730
731 let native = WrappedNativeMsg::<MsgType>::from_loaned(
732 borrowed_msg as *mut CMsgType,
733 Box::new(|_: *mut CMsgType| {}),
734 );
735
736 assert!(native.void_ptr() == borrowed_msg as *mut core::ffi::c_void);
737 }
738
739 #[test]
740 fn test_serialization_fixed_size() {
741 let message = std_msgs::msg::Int32 { data: 10 };
742
743 let bytes = message.to_serialized_bytes().unwrap();
744
745 let message_2 = std_msgs::msg::Int32::from_serialized_bytes(&bytes).unwrap();
746
747 assert_eq!(message.data, message_2.data);
748
749 let bytes_2 = message_2.to_serialized_bytes().unwrap();
750 let bytes_3 = message_2.to_serialized_bytes().unwrap();
751
752 assert_eq!(bytes, bytes_2);
753 assert_eq!(bytes, bytes_3);
754 }
755
756 #[test]
757 fn test_serialization_dynamic_size() {
758 let message = std_msgs::msg::Int32MultiArray {
759 layout: std_msgs::msg::MultiArrayLayout::default(),
760 data: vec![10, 20, 30],
761 };
762
763 let bytes = message.to_serialized_bytes().unwrap();
764
765 let message_2 = std_msgs::msg::Int32MultiArray::from_serialized_bytes(&bytes).unwrap();
766
767 assert_eq!(message.data, message_2.data);
768
769 let bytes_2 = message_2.to_serialized_bytes().unwrap();
770 let bytes_3 = message_2.to_serialized_bytes().unwrap();
771
772 assert_eq!(bytes, bytes_2);
773 assert_eq!(bytes, bytes_3);
774 }
775
776 #[cfg(r2r__test_msgs__msg__Defaults)]
777 #[test]
778 fn test_untyped_json_default() {
779 let json = r#"
788 {
789 "byte_value": 255,
790 "float32_value": 3.14
791 }"#;
792
793 let native = WrappedNativeMsgUntyped::new_from("test_msgs/msg/Defaults").unwrap();
794 let v: serde_json::Value = serde_json::from_str(json).unwrap();
795 native.from_json(v).expect("could make default msg");
796 let json2 = native.to_json().unwrap();
797 let msg2: test_msgs::msg::Defaults = serde_json::from_value(json2).unwrap();
798
799 assert!(msg2.bool_value); assert_eq!(msg2.byte_value, 255); assert_eq!(msg2.char_value, 100); assert_eq!(msg2.float32_value, 3.14); }
804
805 #[cfg(r2r__test_msgs__msg__Arrays)]
806 #[test]
807 fn test_test_msgs_array() {
808 let mut msg = test_msgs::msg::Arrays::default();
809 println!("msg: {:?}", msg.string_values);
810 msg.string_values = vec!["hej".to_string(), "hopp".to_string(), "stropp".to_string()];
811
812 let msg_native = WrappedNativeMsg::<test_msgs::msg::Arrays>::from(&msg);
813 let msg2 = test_msgs::msg::Arrays::from_native(&msg_native);
814
815 assert_eq!(msg, msg2);
816 }
817
818 #[cfg(r2r__test_msgs__msg__Arrays)]
819 #[test]
820 #[should_panic]
821 fn test_test_msgs_array_too_few_elems() {
822 let mut msg = test_msgs::msg::Arrays::default();
823 println!("msg: {:?}", msg.string_values);
824 msg.string_values = vec!["hej".to_string(), "hopp".to_string()];
825 let _msg_native = WrappedNativeMsg::<test_msgs::msg::Arrays>::from(&msg);
826 }
827
828 #[cfg(r2r__test_msgs__msg__WStrings)]
829 #[test]
830 fn test_test_msgs_wstring() {
831 let mut msg = test_msgs::msg::WStrings::default();
832 let rust_str = "ハローワールド";
833 msg.wstring_value = rust_str.to_string();
834 let native = WrappedNativeMsg::<test_msgs::msg::WStrings>::from(&msg);
835 println!("msg: {:?}", msg);
836 let msg2 = test_msgs::msg::WStrings::from_native(&native);
837 assert_eq!(msg.wstring_value, msg2.wstring_value);
838 }
839
840 #[cfg(r2r__example_interfaces__srv__AddTwoInts)]
841 #[test]
842 fn test_service_msgs() {
843 use example_interfaces::srv::AddTwoInts;
844 let req = AddTwoInts::Request {
845 a: 5,
846 ..Default::default()
847 };
848 let rn = WrappedNativeMsg::<_>::from(&req);
849 let req2 = AddTwoInts::Request::from_native(&rn);
850 println!("req2 {:?}", req2);
851 assert_eq!(req, req2);
852
853 let resp = AddTwoInts::Response {
854 sum: 5,
855 ..Default::default()
856 };
857 let rn = WrappedNativeMsg::<_>::from(&resp);
858 let resp2 = AddTwoInts::Response::from_native(&rn);
859 println!("resp {:?}", resp2);
860 assert_eq!(resp, resp2);
861 }
862
863 #[cfg(r2r__std_srvs__srv__Empty)]
864 #[test]
865 fn test_empty_msgs() {
866 use std_srvs::srv::Empty;
867 let req = Empty::Request::default();
868 let resp = Empty::Response::default();
869 println!("req {:?}", req);
870 println!("resp {:?}", resp);
871 }
872
873 #[cfg(r2r__example_interfaces__action__Fibonacci)]
874 #[test]
875 fn test_action_msgs() {
876 use example_interfaces::action::Fibonacci;
877 let goal = Fibonacci::Goal { order: 5 };
878 let gn = WrappedNativeMsg::<_>::from(&goal);
879 let goal2 = Fibonacci::Goal::from_native(&gn);
880 println!("goal2 {:?}", goal2);
881 assert_eq!(goal, goal2);
882
883 let res = Fibonacci::Result {
884 sequence: vec![1, 2, 3],
885 };
886 let rn = WrappedNativeMsg::<_>::from(&res);
887 let res2 = Fibonacci::Result::from_native(&rn);
888 println!("res2 {:?}", res2);
889 assert_eq!(res, res2);
890
891 let fb = Fibonacci::Feedback {
892 sequence: vec![4, 3, 6],
893 };
894 let fbn = WrappedNativeMsg::<_>::from(&fb);
895 let fb2 = Fibonacci::Feedback::from_native(&fbn);
896 println!("feedback2 {:?}", fb2);
897 assert_eq!(fb, fb2);
898
899 let fb = WrappedNativeMsg::<Fibonacci::Feedback>::new();
900 let fb1 = Fibonacci::Feedback::default();
901 let fb2 = Fibonacci::Feedback::from_native(&fb);
902 assert_eq!(fb1, fb2);
903 }
904
905 #[cfg(r2r__example_interfaces__srv__AddTwoInts)]
906 #[test]
907 fn test_untyped_service_support() {
908 let ts = UntypedServiceSupport::new_from("example_interfaces/srv/AddTwoInts").unwrap();
909 let msg = (ts.make_request_msg)();
910 let json = msg.to_json();
911 assert!(!json.unwrap().to_string().is_empty());
913 }
914
915 #[cfg(r2r__example_interfaces__action__Fibonacci)]
916 #[test]
917 fn test_untyped_action_support() {
918 use example_interfaces::action::Fibonacci;
919
920 let ts = UntypedActionSupport::new_from("example_interfaces/action/Fibonacci").unwrap();
921 let uuid = unique_identifier_msgs::msg::UUID::default();
922 let goal = Fibonacci::Goal { order: 5 };
923 let json_goal = serde_json::to_value(&goal).unwrap();
924 let json_request = (ts.make_goal_request_msg)(uuid, json_goal)
925 .to_json()
926 .unwrap();
927 assert!(!json_request.to_string().is_empty());
929 }
930
931 #[cfg(r2r__action_msgs__msg__GoalStatus)]
932 #[test]
933 fn test_msg_constants() {
934 use action_msgs::msg::GoalStatus;
935 let gs = GoalStatus::default();
936
937 assert_eq!(gs.status, GoalStatus::STATUS_UNKNOWN as i8);
938 assert_eq!(0, GoalStatus::STATUS_UNKNOWN as i8);
939 assert_eq!(1, GoalStatus::STATUS_ACCEPTED as i8);
940 assert_eq!(2, GoalStatus::STATUS_EXECUTING as i8);
941 assert_eq!(3, GoalStatus::STATUS_CANCELING as i8);
942 assert_eq!(4, GoalStatus::STATUS_SUCCEEDED as i8);
943 assert_eq!(5, GoalStatus::STATUS_CANCELED as i8);
944 assert_eq!(6, GoalStatus::STATUS_ABORTED as i8);
945
946 use action_msgs::srv::CancelGoal;
947 let cgr = CancelGoal::Response::default();
948
949 assert_eq!(cgr.return_code, CancelGoal::Response::ERROR_NONE as i8);
950 assert_eq!(0, CancelGoal::Response::ERROR_NONE as i8);
951 assert_eq!(1, CancelGoal::Response::ERROR_REJECTED as i8);
952 assert_eq!(2, CancelGoal::Response::ERROR_UNKNOWN_GOAL_ID as i8);
953 assert_eq!(3, CancelGoal::Response::ERROR_GOAL_TERMINATED as i8);
954 }
955}