@@ -3,7 +3,6 @@ use crate::qos::QoSProfile;
3
3
use crate :: Node ;
4
4
use crate :: { rcl_bindings:: * , RclrsError } ;
5
5
6
- use std:: boxed:: Box ;
7
6
use std:: ffi:: CStr ;
8
7
use std:: ffi:: CString ;
9
8
use std:: marker:: PhantomData ;
@@ -12,7 +11,11 @@ use std::sync::{Arc, Mutex, MutexGuard};
12
11
13
12
use rosidl_runtime_rs:: { Message , RmwMessage } ;
14
13
14
+ mod callback;
15
+ mod message_info;
15
16
mod readonly_loaned_message;
17
+ pub use callback:: * ;
18
+ pub use message_info:: * ;
16
19
pub use readonly_loaned_message:: * ;
17
20
18
21
// SAFETY: The functions accessing this type, including drop(), shouldn't care about the thread
71
74
{
72
75
pub ( crate ) handle : Arc < SubscriptionHandle > ,
73
76
/// The callback function that runs when a message was received.
74
- pub callback : Mutex < Box < dyn FnMut ( T ) + ' static + Send > > ,
77
+ pub callback : Mutex < AnySubscriptionCallback < T > > ,
75
78
message : PhantomData < T > ,
76
79
}
77
80
@@ -80,17 +83,16 @@ where
80
83
T : Message ,
81
84
{
82
85
/// Creates a new subscription.
83
- pub ( crate ) fn new < F > (
86
+ pub ( crate ) fn new < Args > (
84
87
node : & Node ,
85
88
topic : & str ,
86
89
qos : QoSProfile ,
87
- callback : F ,
90
+ callback : impl SubscriptionCallback < T , Args > ,
88
91
) -> Result < Self , RclrsError >
89
92
// This uses pub(crate) visibility to avoid instantiating this struct outside
90
93
// [`Node::create_subscription`], see the struct's documentation for the rationale
91
94
where
92
95
T : Message ,
93
- F : FnMut ( T ) + ' static + Send ,
94
96
{
95
97
// SAFETY: Getting a zero-initialized value is always safe.
96
98
let mut rcl_subscription = unsafe { rcl_get_zero_initialized_subscription ( ) } ;
@@ -129,7 +131,7 @@ where
129
131
130
132
Ok ( Self {
131
133
handle,
132
- callback : Mutex :: new ( Box :: new ( callback) ) ,
134
+ callback : Mutex :: new ( callback. into_callback ( ) ) ,
133
135
message : PhantomData ,
134
136
} )
135
137
}
@@ -171,22 +173,44 @@ where
171
173
// | rmw_take |
172
174
// +-------------+
173
175
// ```
174
- pub fn take ( & self ) -> Result < T , RclrsError > {
176
+ pub fn take ( & self ) -> Result < ( T , MessageInfo ) , RclrsError > {
175
177
let mut rmw_message = <T as Message >:: RmwMsg :: default ( ) ;
178
+ let message_info = self . take_inner ( & mut rmw_message) ?;
179
+ Ok ( ( T :: from_rmw_message ( rmw_message) , message_info) )
180
+ }
181
+
182
+ /// This is a version of take() that returns a boxed message.
183
+ ///
184
+ /// This can be more efficient for messages containing large arrays.
185
+ pub fn take_boxed ( & self ) -> Result < ( Box < T > , MessageInfo ) , RclrsError > {
186
+ let mut rmw_message = Box :: new ( <T as Message >:: RmwMsg :: default ( ) ) ;
187
+ let message_info = self . take_inner ( & mut * rmw_message) ?;
188
+ // TODO: This will still use the stack in general. Change signature of
189
+ // from_rmw_message to allow placing the result in a Box directly.
190
+ let message = Box :: new ( T :: from_rmw_message ( * rmw_message) ) ;
191
+ Ok ( ( message, message_info) )
192
+ }
193
+
194
+ // Inner function, to be used by both regular and boxed versions.
195
+ fn take_inner (
196
+ & self ,
197
+ rmw_message : & mut <T as Message >:: RmwMsg ,
198
+ ) -> Result < MessageInfo , RclrsError > {
199
+ let mut message_info = unsafe { rmw_get_zero_initialized_message_info ( ) } ;
176
200
let rcl_subscription = & mut * self . handle . lock ( ) ;
177
201
unsafe {
178
202
// SAFETY: The first two pointers are valid/initialized, and do not need to be valid
179
203
// beyond the function call.
180
204
// The latter two pointers are explicitly allowed to be NULL.
181
205
rcl_take (
182
206
rcl_subscription,
183
- & mut rmw_message as * mut <T as Message >:: RmwMsg as * mut _ ,
184
- std :: ptr :: null_mut ( ) ,
207
+ rmw_message as * mut <T as Message >:: RmwMsg as * mut _ ,
208
+ & mut message_info ,
185
209
std:: ptr:: null_mut ( ) ,
186
210
)
187
211
. ok ( ) ?
188
212
} ;
189
- Ok ( T :: from_rmw_message ( rmw_message ) )
213
+ Ok ( MessageInfo :: from_rmw_message_info ( & message_info ) )
190
214
}
191
215
}
192
216
@@ -233,19 +257,38 @@ where
233
257
}
234
258
235
259
fn execute ( & self ) -> Result < ( ) , RclrsError > {
236
- let msg = match self . take ( ) {
237
- Ok ( msg) => msg,
260
+ // Immediately evaluated closure, to handle SubscriptionTakeFailed
261
+ // outside this match
262
+ match ( || {
263
+ match & mut * self . callback . lock ( ) . unwrap ( ) {
264
+ AnySubscriptionCallback :: Regular ( cb) => {
265
+ let ( msg, _) = self . take ( ) ?;
266
+ cb ( msg)
267
+ }
268
+ AnySubscriptionCallback :: Boxed ( cb) => {
269
+ let ( msg, _) = self . take_boxed ( ) ?;
270
+ cb ( msg)
271
+ }
272
+ AnySubscriptionCallback :: RegularWithMessageInfo ( cb) => {
273
+ let ( msg, msg_info) = self . take ( ) ?;
274
+ cb ( msg, msg_info)
275
+ }
276
+ AnySubscriptionCallback :: BoxedWithMessageInfo ( cb) => {
277
+ let ( msg, msg_info) = self . take_boxed ( ) ?;
278
+ cb ( msg, msg_info)
279
+ }
280
+ }
281
+ Ok ( ( ) )
282
+ } ) ( ) {
238
283
Err ( RclrsError :: RclError {
239
284
code : RclReturnCode :: SubscriptionTakeFailed ,
240
285
..
241
286
} ) => {
242
287
// Spurious wakeup – this may happen even when a waitset indicated that this
243
288
// subscription was ready, so it shouldn't be an error.
244
- return Ok ( ( ) ) ;
289
+ Ok ( ( ) )
245
290
}
246
- Err ( e) => return Err ( e) ,
247
- } ;
248
- ( * self . callback . lock ( ) . unwrap ( ) ) ( msg) ;
249
- Ok ( ( ) )
291
+ other => other,
292
+ }
250
293
}
251
294
}
0 commit comments