diff --git a/rosidl_generator_rs/cmake/rosidl_generator_rs_generate_interfaces.cmake b/rosidl_generator_rs/cmake/rosidl_generator_rs_generate_interfaces.cmake index af42061..de2fe2f 100644 --- a/rosidl_generator_rs/cmake/rosidl_generator_rs_generate_interfaces.cmake +++ b/rosidl_generator_rs/cmake/rosidl_generator_rs_generate_interfaces.cmake @@ -60,18 +60,21 @@ list(APPEND _generated_common_rs_files if(${_has_msg}) list(APPEND _generated_msg_rs_files "${_output_path}/rust/src/msg.rs" + "${_output_path}/rust/src/msg/rmw.rs" ) endif() if(${_has_srv}) list(APPEND _generated_srv_rs_files "${_output_path}/rust/src/srv.rs" + "${_output_path}/rust/src/srv/rmw.rs" ) endif() if(${_has_action}) list(APPEND _generated_action_rs_files "${_output_path}/rust/src/action.rs" + "${_output_path}/rust/src/action/rmw.rs" ) endif() @@ -90,12 +93,15 @@ set(target_dependencies "${rosidl_generator_rs_BIN}" ${rosidl_generator_rs_GENERATOR_FILES} "${rosidl_generator_rs_TEMPLATE_DIR}/action.rs.em" - "${rosidl_generator_rs_TEMPLATE_DIR}/msg_idiomatic.rs.em" - "${rosidl_generator_rs_TEMPLATE_DIR}/msg_rmw.rs.em" + "${rosidl_generator_rs_TEMPLATE_DIR}/action/rmw.rs.em" "${rosidl_generator_rs_TEMPLATE_DIR}/msg.rs.em" - "${rosidl_generator_rs_TEMPLATE_DIR}/srv_idiomatic.rs.em" - "${rosidl_generator_rs_TEMPLATE_DIR}/srv_rmw.rs.em" + "${rosidl_generator_rs_TEMPLATE_DIR}/msg/rmw.rs.em" "${rosidl_generator_rs_TEMPLATE_DIR}/srv.rs.em" + "${rosidl_generator_rs_TEMPLATE_DIR}/srv/rmw.rs.em" + "${rosidl_generator_rs_TEMPLATE_DIR}/templates/msg_idiomatic.rs.em" + "${rosidl_generator_rs_TEMPLATE_DIR}/templates/msg_rmw.rs.em" + "${rosidl_generator_rs_TEMPLATE_DIR}/templates/srv_idiomatic.rs.em" + "${rosidl_generator_rs_TEMPLATE_DIR}/templates/srv_rmw.rs.em" ${rosidl_generate_interfaces_ABS_IDL_FILES} ${_idl_files} ${_dependency_files}) diff --git a/rosidl_generator_rs/resource/Cargo.toml.em b/rosidl_generator_rs/resource/Cargo.toml.em index 572562c..9eb6ca9 100644 --- a/rosidl_generator_rs/resource/Cargo.toml.em +++ b/rosidl_generator_rs/resource/Cargo.toml.em @@ -7,6 +7,8 @@ edition = "2021" rosidl_runtime_rs = "0.5" serde = { version = "1", optional = true, features = ["derive"] } serde-big-array = { version = "0.5.1", optional = true } + +# ROS Dependencies @[for dep in dependency_packages]@ @(dep) = "*" @[end for]@ @@ -18,3 +20,6 @@ for dep in dependency_packages: serde_features.append("{}/serde".format(dep)) }@ serde = @(serde_features) + +[package.metadata.rclrs] +reexport = true diff --git a/rosidl_generator_rs/resource/action.rs.em b/rosidl_generator_rs/resource/action.rs.em index 91ec4af..e042e7d 100644 --- a/rosidl_generator_rs/resource/action.rs.em +++ b/rosidl_generator_rs/resource/action.rs.em @@ -25,52 +25,28 @@ for subfolder, action in action_specs: action_srv_specs.append((subfolder, action.get_result_service)) }@ -pub mod rmw { - #[cfg(feature = "serde")] - use serde::{Deserialize, Serialize}; -@{ -TEMPLATE( - 'msg_rmw.rs.em', - package_name=package_name, interface_path=interface_path, - msg_specs=action_msg_specs, - get_rs_name=get_rs_name, get_rmw_rs_type=get_rmw_rs_type, - pre_field_serde=pre_field_serde, - get_idiomatic_rs_type=get_idiomatic_rs_type, - constant_value_to_rs=constant_value_to_rs) - -TEMPLATE( - 'srv_rmw.rs.em', - package_name=package_name, interface_path=interface_path, - srv_specs=action_srv_specs, - get_rs_name=get_rs_name, get_rmw_rs_type=get_rmw_rs_type, - pre_field_serde=pre_field_serde, - get_idiomatic_rs_type=get_idiomatic_rs_type, - constant_value_to_rs=constant_value_to_rs) -}@ -} // mod rmw - #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @{ TEMPLATE( - 'msg_idiomatic.rs.em', + 'templates/msg_idiomatic.rs.em', package_name=package_name, interface_path=interface_path, msg_specs=action_msg_specs, - get_rs_name=get_rs_name, get_rmw_rs_type=get_rmw_rs_type, + get_rs_name=get_rs_name, + get_rs_type=make_get_rs_type(True), pre_field_serde=pre_field_serde, - get_idiomatic_rs_type=get_idiomatic_rs_type, constant_value_to_rs=constant_value_to_rs) }@ @{ TEMPLATE( - 'srv_idiomatic.rs.em', + 'templates/srv_idiomatic.rs.em', package_name=package_name, interface_path=interface_path, srv_specs=action_srv_specs, - get_rs_name=get_rs_name, get_rmw_rs_type=get_rmw_rs_type, + get_rs_name=get_rs_name, + get_rs_type=make_get_rs_type(True), pre_field_serde=pre_field_serde, - get_idiomatic_rs_type=get_idiomatic_rs_type, constant_value_to_rs=constant_value_to_rs) }@ @@ -90,15 +66,15 @@ pub struct @(type_name); impl rosidl_runtime_rs::Action for @(type_name) { // --- Associated types for client library users --- - type Goal = crate::@(subfolder)::@(type_name)@(ACTION_GOAL_SUFFIX); - type Result = crate::@(subfolder)::@(type_name)@(ACTION_RESULT_SUFFIX); - type Feedback = crate::@(subfolder)::@(type_name)@(ACTION_FEEDBACK_SUFFIX); + type Goal = @(type_name)@(ACTION_GOAL_SUFFIX); + type Result = @(type_name)@(ACTION_RESULT_SUFFIX); + type Feedback = @(type_name)@(ACTION_FEEDBACK_SUFFIX); // --- Associated types for client library implementation --- - type FeedbackMessage = crate::@(subfolder)::rmw::@(type_name)@(ACTION_FEEDBACK_MESSAGE_SUFFIX); - type SendGoalService = crate::@(subfolder)::rmw::@(type_name)@(ACTION_GOAL_SERVICE_SUFFIX); + type FeedbackMessage = super::@(subfolder)::@(type_name)@(ACTION_FEEDBACK_MESSAGE_SUFFIX); + type SendGoalService = super::@(subfolder)::@(type_name)@(ACTION_GOAL_SERVICE_SUFFIX); type CancelGoalService = action_msgs::srv::rmw::CancelGoal; - type GetResultService = crate::@(subfolder)::rmw::@(type_name)@(ACTION_RESULT_SERVICE_SUFFIX); + type GetResultService = super::@(subfolder)::@(type_name)@(ACTION_RESULT_SERVICE_SUFFIX); // --- Methods for client library implementation --- fn get_type_support() -> *const std::ffi::c_void { @@ -108,19 +84,19 @@ impl rosidl_runtime_rs::Action for @(type_name) { fn create_goal_request( goal_id: &[u8; 16], - goal: crate::@(subfolder)::rmw::@(type_name)@(ACTION_GOAL_SUFFIX), - ) -> crate::@(subfolder)::rmw::@(type_name)@(ACTION_GOAL_SERVICE_SUFFIX)@(SERVICE_REQUEST_MESSAGE_SUFFIX) { - crate::@(subfolder)::rmw::@(type_name)@(ACTION_GOAL_SERVICE_SUFFIX)@(SERVICE_REQUEST_MESSAGE_SUFFIX) { + goal: super::@(subfolder)::rmw::@(type_name)@(ACTION_GOAL_SUFFIX), + ) -> super::@(subfolder)::rmw::@(type_name)@(ACTION_GOAL_SERVICE_SUFFIX)@(SERVICE_REQUEST_MESSAGE_SUFFIX) { + super::@(subfolder)::rmw::@(type_name)@(ACTION_GOAL_SERVICE_SUFFIX)@(SERVICE_REQUEST_MESSAGE_SUFFIX) { goal_id: unique_identifier_msgs::msg::rmw::UUID { uuid: *goal_id }, goal, } } fn split_goal_request( - request: crate::@(subfolder)::rmw::@(type_name)@(ACTION_GOAL_SERVICE_SUFFIX)@(SERVICE_REQUEST_MESSAGE_SUFFIX), + request: super::@(subfolder)::rmw::@(type_name)@(ACTION_GOAL_SERVICE_SUFFIX)@(SERVICE_REQUEST_MESSAGE_SUFFIX), ) -> ( [u8; 16], - crate::@(subfolder)::rmw::@(type_name)@(ACTION_GOAL_SUFFIX), + super::@(subfolder)::rmw::@(type_name)@(ACTION_GOAL_SUFFIX), ) { (request.goal_id.uuid, request.goal) } @@ -128,8 +104,8 @@ impl rosidl_runtime_rs::Action for @(type_name) { fn create_goal_response( accepted: bool, stamp: (i32, u32), - ) -> crate::@(subfolder)::rmw::@(type_name)@(ACTION_GOAL_SERVICE_SUFFIX)@(SERVICE_RESPONSE_MESSAGE_SUFFIX) { - crate::@(subfolder)::rmw::@(type_name)@(ACTION_GOAL_SERVICE_SUFFIX)@(SERVICE_RESPONSE_MESSAGE_SUFFIX) { + ) -> super::@(subfolder)::rmw::@(type_name)@(ACTION_GOAL_SERVICE_SUFFIX)@(SERVICE_RESPONSE_MESSAGE_SUFFIX) { + super::@(subfolder)::rmw::@(type_name)@(ACTION_GOAL_SERVICE_SUFFIX)@(SERVICE_RESPONSE_MESSAGE_SUFFIX) { accepted, stamp: builtin_interfaces::msg::rmw::Time { sec: stamp.0, @@ -139,65 +115,65 @@ impl rosidl_runtime_rs::Action for @(type_name) { } fn get_goal_response_accepted( - response: &crate::@(subfolder)::rmw::@(type_name)@(ACTION_GOAL_SERVICE_SUFFIX)@(SERVICE_RESPONSE_MESSAGE_SUFFIX), + response: &super::@(subfolder)::rmw::@(type_name)@(ACTION_GOAL_SERVICE_SUFFIX)@(SERVICE_RESPONSE_MESSAGE_SUFFIX), ) -> bool { response.accepted } fn get_goal_response_stamp( - response: &crate::@(subfolder)::rmw::@(type_name)@(ACTION_GOAL_SERVICE_SUFFIX)@(SERVICE_RESPONSE_MESSAGE_SUFFIX), + response: &super::@(subfolder)::rmw::@(type_name)@(ACTION_GOAL_SERVICE_SUFFIX)@(SERVICE_RESPONSE_MESSAGE_SUFFIX), ) -> (i32, u32) { (response.stamp.sec, response.stamp.nanosec) } fn create_feedback_message( goal_id: &[u8; 16], - feedback: crate::@(subfolder)::rmw::@(type_name)@(ACTION_FEEDBACK_SUFFIX), - ) -> crate::@(subfolder)::rmw::@(type_name)@(ACTION_FEEDBACK_MESSAGE_SUFFIX) { - let mut message = crate::@(subfolder)::rmw::@(type_name)@(ACTION_FEEDBACK_MESSAGE_SUFFIX)::default(); + feedback: super::@(subfolder)::rmw::@(type_name)@(ACTION_FEEDBACK_SUFFIX), + ) -> super::@(subfolder)::rmw::@(type_name)@(ACTION_FEEDBACK_MESSAGE_SUFFIX) { + let mut message = super::@(subfolder)::rmw::@(type_name)@(ACTION_FEEDBACK_MESSAGE_SUFFIX)::default(); message.goal_id.uuid = *goal_id; message.feedback = feedback; message } fn split_feedback_message( - feedback: crate::@(subfolder)::rmw::@(type_name)@(ACTION_FEEDBACK_MESSAGE_SUFFIX), + feedback: super::@(subfolder)::rmw::@(type_name)@(ACTION_FEEDBACK_MESSAGE_SUFFIX), ) -> ( [u8; 16], - crate::@(subfolder)::rmw::@(type_name)@(ACTION_FEEDBACK_SUFFIX), + super::@(subfolder)::rmw::@(type_name)@(ACTION_FEEDBACK_SUFFIX), ) { (feedback.goal_id.uuid, feedback.feedback) } fn create_result_request( goal_id: &[u8; 16], - ) -> crate::@(subfolder)::rmw::@(type_name)@(ACTION_RESULT_SERVICE_SUFFIX)@(SERVICE_REQUEST_MESSAGE_SUFFIX) { - crate::@(subfolder)::rmw::@(type_name)@(ACTION_RESULT_SERVICE_SUFFIX)@(SERVICE_REQUEST_MESSAGE_SUFFIX) { + ) -> super::@(subfolder)::rmw::@(type_name)@(ACTION_RESULT_SERVICE_SUFFIX)@(SERVICE_REQUEST_MESSAGE_SUFFIX) { + super::@(subfolder)::rmw::@(type_name)@(ACTION_RESULT_SERVICE_SUFFIX)@(SERVICE_REQUEST_MESSAGE_SUFFIX) { goal_id: unique_identifier_msgs::msg::rmw::UUID { uuid: *goal_id }, } } fn get_result_request_uuid( - request: &crate::@(subfolder)::rmw::@(type_name)@(ACTION_RESULT_SERVICE_SUFFIX)@(SERVICE_REQUEST_MESSAGE_SUFFIX), + request: &super::@(subfolder)::rmw::@(type_name)@(ACTION_RESULT_SERVICE_SUFFIX)@(SERVICE_REQUEST_MESSAGE_SUFFIX), ) -> &[u8; 16] { &request.goal_id.uuid } fn create_result_response( status: i8, - result: crate::@(subfolder)::rmw::@(type_name)@(ACTION_RESULT_SUFFIX), - ) -> crate::@(subfolder)::rmw::@(type_name)@(ACTION_RESULT_SERVICE_SUFFIX)@(SERVICE_RESPONSE_MESSAGE_SUFFIX) { - crate::@(subfolder)::rmw::@(type_name)@(ACTION_RESULT_SERVICE_SUFFIX)@(SERVICE_RESPONSE_MESSAGE_SUFFIX) { + result: super::@(subfolder)::rmw::@(type_name)@(ACTION_RESULT_SUFFIX), + ) -> super::@(subfolder)::rmw::@(type_name)@(ACTION_RESULT_SERVICE_SUFFIX)@(SERVICE_RESPONSE_MESSAGE_SUFFIX) { + super::@(subfolder)::rmw::@(type_name)@(ACTION_RESULT_SERVICE_SUFFIX)@(SERVICE_RESPONSE_MESSAGE_SUFFIX) { status, result, } } fn split_result_response( - response: crate::@(subfolder)::rmw::@(type_name)@(ACTION_RESULT_SERVICE_SUFFIX)@(SERVICE_RESPONSE_MESSAGE_SUFFIX) + response: super::@(subfolder)::rmw::@(type_name)@(ACTION_RESULT_SERVICE_SUFFIX)@(SERVICE_RESPONSE_MESSAGE_SUFFIX) ) -> ( i8, - crate::@(subfolder)::rmw::@(type_name)@(ACTION_RESULT_SUFFIX), + super::@(subfolder)::rmw::@(type_name)@(ACTION_RESULT_SUFFIX), ) { (response.status, response.result) } diff --git a/rosidl_generator_rs/resource/action/rmw.rs.em b/rosidl_generator_rs/resource/action/rmw.rs.em new file mode 100644 index 0000000..6da6c87 --- /dev/null +++ b/rosidl_generator_rs/resource/action/rmw.rs.em @@ -0,0 +1,49 @@ +@{ +from rosidl_parser.definition import ( +ACTION_FEEDBACK_MESSAGE_SUFFIX, +ACTION_FEEDBACK_SUFFIX, +ACTION_GOAL_SERVICE_SUFFIX, +ACTION_GOAL_SUFFIX, +ACTION_RESULT_SERVICE_SUFFIX, +ACTION_RESULT_SUFFIX, +SERVICE_REQUEST_MESSAGE_SUFFIX, +SERVICE_RESPONSE_MESSAGE_SUFFIX, +) + +action_msg_specs = [] + +for subfolder, action in action_specs: + action_msg_specs.append((subfolder, action.goal)) + action_msg_specs.append((subfolder, action.result)) + action_msg_specs.append((subfolder, action.feedback)) + action_msg_specs.append((subfolder, action.feedback_message)) + +action_srv_specs = [] + +for subfolder, action in action_specs: + action_srv_specs.append((subfolder, action.send_goal_service)) + action_srv_specs.append((subfolder, action.get_result_service)) +}@ + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +@{ +TEMPLATE( + '../templates/msg_rmw.rs.em', + package_name=package_name, interface_path=interface_path, + msg_specs=action_msg_specs, + get_rs_name=get_rs_name, + get_rs_type=make_get_rs_type(False), + pre_field_serde=pre_field_serde, + constant_value_to_rs=constant_value_to_rs) + +TEMPLATE( + '../templates/srv_rmw.rs.em', + package_name=package_name, interface_path=interface_path, + srv_specs=action_srv_specs, + get_rs_name=get_rs_name, + get_rs_type=make_get_rs_type(False), + pre_field_serde=pre_field_serde, + constant_value_to_rs=constant_value_to_rs) +}@ diff --git a/rosidl_generator_rs/resource/build.rs.em b/rosidl_generator_rs/resource/build.rs.em index d861d0e..be2bf00 100644 --- a/rosidl_generator_rs/resource/build.rs.em +++ b/rosidl_generator_rs/resource/build.rs.em @@ -1,10 +1,10 @@ -use std::path::Path; +// use std::path::Path; fn main() { - let lib_dir = Path::new("../../../lib") - .canonicalize() - .expect("Could not find '../../../lib'"); - // This allows building Rust packages that depend on message crates without - // sourcing the install directory first. - println!("cargo:rustc-link-search={}", lib_dir.display()); + // let lib_dir = Path::new("../../../lib") + // .canonicalize() + // .expect("Could not find '../../../lib'"); + // // This allows building Rust packages that depend on message crates without + // // sourcing the install directory first. + // println!("cargo:rustc-link-search={}", lib_dir.display()); } diff --git a/rosidl_generator_rs/resource/lib.rs.em b/rosidl_generator_rs/resource/lib.rs.em index 1ef7792..e138c55 100644 --- a/rosidl_generator_rs/resource/lib.rs.em +++ b/rosidl_generator_rs/resource/lib.rs.em @@ -3,13 +3,28 @@ #![allow(clippy::upper_case_acronyms)] @[if len(msg_specs) > 0]@ -pub mod msg; +#[path = "msg.rs"] +mod msg_idiomatic; +pub mod msg { + pub use super::msg_idiomatic::*; + pub mod rmw; +} @[end if]@ @[if len(srv_specs) > 0]@ -pub mod srv; +#[path = "srv.rs"] +mod srv_idiomatic; +pub mod srv { + pub use super::srv_idiomatic::*; + pub mod rmw; +} @[end if]@ @[if len(action_specs) > 0]@ -pub mod action; +#[path = "action.rs"] +mod action_idiomatic; +pub mod action { + pub use super::action_idiomatic::*; + pub mod rmw; +} @[end if]@ diff --git a/rosidl_generator_rs/resource/msg.rs.em b/rosidl_generator_rs/resource/msg.rs.em index 3cd19c3..e26d9cd 100644 --- a/rosidl_generator_rs/resource/msg.rs.em +++ b/rosidl_generator_rs/resource/msg.rs.em @@ -1,28 +1,13 @@ -pub mod rmw { - #[cfg(feature = "serde")] - use serde::{Deserialize, Serialize}; -@{ -TEMPLATE( - 'msg_rmw.rs.em', - package_name=package_name, interface_path=interface_path, - msg_specs=msg_specs, - get_rs_name=get_rs_name, get_rmw_rs_type=get_rmw_rs_type, - pre_field_serde=pre_field_serde, - get_idiomatic_rs_type=get_idiomatic_rs_type, - constant_value_to_rs=constant_value_to_rs) -}@ -} // mod rmw - #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @{ TEMPLATE( - 'msg_idiomatic.rs.em', + 'templates/msg_idiomatic.rs.em', package_name=package_name, interface_path=interface_path, msg_specs=msg_specs, - get_rs_name=get_rs_name, get_rmw_rs_type=get_rmw_rs_type, + get_rs_name=get_rs_name, + get_rs_type=make_get_rs_type(True), pre_field_serde=pre_field_serde, - get_idiomatic_rs_type=get_idiomatic_rs_type, constant_value_to_rs=constant_value_to_rs) }@ diff --git a/rosidl_generator_rs/resource/msg/rmw.rs.em b/rosidl_generator_rs/resource/msg/rmw.rs.em new file mode 100644 index 0000000..b9fb29f --- /dev/null +++ b/rosidl_generator_rs/resource/msg/rmw.rs.em @@ -0,0 +1,13 @@ +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +@{ +TEMPLATE( + '../templates/msg_rmw.rs.em', + package_name=package_name, interface_path=interface_path, + msg_specs=msg_specs, + get_rs_name=get_rs_name, + get_rs_type=make_get_rs_type(False), + pre_field_serde=pre_field_serde, + constant_value_to_rs=constant_value_to_rs) +}@ \ No newline at end of file diff --git a/rosidl_generator_rs/resource/srv.rs.em b/rosidl_generator_rs/resource/srv.rs.em index 8484739..7d59145 100644 --- a/rosidl_generator_rs/resource/srv.rs.em +++ b/rosidl_generator_rs/resource/srv.rs.em @@ -3,26 +3,11 @@ use serde::{Deserialize, Serialize}; @{ TEMPLATE( - 'srv_idiomatic.rs.em', + 'templates/srv_idiomatic.rs.em', package_name=package_name, interface_path=interface_path, srv_specs=srv_specs, - get_rs_name=get_rs_name, get_rmw_rs_type=get_rmw_rs_type, + get_rs_name=get_rs_name, + get_rs_type=make_get_rs_type(True), pre_field_serde=pre_field_serde, - get_idiomatic_rs_type=get_idiomatic_rs_type, - constant_value_to_rs=constant_value_to_rs) -} - -pub mod rmw { - #[cfg(feature = "serde")] - use serde::{Deserialize, Serialize}; -@{ -TEMPLATE( - 'srv_rmw.rs.em', - package_name=package_name, interface_path=interface_path, - srv_specs=srv_specs, - get_rs_name=get_rs_name, get_rmw_rs_type=get_rmw_rs_type, - pre_field_serde=pre_field_serde, - get_idiomatic_rs_type=get_idiomatic_rs_type, constant_value_to_rs=constant_value_to_rs) }@ -} // mod rmw diff --git a/rosidl_generator_rs/resource/srv/rmw.rs.em b/rosidl_generator_rs/resource/srv/rmw.rs.em new file mode 100644 index 0000000..b30ca6f --- /dev/null +++ b/rosidl_generator_rs/resource/srv/rmw.rs.em @@ -0,0 +1,13 @@ +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +@{ +TEMPLATE( + '../templates/srv_rmw.rs.em', + package_name=package_name, interface_path=interface_path, + srv_specs=srv_specs, + get_rs_name=get_rs_name, + get_rs_type=make_get_rs_type(False), + pre_field_serde=pre_field_serde, + constant_value_to_rs=constant_value_to_rs) +}@ \ No newline at end of file diff --git a/rosidl_generator_rs/resource/srv_rmw.rs.em b/rosidl_generator_rs/resource/srv_rmw.rs.em deleted file mode 100644 index 6ba55f1..0000000 --- a/rosidl_generator_rs/resource/srv_rmw.rs.em +++ /dev/null @@ -1,44 +0,0 @@ -@{ -req_res_specs = [] - -for subfolder, service in srv_specs: - req_res_specs.append((subfolder, service.request_message)) - req_res_specs.append((subfolder, service.response_message)) -}@ - -@{ -TEMPLATE( - 'msg_rmw.rs.em', - package_name=package_name, interface_path=interface_path, - msg_specs=req_res_specs, - get_rs_name=get_rs_name, get_rmw_rs_type=get_rmw_rs_type, - pre_field_serde=pre_field_serde, - get_idiomatic_rs_type=get_idiomatic_rs_type, - constant_value_to_rs=constant_value_to_rs) -}@ - -@[for subfolder, srv_spec in srv_specs] - -@{ -type_name = srv_spec.namespaced_type.name -}@ - - #[link(name = "@(package_name)__rosidl_typesupport_c")] - extern "C" { - fn rosidl_typesupport_c__get_service_type_support_handle__@(package_name)__@(subfolder)__@(type_name)() -> *const std::ffi::c_void; - } - - // Corresponds to @(package_name)__@(subfolder)__@(type_name) - pub struct @(type_name); - - impl rosidl_runtime_rs::Service for @(type_name) { - type Request = crate::@(subfolder)::rmw::@(type_name)_Request; - type Response = crate::@(subfolder)::rmw::@(type_name)_Response; - - fn get_type_support() -> *const std::ffi::c_void { - // SAFETY: No preconditions for this function. - unsafe { rosidl_typesupport_c__get_service_type_support_handle__@(package_name)__@(subfolder)__@(type_name)() } - } - } - -@[end for] diff --git a/rosidl_generator_rs/resource/msg_idiomatic.rs.em b/rosidl_generator_rs/resource/templates/msg_idiomatic.rs.em similarity index 85% rename from rosidl_generator_rs/resource/msg_idiomatic.rs.em rename to rosidl_generator_rs/resource/templates/msg_idiomatic.rs.em index fe59979..e1e8d70 100644 --- a/rosidl_generator_rs/resource/msg_idiomatic.rs.em +++ b/rosidl_generator_rs/resource/templates/msg_idiomatic.rs.em @@ -24,7 +24,7 @@ type_name = msg_spec.structure.namespaced_type.name #[derive(Clone, Debug, PartialEq, PartialOrd)] pub struct @(type_name) { @[for member in msg_spec.structure.members]@ - @(pre_field_serde(member.type))pub @(get_rs_name(member.name)): @(get_idiomatic_rs_type(member.type)), + @(pre_field_serde(member.type))pub @(get_rs_name(member.name)): @(get_rs_type(member.type)), @[end for]@ } @@ -42,7 +42,7 @@ comments = getattr(constant, 'get_comment_lines', lambda: [])() @[ end if]@ @[ end for]@ @[ if isinstance(constant.type, BasicType)]@ - pub const @(get_rs_name(constant.name)): @(get_rmw_rs_type(constant.type)) = @(constant_value_to_rs(constant.type, constant.value)); + pub const @(get_rs_name(constant.name)): @(get_rs_type(constant.type)) = @(constant_value_to_rs(constant.type, constant.value)); @[ elif isinstance(constant.type, AbstractGenericString)]@ pub const @(get_rs_name(constant.name)): &'static str = @(constant_value_to_rs(constant.type, constant.value)); @[ else]@ @@ -55,12 +55,12 @@ comments = getattr(constant, 'get_comment_lines', lambda: [])() impl Default for @(type_name) { fn default() -> Self { @# This has the benefit of automatically setting the right default values - ::from_rmw_message(crate::@(subfolder)::rmw::@(type_name)::default()) + ::from_rmw_message(super::@(subfolder)::rmw::@(type_name)::default()) } } impl rosidl_runtime_rs::Message for @(type_name) { - type RmwMsg = crate::@(subfolder)::rmw::@(type_name); + type RmwMsg = super::@(subfolder)::rmw::@(type_name); fn into_rmw_message(msg_cow: std::borrow::Cow<'_, Self>) -> std::borrow::Cow<'_, Self::RmwMsg> { match msg_cow { @@ -75,7 +75,7 @@ impl rosidl_runtime_rs::Message for @(type_name) { .map(|elem| elem.as_str().into()), @[ elif isinstance(member.type.value_type, NamedType) or isinstance(member.type.value_type, NamespacedType)]@ @(get_rs_name(member.name)): msg.@(get_rs_name(member.name)) - .map(|elem| @(get_idiomatic_rs_type(member.type.value_type))::into_rmw_message(std::borrow::Cow::Owned(elem)).into_owned()), + .map(|elem| @(get_rs_type(member.type.value_type))::into_rmw_message(std::borrow::Cow::Owned(elem)).into_owned()), @[ elif isinstance(member.type.value_type, BasicType)]@ @(get_rs_name(member.name)): msg.@(get_rs_name(member.name)), @[ else]@ @@ -98,7 +98,7 @@ impl rosidl_runtime_rs::Message for @(type_name) { @[ elif isinstance(member.type.value_type, NamedType) or isinstance(member.type.value_type, NamespacedType)]@ @(get_rs_name(member.name)): msg.@(get_rs_name(member.name)) .into_iter() - .map(|elem| @(get_idiomatic_rs_type(member.type.value_type))::into_rmw_message(std::borrow::Cow::Owned(elem)).into_owned()) + .map(|elem| @(get_rs_type(member.type.value_type))::into_rmw_message(std::borrow::Cow::Owned(elem)).into_owned()) .collect(), @[ else]@ @(get_rs_name(member.name)): msg.@(get_rs_name(member.name)).into(), @@ -107,7 +107,7 @@ impl rosidl_runtime_rs::Message for @(type_name) { @# @# == NamedType + NamespacedType == @[ elif isinstance(member.type, NamedType) or isinstance(member.type, NamespacedType)]@ - @(get_rs_name(member.name)): @(get_idiomatic_rs_type(member.type))::into_rmw_message(std::borrow::Cow::Owned(msg.@(get_rs_name(member.name)))).into_owned(), + @(get_rs_name(member.name)): @(get_rs_type(member.type))::into_rmw_message(std::borrow::Cow::Owned(msg.@(get_rs_name(member.name)))).into_owned(), @# @# @# == Bounded and basic types == @@ -132,7 +132,7 @@ impl rosidl_runtime_rs::Message for @(type_name) { @[ elif isinstance(member.type.value_type, NamedType) or isinstance(member.type.value_type, NamespacedType)]@ @(get_rs_name(member.name)): msg.@(get_rs_name(member.name)) .iter() - .map(|elem| @(get_idiomatic_rs_type(member.type.value_type))::into_rmw_message(std::borrow::Cow::Borrowed(elem)).into_owned()) + .map(|elem| @(get_rs_type(member.type.value_type))::into_rmw_message(std::borrow::Cow::Borrowed(elem)).into_owned()) .collect::>() .try_into() .unwrap(), @@ -158,7 +158,7 @@ impl rosidl_runtime_rs::Message for @(type_name) { @[ elif isinstance(member.type.value_type, NamedType) or isinstance(member.type.value_type, NamespacedType)]@ @(get_rs_name(member.name)): msg.@(get_rs_name(member.name)) .iter() - .map(|elem| @(get_idiomatic_rs_type(member.type.value_type))::into_rmw_message(std::borrow::Cow::Borrowed(elem)).into_owned()) + .map(|elem| @(get_rs_type(member.type.value_type))::into_rmw_message(std::borrow::Cow::Borrowed(elem)).into_owned()) .collect(), @[ else]@ @(get_rs_name(member.name)): msg.@(get_rs_name(member.name)).as_slice().into(), @@ -167,7 +167,7 @@ impl rosidl_runtime_rs::Message for @(type_name) { @# @# == NamedType + NamespacedType == @[ elif isinstance(member.type, NamedType) or isinstance(member.type, NamespacedType)]@ - @(get_rs_name(member.name)): @(get_idiomatic_rs_type(member.type))::into_rmw_message(std::borrow::Cow::Borrowed(&msg.@(get_rs_name(member.name)))).into_owned(), + @(get_rs_name(member.name)): @(get_rs_type(member.type))::into_rmw_message(std::borrow::Cow::Borrowed(&msg.@(get_rs_name(member.name)))).into_owned(), @# @# @# == BasicType == @@ -196,7 +196,7 @@ impl rosidl_runtime_rs::Message for @(type_name) { .map(|elem| elem.to_string()), @[ elif isinstance(member.type.value_type, NamedType) or isinstance(member.type.value_type, NamespacedType)]@ @(get_rs_name(member.name)): msg.@(get_rs_name(member.name)) - .map(@(get_idiomatic_rs_type(member.type.value_type))::from_rmw_message), + .map(@(get_rs_type(member.type.value_type))::from_rmw_message), @[ else]@ @(get_rs_name(member.name)): msg.@(get_rs_name(member.name)), @[ end if]@ @@ -209,7 +209,7 @@ impl rosidl_runtime_rs::Message for @(type_name) { @[ if isinstance(member.type.value_type, UnboundedString) or isinstance(member.type.value_type, UnboundedWString)]@ .map(|elem| elem.to_string()) @[ elif isinstance(member.type.value_type, NamedType) or isinstance(member.type.value_type, NamespacedType)]@ - .map(@(get_idiomatic_rs_type(member.type.value_type))::from_rmw_message) + .map(@(get_rs_type(member.type.value_type))::from_rmw_message) @[ end if]@ .collect(), @# @@ -221,7 +221,7 @@ impl rosidl_runtime_rs::Message for @(type_name) { @# @# == NamedType + NamespacedType == @[ elif isinstance(member.type, NamedType) or isinstance(member.type, NamespacedType)]@ - @(get_rs_name(member.name)): @(get_idiomatic_rs_type(member.type))::from_rmw_message(msg.@(get_rs_name(member.name))), + @(get_rs_name(member.name)): @(get_rs_type(member.type))::from_rmw_message(msg.@(get_rs_name(member.name))), @# @# @# == Bounded and basic types == diff --git a/rosidl_generator_rs/resource/msg_rmw.rs.em b/rosidl_generator_rs/resource/templates/msg_rmw.rs.em similarity index 96% rename from rosidl_generator_rs/resource/msg_rmw.rs.em rename to rosidl_generator_rs/resource/templates/msg_rmw.rs.em index 3c8ab9a..b55bf58 100644 --- a/rosidl_generator_rs/resource/msg_rmw.rs.em +++ b/rosidl_generator_rs/resource/templates/msg_rmw.rs.em @@ -36,7 +36,7 @@ extern "C" { #[derive(Clone, Debug, PartialEq, PartialOrd)] pub struct @(type_name) { @[for member in msg_spec.structure.members]@ - @(pre_field_serde(member.type))pub @(get_rs_name(member.name)): @(get_rmw_rs_type(member.type)), + @(pre_field_serde(member.type))pub @(get_rs_name(member.name)): @(get_rs_type(member.type)), @[end for]@ } @@ -54,7 +54,7 @@ comments = getattr(constant, 'get_comment_lines', lambda: [])() @[ end if]@ @[ end for]@ @[ if isinstance(constant.type, BasicType)]@ - pub const @(get_rs_name(constant.name)): @(get_rmw_rs_type(constant.type)) = @(constant_value_to_rs(constant.type, constant.value)); + pub const @(get_rs_name(constant.name)): @(get_rs_type(constant.type)) = @(constant_value_to_rs(constant.type, constant.value)); @[ elif isinstance(constant.type, AbstractGenericString)]@ pub const @(get_rs_name(constant.name)): &'static str = @(constant_value_to_rs(constant.type, constant.value)); @[ else]@ diff --git a/rosidl_generator_rs/resource/srv_idiomatic.rs.em b/rosidl_generator_rs/resource/templates/srv_idiomatic.rs.em similarity index 63% rename from rosidl_generator_rs/resource/srv_idiomatic.rs.em rename to rosidl_generator_rs/resource/templates/srv_idiomatic.rs.em index 660f1a6..838a6e3 100644 --- a/rosidl_generator_rs/resource/srv_idiomatic.rs.em +++ b/rosidl_generator_rs/resource/templates/srv_idiomatic.rs.em @@ -8,12 +8,12 @@ for subfolder, service in srv_specs: @{ TEMPLATE( - 'msg_idiomatic.rs.em', + 'templates/msg_idiomatic.rs.em', package_name=package_name, interface_path=interface_path, msg_specs=req_res_specs, - get_rs_name=get_rs_name, get_rmw_rs_type=get_rmw_rs_type, + get_rs_name=get_rs_name, + get_rs_type=get_rs_type, pre_field_serde=pre_field_serde, - get_idiomatic_rs_type=get_idiomatic_rs_type, constant_value_to_rs=constant_value_to_rs) }@ @@ -32,13 +32,13 @@ extern "C" { pub struct @(type_name); impl rosidl_runtime_rs::Service for @(type_name) { - type Request = crate::@(subfolder)::@(type_name)_Request; - type Response = crate::@(subfolder)::@(type_name)_Response; + type Request = @(type_name)_Request; + type Response = @(type_name)_Response; - fn get_type_support() -> *const std::ffi::c_void { - // SAFETY: No preconditions for this function. - unsafe { rosidl_typesupport_c__get_service_type_support_handle__@(package_name)__@(subfolder)__@(type_name)() } - } + fn get_type_support() -> *const std::ffi::c_void { + // SAFETY: No preconditions for this function. + unsafe { rosidl_typesupport_c__get_service_type_support_handle__@(package_name)__@(subfolder)__@(type_name)() } + } } @[end for] diff --git a/rosidl_generator_rs/resource/templates/srv_rmw.rs.em b/rosidl_generator_rs/resource/templates/srv_rmw.rs.em new file mode 100644 index 0000000..db10f69 --- /dev/null +++ b/rosidl_generator_rs/resource/templates/srv_rmw.rs.em @@ -0,0 +1,44 @@ +@{ +req_res_specs = [] + +for subfolder, service in srv_specs: + req_res_specs.append((subfolder, service.request_message)) + req_res_specs.append((subfolder, service.response_message)) +}@ + +@{ +TEMPLATE( + '../templates/msg_rmw.rs.em', + package_name=package_name, interface_path=interface_path, + msg_specs=req_res_specs, + get_rs_name=get_rs_name, + get_rs_type=get_rs_type, + pre_field_serde=pre_field_serde, + constant_value_to_rs=constant_value_to_rs) +}@ + +@[for subfolder, srv_spec in srv_specs] + +@{ +type_name = srv_spec.namespaced_type.name +}@ + +#[link(name = "@(package_name)__rosidl_typesupport_c")] +extern "C" { + fn rosidl_typesupport_c__get_service_type_support_handle__@(package_name)__@(subfolder)__@(type_name)() -> *const std::ffi::c_void; +} + +// Corresponds to @(package_name)__@(subfolder)__@(type_name) +pub struct @(type_name); + +impl rosidl_runtime_rs::Service for @(type_name) { + type Request = @(type_name)_Request; + type Response = @(type_name)_Response; + + fn get_type_support() -> *const std::ffi::c_void { + // SAFETY: No preconditions for this function. + unsafe { rosidl_typesupport_c__get_service_type_support_handle__@(package_name)__@(subfolder)__@(type_name)() } + } +} + +@[end for] diff --git a/rosidl_generator_rs/rosidl_generator_rs/__init__.py b/rosidl_generator_rs/rosidl_generator_rs/__init__.py index b7850a6..f9aac10 100644 --- a/rosidl_generator_rs/rosidl_generator_rs/__init__.py +++ b/rosidl_generator_rs/rosidl_generator_rs/__init__.py @@ -44,6 +44,7 @@ from rosidl_parser.parser import parse_idl_file +package_name = "" # Taken from http://stackoverflow.com/a/6425628 def convert_lower_case_underscore_to_camel_case(word): @@ -52,6 +53,8 @@ def convert_lower_case_underscore_to_camel_case(word): def generate_rs(generator_arguments_file, typesupport_impls): args = rosidl_pycommon.read_generator_arguments(generator_arguments_file) + + global package_name package_name = args['package_name'] # expand init modules for each directory @@ -84,15 +87,18 @@ def generate_rs(generator_arguments_file, typesupport_impls): template_dir = args['template_dir'] mapping_msgs = { - os.path.join(template_dir, 'msg.rs.em'): ['rust/src/%s.rs'], + os.path.join(template_dir, 'msg.rs.em'): ['rust/src/%s'], + os.path.join(template_dir, 'msg/rmw.rs.em'): ['rust/src/msg/%s'], } mapping_srvs = { - os.path.join(template_dir, 'srv.rs.em'): ['rust/src/%s.rs'], + os.path.join(template_dir, 'srv.rs.em'): ['rust/src/%s'], + os.path.join(template_dir, 'srv/rmw.rs.em'): ['rust/src/srv/%s'], } mapping_actions = { - os.path.join(template_dir, 'action.rs.em'): ['rust/src/%s.rs'], + os.path.join(template_dir, 'action.rs.em'): ['rust/src/%s'], + os.path.join(template_dir, 'action/rmw.rs.em'): ['rust/src/action/%s'], } # Ensure the required templates exist @@ -108,9 +114,8 @@ def generate_rs(generator_arguments_file, typesupport_impls): data = { 'pre_field_serde': pre_field_serde, - 'get_rmw_rs_type': make_get_rmw_rs_type(args['package_name']), 'get_rs_name': get_rs_name, - 'get_idiomatic_rs_type': make_get_idiomatic_rs_type(args['package_name']), + 'make_get_rs_type': make_get_rs_type, 'constant_value_to_rs': constant_value_to_rs, 'value_to_rs': value_to_rs, 'convert_camel_case_to_lower_case_underscore': @@ -120,7 +125,7 @@ def generate_rs(generator_arguments_file, typesupport_impls): 'msg_specs': [], 'srv_specs': [], 'action_specs': [], - 'package_name': args['package_name'], + 'package_name': package_name, 'typesupport_impls': typesupport_impls, 'interface_path': idl_rel_path, } @@ -139,9 +144,11 @@ def generate_rs(generator_arguments_file, typesupport_impls): if data['msg_specs']: for template_file, generated_filenames in mapping_msgs.items(): + stem = Path(template_file).stem.removesuffix(".em") + for generated_filename in generated_filenames: generated_file = os.path.join(args['output_dir'], - generated_filename % 'msg') + generated_filename % stem) rosidl_pycommon.expand_template( os.path.join(template_dir, template_file), data.copy(), @@ -150,9 +157,11 @@ def generate_rs(generator_arguments_file, typesupport_impls): if data['srv_specs']: for template_file, generated_filenames in mapping_srvs.items(): + stem = Path(template_file).stem.removesuffix(".em") + for generated_filename in generated_filenames: generated_file = os.path.join(args['output_dir'], - generated_filename % 'srv') + generated_filename % stem) rosidl_pycommon.expand_template( os.path.join(template_dir, template_file), data.copy(), @@ -161,9 +170,11 @@ def generate_rs(generator_arguments_file, typesupport_impls): if data['action_specs']: for template_file, generated_filenames in mapping_actions.items(): + stem = Path(template_file).stem.removesuffix(".em") + for generated_filename in generated_filenames: generated_file = os.path.join(args['output_dir'], - generated_filename % 'action') + generated_filename % stem) rosidl_pycommon.expand_template( os.path.join(template_dir, template_file), data.copy(), @@ -178,7 +189,7 @@ def generate_rs(generator_arguments_file, typesupport_impls): cargo_toml_data = { 'dependency_packages': dependency_packages, - 'package_name': args['package_name'], + 'package_name': package_name, 'package_version': args['package_version'], } rosidl_pycommon.expand_template( @@ -201,6 +212,8 @@ def get_rs_name(name): 'as', 'break', 'const', 'continue', 'crate', 'else', 'enum', 'extern', 'false', 'fn', 'for', 'if', 'for', 'impl', 'in', 'let', 'loop', 'match', 'mod', 'move', 'mut', 'pub', 'ref', 'return', 'self', 'Self', 'static', 'struct', 'super', 'trait', 'true', 'type', 'unsafe', 'use', 'where', 'while', + # Edition 2024+ + 'gen', # Edition 2018+ 'async', 'await', 'dyn', # Reserved @@ -278,7 +291,7 @@ def constant_value_to_rs(type_, value): assert False, "unknown constant type '%s'" % type_ # Type hierarchy: -# +# # AbstractType # - AbstractNestableType # - AbstractGenericString @@ -305,28 +318,9 @@ def pre_field_serde(type_): return '' -def make_get_idiomatic_rs_type(package_name): - get_rmw_rs_type = make_get_rmw_rs_type(package_name) - def get_idiomatic_rs_type(type_): - if isinstance(type_, UnboundedString) or isinstance(type_, UnboundedWString): - return 'std::string::String' - elif isinstance(type_, UnboundedSequence): - return 'Vec<{}>'.format(get_idiomatic_rs_type(type_.value_type)) - elif isinstance(type_, NamespacedType): - return '::'.join(type_.namespaced_name()).replace(package_name, 'crate') - elif isinstance(type_, Array): - return '[{}; {}]'.format(get_idiomatic_rs_type(type_.value_type), type_.size) - else: - return get_rmw_rs_type(type_) - return get_idiomatic_rs_type - -def make_get_rmw_rs_type(package_name): - def get_rmw_rs_type(type_): - if isinstance(type_, NamespacedType): - parts = list(type_.namespaced_name()) - parts.insert(-1, 'rmw') - return '::'.join(parts).replace(package_name, 'crate') - elif isinstance(type_, BasicType): +def make_get_rs_type(idiomatic): + def get_rs_type(type_, current_idiomatic, desired_idiomatic): + if isinstance(type_, BasicType): if type_.typename == 'boolean': return 'bool' elif type_.typename in ['byte', 'octet']: @@ -355,20 +349,48 @@ def get_rmw_rs_type(type_): return 'i64' elif type_.typename == 'uint64': return 'u64' - elif isinstance(type_, UnboundedString): - return 'rosidl_runtime_rs::String' - elif isinstance(type_, UnboundedWString): - return 'rosidl_runtime_rs::WString' elif isinstance(type_, BoundedString): return 'rosidl_runtime_rs::BoundedString<{}>'.format(type_.maximum_size) elif isinstance(type_, BoundedWString): return 'rosidl_runtime_rs::BoundedWString<{}>'.format(type_.maximum_size) + elif isinstance(type_, UnboundedString): + return 'std::string::String' if current_idiomatic and desired_idiomatic else 'rosidl_runtime_rs::String' + elif isinstance(type_, UnboundedWString): + return 'std::string::String' if current_idiomatic and desired_idiomatic else 'rosidl_runtime_rs::WString' elif isinstance(type_, Array): - return '[{}; {}]'.format(get_rmw_rs_type(type_.value_type), type_.size) + return f'[{get_rs_type(type_.value_type, current_idiomatic, desired_idiomatic)}; {type_.size}]' elif isinstance(type_, UnboundedSequence): - return 'rosidl_runtime_rs::Sequence<{}>'.format(get_rmw_rs_type(type_.value_type)) + container_type = 'Vec' if current_idiomatic and desired_idiomatic else 'rosidl_runtime_rs::Sequence' + return f'{container_type}<{get_rs_type(type_.value_type, current_idiomatic, desired_idiomatic)}>' elif isinstance(type_, BoundedSequence): - return 'rosidl_runtime_rs::BoundedSequence<{}, {}>'.format(get_rmw_rs_type(type_.value_type), type_.maximum_size) + # BoundedSequences can be in the idiomatic API, but the containing type cannot be from the + # idiomatic API because we do not implement SequenceAlloc for idiomatic types. + return f'rosidl_runtime_rs::BoundedSequence<{get_rs_type(type_.value_type, current_idiomatic, False)}, {type_.maximum_size}>' + elif isinstance(type_, NamespacedType): + # All types should be referencable like this + # `super::msg::rmw::Foo` (From idiomatic modules) + # `super::super::msg::rmw::Foo` (From non-idiomatic modules) + # `::msg::rmw::Foo` (From external packages) + prefix = 'super::' if current_idiomatic else 'super::super::' + + symbol = f'{prefix}{"::".join(type_.namespaced_name()[1:])}' + + # This symbol is coming from an external crate (or needs a `use` statement). + # So it should not be relative (i.e., no `super::`) and should have the top level + # package name (i.e., `builtin_interfaces::`) + top_level_package = type_.namespaces[0] + if top_level_package != package_name: + symbol = "::".join(type_.namespaced_name()) + + if not desired_idiomatic and "::rmw::" not in symbol: + parts = symbol.split("::") + parts.insert(-1, "rmw") + symbol = "::".join(parts) + + return symbol assert False, "unknown type '%s'" % type_.typename - return get_rmw_rs_type + + # Start out by assuming all calls have matching current and desired idiomatic values. + # (i.e. symbols within the `...::rmw` scope want other values in the `...::rmw` scope). + return lambda _type: get_rs_type(_type, idiomatic, idiomatic)