use darling::FromDeriveInput;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use syn::DeriveInput;
use crate::attrs::{Ros2FieldOpts, Ros2TypeOpts, parse_fields};
pub fn derive_ros2_msg_impl(input: DeriveInput) -> Result<TokenStream, syn::Error> {
let opts = Ros2TypeOpts::from_derive_input(&input)
.map_err(|e| syn::Error::new_spanned(&input, e.to_string()))?;
let field_opts = parse_fields(&input)?;
let rcl_impl = generate_rcl_impl(&opts, &field_opts);
let pure_impl = generate_pure_impl(&opts, &field_opts);
let common_impl = generate_common_impl(&opts);
let wrapper_impl = generate_wrapper_impl(&opts);
let expanded = quote! {
#common_impl
#[cfg(feature = "rcl")]
const _: () = {
#rcl_impl
};
#[cfg(not(feature = "rcl"))]
const _: () = {
#pure_impl
};
#wrapper_impl
};
Ok(expanded)
}
fn generate_serialization_ffi_decls() -> TokenStream {
quote! {
fn rcutils_get_zero_initialized_uint8_array() -> rcl_serialized_message_t;
fn rcutils_uint8_array_init(
array: *mut rcl_serialized_message_t,
size: usize,
allocator: *const std::ffi::c_void,
) -> i32;
fn rcutils_get_default_allocator() -> std::ffi::c_void;
fn rcutils_uint8_array_fini(array: *mut rcl_serialized_message_t);
fn rmw_serialize(
msg: *const std::ffi::c_void,
type_support: *const std::ffi::c_void,
serialized_msg: *mut rcl_serialized_message_t,
) -> i32;
fn rmw_deserialize(
buffer: *const u8,
buffer_size: usize,
type_support: *const std::ffi::c_void,
msg: *mut std::ffi::c_void,
bytes_read: *mut usize,
) -> i32;
}
}
fn generate_serialized_message_struct() -> TokenStream {
quote! {
#[repr(C)]
struct rcl_serialized_message_t {
buffer: *mut u8,
buffer_length: usize,
buffer_capacity: usize,
allocator: *const std::ffi::c_void,
}
}
}
fn get_default_expr_for_type(ty: &syn::Type) -> TokenStream {
if let Some((elem_ty, _)) = get_large_array_info(ty) {
return quote! { std::array::from_fn(|_| <#elem_ty as Default>::default()) };
}
quote! { Default::default() }
}
fn get_clone_expr_for_field(field_name: &syn::Ident, ty: &syn::Type) -> TokenStream {
if get_large_array_info(ty).is_some() {
return quote! { std::array::from_fn(|i| self.#field_name[i].clone()) };
}
quote! { self.#field_name.clone() }
}
fn get_large_array_info(ty: &syn::Type) -> Option<(&syn::Type, usize)> {
if let syn::Type::Array(array) = ty
&& let syn::Expr::Lit(syn::ExprLit {
lit: syn::Lit::Int(lit_int),
..
}) = &array.len
&& let Ok(size) = lit_int.base10_parse::<usize>()
&& size > 32
{
return Some((&array.elem, size));
}
None
}
fn generate_wrapper_impl(opts: &Ros2TypeOpts) -> TokenStream {
if opts.skip_wrapper {
return TokenStream::new();
}
let name = &opts.ident;
let package = &opts.package;
let interface_type = &opts.interface_type;
let name_str = name.to_string();
if interface_type == "srv"
&& let Some(service_name) = name_str.strip_suffix("_Request")
{
return generate_service_wrapper(package, service_name);
}
if interface_type == "action"
&& let Some(action_name) = name_str.strip_suffix("_Goal")
{
let uuid_path = opts.uuid_path.as_deref().or(Some("super::super::super"));
return generate_action_wrapper(package, action_name, uuid_path);
}
TokenStream::new()
}
fn generate_rcl_impl(opts: &Ros2TypeOpts, _field_opts: &[Ros2FieldOpts]) -> TokenStream {
let name = &opts.ident;
let package = &opts.package;
let interface_type = &opts.interface_type;
generate_rcl_base_impl(name, package, interface_type)
}
fn generate_common_impl(opts: &Ros2TypeOpts) -> TokenStream {
let name = &opts.ident;
let seq_raw_type = format_ident!("{}SeqRaw", name);
let seq_type = format_ident!("{}Seq", name);
quote! {
type #seq_raw_type = ros2_types::SequenceRaw<#name>;
#[repr(transparent)]
#[derive(Debug)]
pub struct #seq_type<const N: usize>(pub #seq_raw_type);
impl<const N: usize> std::ops::Deref for #seq_type<N> {
type Target = #seq_raw_type;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<const N: usize> std::ops::DerefMut for #seq_type<N> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<const N: usize> #seq_type<N> {
pub const fn null() -> Self {
Self(#seq_raw_type::null())
}
}
unsafe impl<const N: usize> Send for #seq_type<N> {}
unsafe impl<const N: usize> Sync for #seq_type<N> {}
impl<const N: usize> ros2_types::TypeDescription for #seq_type<N> {
fn type_description() -> ros2_types::types::TypeDescriptionMsg {
<#name as ros2_types::TypeDescription>::type_description()
}
fn message_type_name() -> ros2_types::MessageTypeName {
<#name as ros2_types::TypeDescription>::message_type_name()
}
}
impl<const N: usize> ros2_types::RosFieldType for #seq_type<N> {
fn ros_field_type() -> ros2_types::types::FieldType {
let nested_name = <#name as ros2_types::TypeDescription>::message_type_name();
let type_name = format!("{}/{}/{}", nested_name.package, nested_name.message_type, nested_name.type_name);
if N == 0 {
ros2_types::types::FieldType::nested_sequence(&type_name)
} else {
ros2_types::types::FieldType::nested_bounded_sequence(&type_name, N as u64)
}
}
fn referenced_types() -> Vec<ros2_types::types::IndividualTypeDescription> {
<#name as ros2_types::RosFieldType>::referenced_types()
}
}
}
}
fn generate_rcl_base_impl(name: &syn::Ident, package: &str, interface_type: &str) -> TokenStream {
let ffi_prefix = format!("{}__{}__{}", package, interface_type, name);
let init_fn = format_ident!("{}__init", ffi_prefix);
let fini_fn = format_ident!("{}__fini", ffi_prefix);
let are_equal_fn = format_ident!("{}__are_equal", ffi_prefix);
let copy_fn = format_ident!("{}__copy", ffi_prefix);
let seq_init_fn = format_ident!("{}__Sequence__init", ffi_prefix);
let seq_fini_fn = format_ident!("{}__Sequence__fini", ffi_prefix);
let seq_are_equal_fn = format_ident!("{}__Sequence__are_equal", ffi_prefix);
let seq_copy_fn = format_ident!("{}__Sequence__copy", ffi_prefix);
let type_support_fn = format_ident!(
"rosidl_typesupport_c__get_message_type_support_handle__{}__{}__{}",
package,
interface_type,
name
);
let seq_raw_type = format_ident!("{}SeqRaw", name);
let seq_type = format_ident!("{}Seq", name);
let ts_impl = generate_rcl_type_support_impl(name, package, interface_type);
let serialization_ffi = generate_serialization_ffi_decls();
let serialized_msg_struct = generate_serialized_message_struct();
quote! {
unsafe extern "C" {
fn #init_fn(msg: *mut #name) -> bool;
fn #fini_fn(msg: *mut #name);
fn #are_equal_fn(lhs: *const #name, rhs: *const #name) -> bool;
fn #copy_fn(lhs: *const #name, rhs: *mut #name) -> bool;
fn #seq_init_fn(msg: *mut #seq_raw_type, size: usize) -> bool;
fn #seq_fini_fn(msg: *mut #seq_raw_type);
fn #seq_are_equal_fn(lhs: *const #seq_raw_type, rhs: *const #seq_raw_type) -> bool;
fn #seq_copy_fn(lhs: *const #seq_raw_type, rhs: *mut #seq_raw_type) -> bool;
fn #type_support_fn() -> *const std::ffi::c_void;
#serialization_ffi
}
#serialized_msg_struct
#ts_impl
impl #name {
pub fn new() -> Option<Self> {
let mut msg = unsafe { std::mem::zeroed() };
if unsafe { #init_fn(&mut msg) } {
Some(msg)
} else {
None
}
}
}
impl Drop for #name {
fn drop(&mut self) {
unsafe { #fini_fn(self) };
}
}
impl PartialEq for #name {
fn eq(&self, other: &Self) -> bool {
unsafe { #are_equal_fn(self, other) }
}
}
impl ros2_types::TryClone for #name {
fn try_clone(&self) -> Option<Self> {
let mut result = Self::new()?;
if unsafe { #copy_fn(self, &mut result) } {
Some(result)
} else {
None
}
}
}
impl Default for #name {
fn default() -> Self {
Self::new().expect("Failed to initialize ROS2 message")
}
}
impl Clone for #name {
fn clone(&self) -> Self {
ros2_types::TryClone::try_clone(self).expect("Failed to clone ROS2 message")
}
}
impl<const N: usize> #seq_type<N> {
pub fn new(size: usize) -> Option<Self> {
if N != 0 && size > N {
return None;
}
let mut msg = #seq_raw_type::null();
if unsafe { #seq_init_fn(&mut msg, size) } {
Some(Self(msg))
} else {
None
}
}
}
impl<const N: usize> Drop for #seq_type<N> {
fn drop(&mut self) {
unsafe { #seq_fini_fn(std::ops::DerefMut::deref_mut(self)) };
}
}
impl<const N: usize> PartialEq for #seq_type<N> {
fn eq(&self, other: &Self) -> bool {
unsafe {
let msg1 = #seq_raw_type { data: self.data, size: self.size, capacity: self.capacity };
let msg2 = #seq_raw_type { data: other.data, size: other.size, capacity: other.capacity };
#seq_are_equal_fn(&msg1, &msg2)
}
}
}
impl<const N: usize> ros2_types::TryClone for #seq_type<N> {
fn try_clone(&self) -> Option<Self> {
let mut result = Self::new(self.size)?;
let msg1 = #seq_raw_type { data: self.data, size: self.size, capacity: self.capacity };
let mut msg2 = #seq_raw_type { data: result.data, size: result.size, capacity: result.capacity };
if unsafe { #seq_copy_fn(&msg1, &mut msg2) } {
result.0 = msg2;
Some(result)
} else {
None
}
}
}
impl<const N: usize> Default for #seq_type<N> {
fn default() -> Self {
Self::null()
}
}
impl<const N: usize> Clone for #seq_type<N> {
fn clone(&self) -> Self {
ros2_types::TryClone::try_clone(self).expect("Failed to clone ROS2 sequence")
}
}
}
}
fn generate_pure_impl(opts: &Ros2TypeOpts, field_opts: &[Ros2FieldOpts]) -> TokenStream {
let name = &opts.ident;
let default_fields: Vec<_> = field_opts
.iter()
.map(|f| {
let field_name = f.ident.as_ref().unwrap();
let default_expr = get_default_expr_for_type(&f.ty);
quote! { #field_name: #default_expr }
})
.collect();
let clone_fields: Vec<_> = field_opts
.iter()
.map(|f| {
let field_name = f.ident.as_ref().unwrap();
let clone_expr = get_clone_expr_for_field(field_name, &f.ty);
quote! { #field_name: #clone_expr }
})
.collect();
let eq_comparisons: Vec<_> = field_opts
.iter()
.map(|f| {
let field_name = f.ident.as_ref().unwrap();
quote! { self.#field_name == other.#field_name }
})
.collect();
let eq_body = if eq_comparisons.is_empty() {
quote! { true }
} else {
quote! { #(#eq_comparisons)&&* }
};
let seq_raw_type = format_ident!("{}SeqRaw", name);
let seq_type = format_ident!("{}Seq", name);
let ts_impl = generate_native_type_support_impl(name, &opts.package, &opts.interface_type);
quote! {
impl #name {
pub fn new() -> Option<Self> {
Some(Self::default())
}
}
#ts_impl
impl Default for #name {
fn default() -> Self {
Self {
#(#default_fields),*
}
}
}
impl Clone for #name {
fn clone(&self) -> Self {
Self {
#(#clone_fields),*
}
}
}
impl ros2_types::TryClone for #name {
fn try_clone(&self) -> Option<Self> {
Some(self.clone())
}
}
impl PartialEq for #name {
fn eq(&self, other: &Self) -> bool {
#eq_body
}
}
impl<const N: usize> #seq_type<N> {
pub fn new(size: usize) -> Option<Self>
where
#name: Default,
{
if N != 0 && size > N {
return None;
}
let vec: Vec<#name> = (0..size).map(|_| #name::default()).collect();
Some(Self(#seq_raw_type::from_vec(vec)))
}
pub fn from_vec(vec: Vec<#name>) -> Option<Self> {
if N != 0 && vec.len() > N {
return None;
}
Some(Self(#seq_raw_type::from_vec(vec)))
}
pub unsafe fn into_vec(self) -> Vec<#name> {
let inner = std::ptr::read(&self.0);
std::mem::forget(self); inner.into_vec()
}
}
impl<const N: usize> Default for #seq_type<N> {
fn default() -> Self {
Self::null()
}
}
impl<const N: usize> Clone for #seq_type<N>
where
#name: Clone,
{
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<const N: usize> ros2_types::TryClone for #seq_type<N>
where
#name: Clone,
{
fn try_clone(&self) -> Option<Self> {
Some(self.clone())
}
}
impl<const N: usize> PartialEq for #seq_type<N>
where
#name: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<const N: usize> ros2_types::serde::Serialize for #seq_type<N>
where
#name: ros2_types::serde::Serialize,
{
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: ros2_types::serde::Serializer,
{
self.0.serialize(serializer)
}
}
impl<'de, const N: usize> ros2_types::serde::Deserialize<'de> for #seq_type<N>
where
#name: ros2_types::serde::Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: ros2_types::serde::Deserializer<'de>,
{
let inner = #seq_raw_type::deserialize(deserializer)?;
if N != 0 && inner.len() > N {
return Err(ros2_types::serde::de::Error::custom(
format!("sequence length {} exceeds maximum {}", inner.len(), N)
));
}
Ok(Self(inner))
}
}
}
}
fn generate_native_type_support_impl(
name: &syn::Ident,
package: &str,
interface_type: &str,
) -> TokenStream {
let dds_type_name = format!("{}::{}::dds_::{}_", package, interface_type, name);
quote! {
impl ros2_types::TypeSupport for #name {
fn to_bytes(&self) -> ros2_types::Result<Vec<u8>> {
<Self as ros2_types::CdrSerde>::serialize(self)
}
fn from_bytes(bytes: &[u8]) -> ros2_types::Result<Self> {
<Self as ros2_types::CdrSerde>::deserialize(bytes)
}
fn type_name() -> &'static str {
#dds_type_name
}
fn type_hash() -> ros2_types::Result<::std::string::String> {
<Self as ros2_types::TypeDescription>::compute_hash()
}
}
}
}
fn generate_native_type_support_impl_no_hash(
name: &syn::Ident,
package: &str,
interface_type: &str,
) -> TokenStream {
let dds_type_name = format!("{}::{}::dds_::{}_", package, interface_type, name);
quote! {
impl ros2_types::TypeSupport for #name {
fn to_bytes(&self) -> ros2_types::Result<Vec<u8>> {
<Self as ros2_types::CdrSerde>::serialize(self)
}
fn from_bytes(bytes: &[u8]) -> ros2_types::Result<Self> {
<Self as ros2_types::CdrSerde>::deserialize(bytes)
}
fn type_name() -> &'static str {
#dds_type_name
}
}
}
}
fn generate_rcl_type_support_impl(
name: &syn::Ident,
package: &str,
interface_type: &str,
) -> TokenStream {
let dds_type_name = format!("{}::{}::dds_::{}_", package, interface_type, name);
let type_support_fn = format_ident!(
"rosidl_typesupport_c__get_message_type_support_handle__{}__{}__{}",
package,
interface_type,
name
);
let dds_lit = syn::LitStr::new(&dds_type_name, proc_macro2::Span::call_site());
quote! {
impl ros2_types::TypeSupport for #name {
fn type_support() -> *const std::ffi::c_void {
unsafe { #type_support_fn() }
}
fn to_bytes(&self) -> ros2_types::Result<Vec<u8>> {
let ts = Self::type_support();
let mut msg_buf: rcl_serialized_message_t = unsafe { rcutils_get_zero_initialized_uint8_array() };
let ret_init = unsafe {
rcutils_uint8_array_init(
&mut msg_buf as *mut rcl_serialized_message_t,
0,
&rcutils_get_default_allocator() as *const _,
)
};
if ret_init != 0 {
return Err(ros2_types::Error::CdrError("rcutils_uint8_array_init failed".to_string()));
}
let ret = unsafe {
rmw_serialize(
self as *const _ as *const std::ffi::c_void,
ts,
&mut msg_buf as *mut rcl_serialized_message_t,
)
};
let result = if ret == 0 {
let slice = unsafe { std::slice::from_raw_parts(msg_buf.buffer, msg_buf.buffer_length) };
Ok(slice.to_vec())
} else {
Err(ros2_types::Error::CdrError("rmw_serialize failed".to_string()))
};
unsafe { rcutils_uint8_array_fini(&mut msg_buf as *mut rcl_serialized_message_t) };
result
}
fn from_bytes(bytes: &[u8]) -> ros2_types::Result<Self> {
let ts = Self::type_support();
let mut msg = unsafe { std::mem::zeroed() };
let mut read = 0usize;
let ret = unsafe {
rmw_deserialize(
bytes.as_ptr(),
bytes.len(),
ts,
&mut msg as *mut _ as *mut std::ffi::c_void,
&mut read as *mut usize,
)
};
if ret == 0 {
Ok(msg)
} else {
Err(ros2_types::Error::CdrError("rmw_deserialize failed".to_string()))
}
}
fn type_name() -> &'static str {
#dds_lit
}
}
}
}
pub fn generate_service_wrapper(package: &str, service_name: &str) -> TokenStream {
let service_ident = format_ident!("{}", service_name);
let request_ident = format_ident!("{}_Request", service_name);
let response_ident = format_ident!("{}_Response", service_name);
let type_support_fn = format_ident!(
"rosidl_typesupport_c__get_service_type_support_handle__{}__srv__{}",
package,
service_name
);
let service_doc = format!("Service wrapper for {}", service_name);
let dds_type_name = format!("{}::srv::dds_::{}_", package, service_name);
quote! {
#[doc = #service_doc]
#[derive(Debug, ros2_types::ServiceTypeDescription)]
#[ros2(package = #package)]
pub struct #service_ident;
#[cfg(feature = "rcl")]
unsafe extern "C" {
fn #type_support_fn() -> *const std::ffi::c_void;
}
impl ros2_types::ServiceMsg for #service_ident {
type Request = #request_ident;
type Response = #response_ident;
#[cfg(feature = "rcl")]
fn type_support() -> *const std::ffi::c_void {
unsafe { #type_support_fn() }
}
#[cfg(not(feature = "rcl"))]
fn type_hash() -> ros2_types::Result<::std::string::String> {
<Self as ros2_types::ServiceTypeDescription>::compute_hash()
}
fn type_name() -> &'static str {
#dds_type_name
}
}
}
}
pub fn generate_action_wrapper(
package: &str,
action_name: &str,
uuid_path_prefix: Option<&str>,
) -> TokenStream {
let dds_type_name = format!("{}::action::dds_::{}_", package, action_name);
let action_ident = format_ident!("{}", action_name);
let goal_ident = format_ident!("{}_Goal", action_name);
let result_ident = format_ident!("{}_Result", action_name);
let feedback_ident = format_ident!("{}_Feedback", action_name);
let send_goal_ident = format_ident!("{}_SendGoal", action_name);
let send_goal_request_ident = format_ident!("{}_SendGoal_Request", action_name);
let send_goal_response_ident = format_ident!("{}_SendGoal_Response", action_name);
let get_result_ident = format_ident!("{}_GetResult", action_name);
let get_result_request_ident = format_ident!("{}_GetResult_Request", action_name);
let get_result_response_ident = format_ident!("{}_GetResult_Response", action_name);
let feedback_message_ident = format_ident!("{}_FeedbackMessage", action_name);
let action_type_support_fn = format_ident!(
"rosidl_typesupport_c__get_action_type_support_handle__{}__action__{}",
package,
action_name
);
let send_goal_type_support_fn = format_ident!(
"rosidl_typesupport_c__get_service_type_support_handle__{}__action__{}_SendGoal",
package,
action_name
);
let get_result_type_support_fn = format_ident!(
"rosidl_typesupport_c__get_service_type_support_handle__{}__action__{}_GetResult",
package,
action_name
);
let send_goal_request_type_support_fn = format_ident!(
"rosidl_typesupport_c__get_message_type_support_handle__{}__action__{}_SendGoal_Request",
package,
action_name
);
let send_goal_response_type_support_fn = format_ident!(
"rosidl_typesupport_c__get_message_type_support_handle__{}__action__{}_SendGoal_Response",
package,
action_name
);
let get_result_request_type_support_fn = format_ident!(
"rosidl_typesupport_c__get_message_type_support_handle__{}__action__{}_GetResult_Request",
package,
action_name
);
let get_result_response_type_support_fn = format_ident!(
"rosidl_typesupport_c__get_message_type_support_handle__{}__action__{}_GetResult_Response",
package,
action_name
);
let feedback_message_type_support_fn = format_ident!(
"rosidl_typesupport_c__get_message_type_support_handle__{}__action__{}_FeedbackMessage",
package,
action_name
);
let uuid_type: syn::Type = if let Some(prefix) = uuid_path_prefix {
syn::parse_str(&format!("{}::unique_identifier_msgs::msg::UUID", prefix))
.unwrap_or_else(|_| syn::parse_str("unique_identifier_msgs::msg::UUID").unwrap())
} else {
syn::parse_str("unique_identifier_msgs::msg::UUID").unwrap()
};
let action_doc = format!("Action wrapper for {}", action_name);
let ts_send_goal_req_impl_rcl =
generate_rcl_type_support_impl(&send_goal_request_ident, package, "action");
let ts_send_goal_resp_impl_rcl =
generate_rcl_type_support_impl(&send_goal_response_ident, package, "action");
let ts_get_result_req_impl_rcl =
generate_rcl_type_support_impl(&get_result_request_ident, package, "action");
let ts_get_result_resp_impl_rcl =
generate_rcl_type_support_impl(&get_result_response_ident, package, "action");
let ts_feedback_message_impl_rcl =
generate_rcl_type_support_impl(&feedback_message_ident, package, "action");
let ts_send_goal_req_impl_native =
generate_native_type_support_impl_no_hash(&send_goal_request_ident, package, "action");
let ts_send_goal_resp_impl_native =
generate_native_type_support_impl_no_hash(&send_goal_response_ident, package, "action");
let ts_get_result_req_impl_native =
generate_native_type_support_impl_no_hash(&get_result_request_ident, package, "action");
let ts_get_result_resp_impl_native =
generate_native_type_support_impl_no_hash(&get_result_response_ident, package, "action");
let ts_feedback_message_impl_native =
generate_native_type_support_impl_no_hash(&feedback_message_ident, package, "action");
let serialization_ffi = generate_serialization_ffi_decls();
let serialized_msg_struct = generate_serialized_message_struct();
quote! {
#[cfg(feature = "rcl")]
unsafe extern "C" {
fn #action_type_support_fn() -> *const std::ffi::c_void;
fn #send_goal_type_support_fn() -> *const std::ffi::c_void;
fn #get_result_type_support_fn() -> *const std::ffi::c_void;
fn #send_goal_request_type_support_fn() -> *const std::ffi::c_void;
fn #send_goal_response_type_support_fn() -> *const std::ffi::c_void;
fn #get_result_request_type_support_fn() -> *const std::ffi::c_void;
fn #get_result_response_type_support_fn() -> *const std::ffi::c_void;
fn #feedback_message_type_support_fn() -> *const std::ffi::c_void;
#serialization_ffi
}
#serialized_msg_struct
#[repr(C)]
#[derive(Debug)]
#[cfg_attr(not(feature = "rcl"), derive(ros2_types::serde::Serialize, ros2_types::serde::Deserialize))]
#[cfg_attr(not(feature = "rcl"), serde(crate = "ros2_types::serde"))]
pub struct #send_goal_request_ident {
pub goal_id: #uuid_type,
pub goal: #goal_ident,
}
#[repr(C)]
#[derive(Debug)]
#[cfg_attr(not(feature = "rcl"), derive(ros2_types::serde::Serialize, ros2_types::serde::Deserialize))]
#[cfg_attr(not(feature = "rcl"), serde(crate = "ros2_types::serde"))]
pub struct #send_goal_response_ident {
pub accepted: bool,
pub stamp: ros2_types::UnsafeTime,
}
#[derive(Debug)]
pub struct #send_goal_ident;
impl ros2_types::ActionGoal for #send_goal_ident {
type Request = #send_goal_request_ident;
type Response = #send_goal_response_ident;
#[cfg(feature = "rcl")]
fn type_support() -> *const std::ffi::c_void {
unsafe { #send_goal_type_support_fn() }
}
}
impl ros2_types::GetUUID for #send_goal_request_ident {
fn get_uuid(&self) -> &[u8; 16] {
&self.goal_id.uuid
}
}
#[cfg(feature = "rcl")]
#ts_send_goal_req_impl_rcl
#[cfg(not(feature = "rcl"))]
#ts_send_goal_req_impl_native
impl ros2_types::GoalResponse for #send_goal_response_ident {
fn is_accepted(&self) -> bool {
self.accepted
}
fn get_time_stamp(&self) -> ros2_types::UnsafeTime {
ros2_types::UnsafeTime {
sec: self.stamp.sec,
nanosec: self.stamp.nanosec,
}
}
fn new(accepted: bool, stamp: ros2_types::UnsafeTime) -> Self {
Self { accepted, stamp }
}
}
#[cfg(feature = "rcl")]
#ts_send_goal_resp_impl_rcl
#[cfg(not(feature = "rcl"))]
#ts_send_goal_resp_impl_native
#[repr(C)]
#[derive(Debug)]
#[cfg_attr(not(feature = "rcl"), derive(ros2_types::serde::Serialize, ros2_types::serde::Deserialize))]
#[cfg_attr(not(feature = "rcl"), serde(crate = "ros2_types::serde"))]
pub struct #get_result_request_ident {
pub goal_id: #uuid_type,
}
#[repr(C)]
#[derive(Debug)]
#[cfg_attr(not(feature = "rcl"), derive(ros2_types::serde::Serialize, ros2_types::serde::Deserialize))]
#[cfg_attr(not(feature = "rcl"), serde(crate = "ros2_types::serde"))]
pub struct #get_result_response_ident {
pub status: u8,
pub result: #result_ident,
}
#[derive(Debug)]
pub struct #get_result_ident;
impl ros2_types::ActionResult for #get_result_ident {
type Request = #get_result_request_ident;
type Response = #get_result_response_ident;
#[cfg(feature = "rcl")]
fn type_support() -> *const std::ffi::c_void {
unsafe { #get_result_type_support_fn() }
}
}
impl ros2_types::GetUUID for #get_result_request_ident {
fn get_uuid(&self) -> &[u8; 16] {
&self.goal_id.uuid
}
}
#[cfg(feature = "rcl")]
#ts_get_result_req_impl_rcl
#[cfg(not(feature = "rcl"))]
#ts_get_result_req_impl_native
impl ros2_types::ResultResponse for #get_result_response_ident {
fn get_status(&self) -> u8 {
self.status
}
}
#[cfg(feature = "rcl")]
#ts_get_result_resp_impl_rcl
#[cfg(not(feature = "rcl"))]
#ts_get_result_resp_impl_native
#[repr(C)]
#[derive(Debug)]
#[cfg_attr(not(feature = "rcl"), derive(ros2_types::serde::Serialize, ros2_types::serde::Deserialize))]
#[cfg_attr(not(feature = "rcl"), serde(crate = "ros2_types::serde"))]
pub struct #feedback_message_ident {
pub goal_id: #uuid_type,
pub feedback: #feedback_ident,
}
impl ros2_types::GetUUID for #feedback_message_ident {
fn get_uuid(&self) -> &[u8; 16] {
&self.goal_id.uuid
}
}
#[cfg(feature = "rcl")]
#ts_feedback_message_impl_rcl
#[cfg(not(feature = "rcl"))]
#ts_feedback_message_impl_native
#[doc = #action_doc]
#[derive(Debug, ros2_types::ActionTypeDescription)]
#[ros2(package = #package)]
pub struct #action_ident;
impl ros2_types::ActionMsg for #action_ident {
type Goal = #send_goal_ident;
type Result = #get_result_ident;
type Feedback = #feedback_message_ident;
fn type_name() -> &'static str {
#dds_type_name
}
#[cfg(feature = "rcl")]
fn type_support() -> *const std::ffi::c_void {
unsafe { #action_type_support_fn() }
}
type GoalContent = #goal_ident;
fn new_goal_request(
goal: Self::GoalContent,
uuid: [u8; 16],
) -> <Self::Goal as ros2_types::ActionGoal>::Request {
#send_goal_request_ident {
goal,
goal_id: #uuid_type { uuid },
}
}
type ResultContent = #result_ident;
fn new_result_response(
status: u8,
result: Self::ResultContent,
) -> <Self::Result as ros2_types::ActionResult>::Response {
#get_result_response_ident { status, result }
}
type FeedbackContent = #feedback_ident;
fn new_feedback_message(
feedback: Self::FeedbackContent,
uuid: [u8; 16],
) -> Self::Feedback {
#feedback_message_ident {
feedback,
goal_id: #uuid_type { uuid },
}
}
#[cfg(not(feature = "rcl"))]
fn type_hash() -> ros2_types::Result<::std::string::String> {
<Self as ros2_types::ActionTypeDescription>::compute_hash()
}
}
}
}