@@ -25,6 +25,44 @@ pub enum CancelResponse {
25
25
Accept = 2 ,
26
26
}
27
27
28
+ // SAFETY: The functions accessing this type, including drop(), shouldn't care about the thread
29
+ // they are running in. Therefore, this type can be safely sent to another thread.
30
+ unsafe impl Send for rcl_action_client_t { }
31
+
32
+ // SAFETY: The functions accessing this type, including drop(), shouldn't care about the thread
33
+ // they are running in. Therefore, this type can be safely sent to another thread.
34
+ unsafe impl Send for rcl_action_server_t { }
35
+
36
+ /// Manage the lifecycle of an `rcl_action_client_t`, including managing its dependencies
37
+ /// on `rcl_node_t` and `rcl_context_t` by ensuring that these dependencies are
38
+ /// [dropped after][1] the `rcl_action_client_t`.
39
+ ///
40
+ /// [1]: <https://doc.rust-lang.org/reference/destructors.html>
41
+ pub struct ActionClientHandle {
42
+ rcl_action_client : Mutex < rcl_action_client_t > ,
43
+ node_handle : Arc < NodeHandle > ,
44
+ pub ( crate ) in_use_by_wait_set : Arc < AtomicBool > ,
45
+ }
46
+
47
+ impl ActionClientHandle {
48
+ pub ( crate ) fn lock ( & self ) -> MutexGuard < rcl_action_client_t > {
49
+ self . rcl_action_client . lock ( ) . unwrap ( )
50
+ }
51
+ }
52
+
53
+ impl Drop for ActionClientHandle {
54
+ fn drop ( & mut self ) {
55
+ let rcl_action_client = self . rcl_action_client . get_mut ( ) . unwrap ( ) ;
56
+ let mut rcl_node = self . node_handle . rcl_node . lock ( ) . unwrap ( ) ;
57
+ let _lifecycle_lock = ENTITY_LIFECYCLE_MUTEX . lock ( ) . unwrap ( ) ;
58
+ // SAFETY: The entity lifecycle mutex is locked to protect against the risk of
59
+ // global variables in the rmw implementation being unsafely modified during cleanup.
60
+ unsafe {
61
+ rcl_action_client_fini ( rcl_action_client, & mut * rcl_node) ;
62
+ }
63
+ }
64
+ }
65
+
28
66
/// Manage the lifecycle of an `rcl_action_server_t`, including managing its dependencies
29
67
/// on `rcl_node_t` and `rcl_context_t` by ensuring that these dependencies are
30
68
/// [dropped after][1] the `rcl_action_server_t`.
@@ -55,6 +93,16 @@ impl Drop for ActionServerHandle {
55
93
}
56
94
}
57
95
96
+ /// Trait to be implemented by concrete ActionClient structs.
97
+ ///
98
+ /// See [`ActionClient<T>`] for an example
99
+ pub trait ActionClientBase : Send + Sync {
100
+ /// Internal function to get a reference to the `rcl` handle.
101
+ fn handle ( & self ) -> & ActionClientHandle ;
102
+ // /// Tries to take a new request and run the callback with it.
103
+ // fn execute(&self) -> Result<(), RclrsError>;
104
+ }
105
+
58
106
/// Trait to be implemented by concrete ActionServer structs.
59
107
///
60
108
/// See [`ActionServer<T>`] for an example
@@ -69,7 +117,8 @@ pub struct ActionClient<T>
69
117
where
70
118
T : rosidl_runtime_rs:: Action ,
71
119
{
72
- _marker : PhantomData < T > ,
120
+ _marker : PhantomData < fn ( ) -> T > ,
121
+ pub ( crate ) handle : Arc < ActionClientHandle > ,
73
122
}
74
123
75
124
impl < T > ActionClient < T >
@@ -81,17 +130,68 @@ where
81
130
where
82
131
T : rosidl_runtime_rs:: Action ,
83
132
{
133
+ // SAFETY: Getting a zero-initialized value is always safe.
134
+ let mut rcl_action_client = unsafe { rcl_action_get_zero_initialized_client ( ) } ;
135
+ let type_support = <T as rosidl_runtime_rs:: Action >:: get_type_support ( )
136
+ as * const rosidl_action_type_support_t ;
137
+ let topic_c_string = CString :: new ( topic) . map_err ( |err| RclrsError :: StringContainsNul {
138
+ err,
139
+ s : topic. into ( ) ,
140
+ } ) ?;
141
+
142
+ // SAFETY: No preconditions for this function.
143
+ let action_client_options = unsafe { rcl_action_client_get_default_options ( ) } ;
144
+
145
+ {
146
+ let mut rcl_node = node_handle. rcl_node . lock ( ) . unwrap ( ) ;
147
+ let _lifecycle_lock = ENTITY_LIFECYCLE_MUTEX . lock ( ) . unwrap ( ) ;
148
+
149
+ // SAFETY:
150
+ // * The rcl_client was zero-initialized as expected by this function.
151
+ // * The rcl_node is kept alive by the NodeHandle because it is a dependency of the client.
152
+ // * The topic name and the options are copied by this function, so they can be dropped
153
+ // afterwards.
154
+ // * The entity lifecycle mutex is locked to protect against the risk of global
155
+ // variables in the rmw implementation being unsafely modified during initialization.
156
+ unsafe {
157
+ rcl_action_client_init (
158
+ & mut rcl_action_client,
159
+ & mut * rcl_node,
160
+ type_support,
161
+ topic_c_string. as_ptr ( ) ,
162
+ & action_client_options,
163
+ )
164
+ . ok ( ) ?;
165
+ }
166
+ }
167
+
168
+ let handle = Arc :: new ( ActionClientHandle {
169
+ rcl_action_client : Mutex :: new ( rcl_action_client) ,
170
+ node_handle,
171
+ in_use_by_wait_set : Arc :: new ( AtomicBool :: new ( false ) ) ,
172
+ } ) ;
173
+
84
174
Ok ( Self {
85
175
_marker : Default :: default ( ) ,
176
+ handle,
86
177
} )
87
178
}
88
179
}
89
180
181
+ impl < T > ActionClientBase for ActionClient < T >
182
+ where
183
+ T : rosidl_runtime_rs:: Action ,
184
+ {
185
+ fn handle ( & self ) -> & ActionClientHandle {
186
+ & self . handle
187
+ }
188
+ }
189
+
90
190
pub struct ActionServer < T >
91
191
where
92
192
T : rosidl_runtime_rs:: Action ,
93
193
{
94
- _marker : PhantomData < T > ,
194
+ _marker : PhantomData < fn ( ) -> T > ,
95
195
pub ( crate ) handle : Arc < ActionServerHandle > ,
96
196
// goal_callback: (),
97
197
// cancel_callback: (),
@@ -133,10 +233,10 @@ where
133
233
rcl_action_server_init (
134
234
& mut rcl_action_server,
135
235
& mut * rcl_node,
136
- todo ! ( ) ,
236
+ todo ! ( "pass in a rcl_clock_t" ) ,
137
237
type_support,
138
238
topic_c_string. as_ptr ( ) ,
139
- & action_server_options as * const _ ,
239
+ & action_server_options,
140
240
)
141
241
. ok ( ) ?;
142
242
}
@@ -155,6 +255,15 @@ where
155
255
}
156
256
}
157
257
258
+ impl < T > ActionServerBase for ActionServer < T >
259
+ where
260
+ T : rosidl_runtime_rs:: Action ,
261
+ {
262
+ fn handle ( & self ) -> & ActionServerHandle {
263
+ & self . handle
264
+ }
265
+ }
266
+
158
267
pub struct ServerGoalHandle < T >
159
268
where
160
269
T : rosidl_runtime_rs:: Action ,
0 commit comments