Skip to content

Commit 75fd275

Browse files
committed
Implement client-side trait methods for action messages
This adds methods to ActionImpl for creating and accessing action-specific message types. These are needed by the rclrs ActionClient to generically read and write RMW messages. Due to issues with qualified paths in certain places (rust-lang/rust#86935), the generator now refers directly to its service and message types rather than going through associated types of the various traits. This also makes the generated code a little easier to read, with the trait method signatures from rosidl_runtime_rs still enforcing type-safety.
1 parent be5b7e1 commit 75fd275

File tree

3 files changed

+90
-23
lines changed

3 files changed

+90
-23
lines changed

rclrs/src/action/server.rs

+5-7
Original file line numberDiff line numberDiff line change
@@ -197,9 +197,7 @@ where
197197
mut request_id: rmw_request_id_t,
198198
accepted: bool,
199199
) -> Result<(), RclrsError> {
200-
type RmwResponse<T> = <<<T as ActionImpl>::SendGoalService as Service>::Response as Message>::RmwMsg;
201-
let mut response_rmw = RmwResponse::<T>::default();
202-
<T as ActionImpl>::set_goal_response_accepted(&mut response_rmw, accepted);
200+
let mut response_rmw = <T as ActionImpl>::create_goal_response(accepted, (0, 0));
203201
let handle = &*self.handle.lock();
204202
let result = unsafe {
205203
// SAFETY: The action server handle is locked and so synchronized with other
@@ -210,7 +208,7 @@ where
210208
rcl_action_send_goal_response(
211209
handle,
212210
&mut request_id,
213-
&mut response_rmw as *mut RmwResponse<T> as *mut _,
211+
&mut response_rmw as *mut _ as *mut _,
214212
)
215213
}
216214
.ok();
@@ -242,7 +240,7 @@ where
242240
Err(err) => return Err(err),
243241
};
244242

245-
let uuid = GoalUuid(<T as ActionImpl>::get_goal_request_uuid(&request));
243+
let uuid = GoalUuid(*<T as ActionImpl>::get_goal_request_uuid(&request));
246244

247245
let response: GoalResponse = {
248246
todo!("Optionally convert request to an idiomatic type for the user's callback.");
@@ -522,7 +520,7 @@ where
522520
Err(err) => return Err(err),
523521
};
524522

525-
let uuid = GoalUuid(<T as ActionImpl>::get_result_request_uuid(&request));
523+
let uuid = GoalUuid(*<T as ActionImpl>::get_result_request_uuid(&request));
526524

527525
let goal_exists = unsafe {
528526
// SAFETY: No preconditions
@@ -640,7 +638,7 @@ where
640638

641639
pub(crate) fn publish_feedback(&self, goal_id: &GoalUuid, feedback: &<T as rosidl_runtime_rs::Action>::Feedback) -> Result<(), RclrsError> {
642640
let feedback_rmw = <<T as rosidl_runtime_rs::Action>::Feedback as Message>::into_rmw_message(std::borrow::Cow::Borrowed(feedback));
643-
let mut feedback_msg = <T as rosidl_runtime_rs::ActionImpl>::create_feedback_message(&goal_id.0, &*feedback_rmw);
641+
let mut feedback_msg = <T as rosidl_runtime_rs::ActionImpl>::create_feedback_message(&goal_id.0, feedback_rmw.into_owned());
644642
unsafe {
645643
// SAFETY: The action server is locked through the handle, meaning that no other
646644
// non-thread-safe functions can be called on it at the same time. The feedback_msg is

rosidl_generator_rs/resource/action.rs.em

+56-11
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ from rosidl_parser.definition import (
66
ACTION_GOAL_SUFFIX,
77
ACTION_RESULT_SERVICE_SUFFIX,
88
ACTION_RESULT_SUFFIX,
9+
SERVICE_REQUEST_MESSAGE_SUFFIX,
10+
SERVICE_RESPONSE_MESSAGE_SUFFIX,
911
)
1012

1113
action_msg_specs = []
@@ -100,31 +102,74 @@ impl rosidl_runtime_rs::ActionImpl for @(type_name) {
100102
type CancelGoalService = action_msgs::srv::rmw::CancelGoal;
101103
type GetResultService = crate::@(subfolder)::rmw::@(type_name)@(ACTION_RESULT_SERVICE_SUFFIX);
102104

103-
fn get_goal_request_uuid(request: &<<Self::SendGoalService as rosidl_runtime_rs::Service>::Request as rosidl_runtime_rs::Message>::RmwMsg) -> [u8; 16] {
104-
request.goal_id.uuid
105+
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) {
106+
crate::@(subfolder)::rmw::@(type_name)@(ACTION_GOAL_SERVICE_SUFFIX)@(SERVICE_REQUEST_MESSAGE_SUFFIX) {
107+
goal_id: unique_identifier_msgs::msg::rmw::UUID { uuid: *goal_id },
108+
goal,
109+
}
110+
}
111+
112+
fn get_goal_request_uuid(request: &crate::@(subfolder)::rmw::@(type_name)@(ACTION_GOAL_SERVICE_SUFFIX)@(SERVICE_REQUEST_MESSAGE_SUFFIX)) -> &[u8; 16] {
113+
&request.goal_id.uuid
114+
}
115+
116+
fn create_goal_response(accepted: bool, stamp: (i32, u32)) -> crate::@(subfolder)::rmw::@(type_name)@(ACTION_GOAL_SERVICE_SUFFIX)@(SERVICE_RESPONSE_MESSAGE_SUFFIX) {
117+
crate::@(subfolder)::rmw::@(type_name)@(ACTION_GOAL_SERVICE_SUFFIX)@(SERVICE_RESPONSE_MESSAGE_SUFFIX) {
118+
accepted,
119+
stamp: builtin_interfaces::msg::rmw::Time {
120+
sec: stamp.0,
121+
nanosec: stamp.1,
122+
},
123+
}
124+
}
125+
126+
fn get_goal_response_accepted(response: &crate::@(subfolder)::rmw::@(type_name)@(ACTION_GOAL_SERVICE_SUFFIX)@(SERVICE_RESPONSE_MESSAGE_SUFFIX)) -> bool {
127+
response.accepted
105128
}
106129

107-
fn set_goal_response_accepted(response: &mut <<Self::SendGoalService as rosidl_runtime_rs::Service>::Response as rosidl_runtime_rs::Message>::RmwMsg, accepted: bool) {
108-
response.accepted = accepted;
130+
fn get_goal_response_stamp(response: &crate::@(subfolder)::rmw::@(type_name)@(ACTION_GOAL_SERVICE_SUFFIX)@(SERVICE_RESPONSE_MESSAGE_SUFFIX)) -> (i32, u32) {
131+
(response.stamp.sec, response.stamp.nanosec)
109132
}
110133

111-
fn create_feedback_message(goal_id: &[u8; 16], feedback: &<<Self as rosidl_runtime_rs::Action>::Feedback as rosidl_runtime_rs::Message>::RmwMsg) -> <Self::FeedbackMessage as rosidl_runtime_rs::Message>::RmwMsg {
112-
let mut message = <Self::FeedbackMessage as rosidl_runtime_rs::Message>::RmwMsg::default();
134+
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) {
135+
let mut message = crate::@(subfolder)::rmw::@(type_name)@(ACTION_FEEDBACK_MESSAGE_SUFFIX)::default();
113136
message.goal_id.uuid = *goal_id;
114-
message.feedback = feedback.clone();
137+
message.feedback = feedback;
115138
message
116139
}
117140

118-
fn get_result_request_uuid(request: &<<Self::GetResultService as rosidl_runtime_rs::Service>::Request as rosidl_runtime_rs::Message>::RmwMsg) -> [u8; 16] {
119-
request.goal_id.uuid
141+
fn get_feedback_message_uuid(feedback: &crate::@(subfolder)::rmw::@(type_name)@(ACTION_FEEDBACK_MESSAGE_SUFFIX)) -> &[u8; 16] {
142+
&feedback.goal_id.uuid
143+
}
144+
145+
fn get_feedback_message_feedback(feedback: &crate::@(subfolder)::rmw::@(type_name)@(ACTION_FEEDBACK_MESSAGE_SUFFIX)) -> &crate::@(subfolder)::rmw::@(type_name)@(ACTION_FEEDBACK_SUFFIX) {
146+
&feedback.feedback
120147
}
121148

122-
fn create_result_response(status: i8, result: <<Self as Action>::Result as Message>::RmwMsg) -> <<Self::GetResultService as Service>::Response as Message>::RmwMsg {
123-
<<Self::GetResultService as rosidl_runtime_rs::Service>::Response as rosidl_runtime_rs::Message>::RmwMsg {
149+
fn create_result_request(goal_id: &[u8; 16]) -> crate::@(subfolder)::rmw::@(type_name)@(ACTION_RESULT_SERVICE_SUFFIX)@(SERVICE_REQUEST_MESSAGE_SUFFIX) {
150+
crate::@(subfolder)::rmw::@(type_name)@(ACTION_RESULT_SERVICE_SUFFIX)@(SERVICE_REQUEST_MESSAGE_SUFFIX) {
151+
goal_id: unique_identifier_msgs::msg::rmw::UUID { uuid: *goal_id },
152+
}
153+
}
154+
155+
fn get_result_request_uuid(request: &crate::@(subfolder)::rmw::@(type_name)@(ACTION_RESULT_SERVICE_SUFFIX)@(SERVICE_REQUEST_MESSAGE_SUFFIX)) -> &[u8; 16] {
156+
&request.goal_id.uuid
157+
}
158+
159+
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) {
160+
crate::@(subfolder)::rmw::@(type_name)@(ACTION_RESULT_SERVICE_SUFFIX)@(SERVICE_RESPONSE_MESSAGE_SUFFIX) {
124161
status,
125162
result,
126163
}
127164
}
165+
166+
fn get_result_response_result(response: &crate::@(subfolder)::rmw::@(type_name)@(ACTION_RESULT_SERVICE_SUFFIX)@(SERVICE_RESPONSE_MESSAGE_SUFFIX)) -> &crate::@(subfolder)::rmw::@(type_name)@(ACTION_RESULT_SUFFIX) {
167+
&response.result
168+
}
169+
170+
fn get_result_response_status(response: &crate::@(subfolder)::rmw::@(type_name)@(ACTION_RESULT_SERVICE_SUFFIX)@(SERVICE_RESPONSE_MESSAGE_SUFFIX)) -> i8 {
171+
response.status
172+
}
128173
}
129174

130175
@[end for]

rosidl_runtime_rs/src/traits.rs

+29-5
Original file line numberDiff line numberDiff line change
@@ -196,18 +196,42 @@ pub trait ActionImpl: 'static + Action {
196196
/// The get_result service associated with this action.
197197
type GetResultService: Service;
198198

199+
/// Create a goal request message with the given UUID and goal.
200+
fn create_goal_request(goal_id: &[u8; 16], goal: <<Self as Action>::Goal as Message>::RmwMsg) -> <<Self::SendGoalService as Service>::Request as Message>::RmwMsg;
201+
199202
/// Get the UUID of a goal request.
200-
fn get_goal_request_uuid(request: &<<Self::SendGoalService as Service>::Request as Message>::RmwMsg) -> [u8; 16];
203+
fn get_goal_request_uuid(request: &<<Self::SendGoalService as Service>::Request as Message>::RmwMsg) -> &[u8; 16];
204+
205+
/// Create a goal response message with the given acceptance and timestamp.
206+
fn create_goal_response(accepted: bool, stamp: (i32, u32)) -> <<Self::SendGoalService as Service>::Response as Message>::RmwMsg;
201207

202-
/// Sets the `accepted` field of a goal response.
203-
fn set_goal_response_accepted(response: &mut <<Self::SendGoalService as Service>::Response as Message>::RmwMsg, accepted: bool);
208+
/// Get the `accepted` field of a goal response.
209+
fn get_goal_response_accepted(response: &<<Self::SendGoalService as Service>::Response as Message>::RmwMsg) -> bool;
210+
211+
/// Get the `stamp` field of a goal response.
212+
fn get_goal_response_stamp(response: &<<Self::SendGoalService as Service>::Response as Message>::RmwMsg) -> (i32, u32);
204213

205214
/// Create a feedback message with the given goal ID and contents.
206-
fn create_feedback_message(goal_id: &[u8; 16], feedback: &<<Self as Action>::Feedback as Message>::RmwMsg) -> <Self::FeedbackMessage as Message>::RmwMsg;
215+
fn create_feedback_message(goal_id: &[u8; 16], feedback: <<Self as Action>::Feedback as Message>::RmwMsg) -> <Self::FeedbackMessage as Message>::RmwMsg;
216+
217+
/// Get the UUID of a feedback message.
218+
fn get_feedback_message_uuid(feedback: &<Self::FeedbackMessage as Message>::RmwMsg) -> &[u8; 16];
219+
220+
/// Get the feedback of a feedback message.
221+
fn get_feedback_message_feedback(feedback: &<Self::FeedbackMessage as Message>::RmwMsg) -> &<<Self as Action>::Feedback as Message>::RmwMsg;
222+
223+
/// Create a result request message with the given goal ID.
224+
fn create_result_request(goal_id: &[u8; 16]) -> <<Self::GetResultService as Service>::Request as Message>::RmwMsg;
207225

208226
/// Get the UUID of a result request.
209-
fn get_result_request_uuid(request: &<<Self::GetResultService as Service>::Request as Message>::RmwMsg) -> [u8; 16];
227+
fn get_result_request_uuid(request: &<<Self::GetResultService as Service>::Request as Message>::RmwMsg) -> &[u8; 16];
210228

211229
/// Create a result response message with the given status and contents.
212230
fn create_result_response(status: i8, result: <<Self as Action>::Result as Message>::RmwMsg) -> <<Self::GetResultService as Service>::Response as Message>::RmwMsg;
231+
232+
/// Get the result of a result response.
233+
fn get_result_response_result(response: &<<Self::GetResultService as Service>::Response as Message>::RmwMsg) -> &<<Self as Action>::Result as Message>::RmwMsg;
234+
235+
/// Get the status of a result response.
236+
fn get_result_response_status(response: &<<Self::GetResultService as Service>::Response as Message>::RmwMsg) -> i8;
213237
}

0 commit comments

Comments
 (0)