@@ -3,7 +3,7 @@ use crate::{
3
3
error:: { RclReturnCode , ToResult } ,
4
4
rcl_bindings:: * ,
5
5
wait:: WaitableNumEntities ,
6
- Clock , DropGuard , Node , RclrsError , ENTITY_LIFECYCLE_MUTEX ,
6
+ Clock , DropGuard , Node , NodeHandle , RclrsError , ENTITY_LIFECYCLE_MUTEX ,
7
7
} ;
8
8
use rosidl_runtime_rs:: { Action , ActionImpl , Message , Service } ;
9
9
use std:: {
@@ -23,7 +23,7 @@ unsafe impl Send for rcl_action_server_t {}
23
23
/// [1]: <https://doc.rust-lang.org/reference/destructors.html>
24
24
pub struct ActionServerHandle {
25
25
rcl_action_server : Mutex < rcl_action_server_t > ,
26
- node : Node ,
26
+ node_handle : Arc < NodeHandle > ,
27
27
pub ( crate ) in_use_by_wait_set : Arc < AtomicBool > ,
28
28
}
29
29
@@ -36,7 +36,7 @@ impl ActionServerHandle {
36
36
impl Drop for ActionServerHandle {
37
37
fn drop ( & mut self ) {
38
38
let rcl_action_server = self . rcl_action_server . get_mut ( ) . unwrap ( ) ;
39
- let mut rcl_node = self . node . handle . rcl_node . lock ( ) . unwrap ( ) ;
39
+ let mut rcl_node = self . node_handle . rcl_node . lock ( ) . unwrap ( ) ;
40
40
let _lifecycle_lock = ENTITY_LIFECYCLE_MUTEX . lock ( ) . unwrap ( ) ;
41
41
// SAFETY: The entity lifecycle mutex is locked to protect against the risk of
42
42
// global variables in the rmw implementation being unsafely modified during cleanup.
@@ -69,7 +69,33 @@ pub type GoalCallback<ActionT> = dyn Fn(GoalUuid, <ActionT as rosidl_runtime_rs:
69
69
pub type CancelCallback < ActionT > = dyn Fn ( Arc < ServerGoalHandle < ActionT > > ) -> CancelResponse + ' static + Send + Sync ;
70
70
pub type AcceptedCallback < ActionT > = dyn Fn ( Arc < ServerGoalHandle < ActionT > > ) + ' static + Send + Sync ;
71
71
72
- pub struct ActionServer < ActionT >
72
+ /// An action server that can respond to requests sent by ROS action clients.
73
+ ///
74
+ /// Create an action server using [`Node::create_action_server`][1].
75
+ ///
76
+ /// ROS only supports having one server for any given fully-qualified
77
+ /// action name. "Fully-qualified" means the namespace is also taken into account
78
+ /// for uniqueness. A clone of an `ActionServer` will refer to the same server
79
+ /// instance as the original. The underlying instance is tied to [`ActionServerState`]
80
+ /// which implements the [`ActionServer`] API.
81
+ ///
82
+ /// Responding to requests requires the node's executor to [spin][2].
83
+ ///
84
+ /// [1]: crate::NodeState::create_action_server
85
+ /// [2]: crate::spin
86
+ pub type ActionServer < ActionT > = Arc < ActionServerState < ActionT > > ;
87
+
88
+ /// The inner state of an [`ActionServer`].
89
+ ///
90
+ /// This is public so that you can choose to create a [`Weak`][1] reference to it
91
+ /// if you want to be able to refer to a [`ActionServer`] in a non-owning way. It is
92
+ /// generally recommended to manage the `ActionServerState` inside of an [`Arc`],
93
+ /// and [`ActionServer`] is provided as a convenience alias for that.
94
+ ///
95
+ /// The public API of the [`ActionServer`] type is implemented via `ActionServerState`.
96
+ ///
97
+ /// [1]: std::sync::Weak
98
+ pub struct ActionServerState < ActionT >
73
99
where
74
100
ActionT : rosidl_runtime_rs:: Action + rosidl_runtime_rs:: ActionImpl ,
75
101
{
@@ -83,16 +109,19 @@ where
83
109
goal_handles : Mutex < HashMap < GoalUuid , Arc < ServerGoalHandle < ActionT > > > > ,
84
110
goal_results : Mutex < HashMap < GoalUuid , <<ActionT :: GetResultService as Service >:: Response as Message >:: RmwMsg > > ,
85
111
result_requests : Mutex < HashMap < GoalUuid , Vec < rmw_request_id_t > > > ,
112
+ /// Ensure the parent node remains alive as long as the subscription is held.
113
+ /// This implementation will change in the future.
114
+ #[ allow( unused) ]
115
+ node : Node ,
86
116
}
87
117
88
- impl < T > ActionServer < T >
118
+ impl < T > ActionServerState < T >
89
119
where
90
120
T : rosidl_runtime_rs:: Action + rosidl_runtime_rs:: ActionImpl ,
91
121
{
92
122
/// Creates a new action server.
93
123
pub ( crate ) fn new (
94
124
node : & Node ,
95
- clock : Clock ,
96
125
topic : & str ,
97
126
goal_callback : impl Fn ( GoalUuid , T :: Goal ) -> GoalResponse + ' static + Send + Sync ,
98
127
cancel_callback : impl Fn ( Arc < ServerGoalHandle < T > > ) -> CancelResponse + ' static + Send + Sync ,
@@ -114,13 +143,14 @@ where
114
143
115
144
{
116
145
let mut rcl_node = node. handle . rcl_node . lock ( ) . unwrap ( ) ;
146
+ let clock = node. get_clock ( ) ;
117
147
let rcl_clock = clock. rcl_clock ( ) ;
118
148
let mut rcl_clock = rcl_clock. lock ( ) . unwrap ( ) ;
119
149
let _lifecycle_lock = ENTITY_LIFECYCLE_MUTEX . lock ( ) . unwrap ( ) ;
120
150
121
151
// SAFETY:
122
152
// * The rcl_action_server is zero-initialized as mandated by this function.
123
- // * The rcl_node is kept alive by the Node because it is a dependency of the action server.
153
+ // * The rcl_node is kept alive by the NodeHandle because it is a dependency of the action server.
124
154
// * The topic name and the options are copied by this function, so they can be dropped
125
155
// afterwards.
126
156
// * The entity lifecycle mutex is locked to protect against the risk of global
@@ -140,7 +170,7 @@ where
140
170
141
171
let handle = Arc :: new ( ActionServerHandle {
142
172
rcl_action_server : Mutex :: new ( rcl_action_server) ,
143
- node : node . clone ( ) ,
173
+ node_handle : Arc :: clone ( & node . handle ) ,
144
174
in_use_by_wait_set : Arc :: new ( AtomicBool :: new ( false ) ) ,
145
175
} ) ;
146
176
@@ -166,6 +196,7 @@ where
166
196
goal_handles : Mutex :: new ( HashMap :: new ( ) ) ,
167
197
goal_results : Mutex :: new ( HashMap :: new ( ) ) ,
168
198
result_requests : Mutex :: new ( HashMap :: new ( ) ) ,
199
+ node : node. clone ( ) ,
169
200
} )
170
201
}
171
202
@@ -684,7 +715,7 @@ where
684
715
}
685
716
}
686
717
687
- impl < T > ActionServerBase for ActionServer < T >
718
+ impl < T > ActionServerBase for ActionServerState < T >
688
719
where
689
720
T : rosidl_runtime_rs:: Action + rosidl_runtime_rs:: ActionImpl ,
690
721
{
0 commit comments