@@ -3,7 +3,7 @@ use crate::{
33 error:: { RclReturnCode , ToResult } ,
44 rcl_bindings:: * ,
55 wait:: WaitableNumEntities ,
6- Clock , DropGuard , Node , RclrsError , ENTITY_LIFECYCLE_MUTEX ,
6+ Clock , DropGuard , Node , NodeHandle , RclrsError , ENTITY_LIFECYCLE_MUTEX ,
77} ;
88use rosidl_runtime_rs:: { Action , ActionImpl , Message , Service } ;
99use std:: {
@@ -23,7 +23,7 @@ unsafe impl Send for rcl_action_server_t {}
2323/// [1]: <https://doc.rust-lang.org/reference/destructors.html>
2424pub struct ActionServerHandle {
2525 rcl_action_server : Mutex < rcl_action_server_t > ,
26- node : Node ,
26+ node_handle : Arc < NodeHandle > ,
2727 pub ( crate ) in_use_by_wait_set : Arc < AtomicBool > ,
2828}
2929
@@ -36,7 +36,7 @@ impl ActionServerHandle {
3636impl Drop for ActionServerHandle {
3737 fn drop ( & mut self ) {
3838 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 ( ) ;
4040 let _lifecycle_lock = ENTITY_LIFECYCLE_MUTEX . lock ( ) . unwrap ( ) ;
4141 // SAFETY: The entity lifecycle mutex is locked to protect against the risk of
4242 // 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:
6969pub type CancelCallback < ActionT > = dyn Fn ( Arc < ServerGoalHandle < ActionT > > ) -> CancelResponse + ' static + Send + Sync ;
7070pub type AcceptedCallback < ActionT > = dyn Fn ( Arc < ServerGoalHandle < ActionT > > ) + ' static + Send + Sync ;
7171
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 >
7399where
74100 ActionT : rosidl_runtime_rs:: Action + rosidl_runtime_rs:: ActionImpl ,
75101{
@@ -83,16 +109,19 @@ where
83109 goal_handles : Mutex < HashMap < GoalUuid , Arc < ServerGoalHandle < ActionT > > > > ,
84110 goal_results : Mutex < HashMap < GoalUuid , <<ActionT :: GetResultService as Service >:: Response as Message >:: RmwMsg > > ,
85111 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 ,
86116}
87117
88- impl < T > ActionServer < T >
118+ impl < T > ActionServerState < T >
89119where
90120 T : rosidl_runtime_rs:: Action + rosidl_runtime_rs:: ActionImpl ,
91121{
92122 /// Creates a new action server.
93123 pub ( crate ) fn new (
94124 node : & Node ,
95- clock : Clock ,
96125 topic : & str ,
97126 goal_callback : impl Fn ( GoalUuid , T :: Goal ) -> GoalResponse + ' static + Send + Sync ,
98127 cancel_callback : impl Fn ( Arc < ServerGoalHandle < T > > ) -> CancelResponse + ' static + Send + Sync ,
@@ -114,13 +143,14 @@ where
114143
115144 {
116145 let mut rcl_node = node. handle . rcl_node . lock ( ) . unwrap ( ) ;
146+ let clock = node. get_clock ( ) ;
117147 let rcl_clock = clock. rcl_clock ( ) ;
118148 let mut rcl_clock = rcl_clock. lock ( ) . unwrap ( ) ;
119149 let _lifecycle_lock = ENTITY_LIFECYCLE_MUTEX . lock ( ) . unwrap ( ) ;
120150
121151 // SAFETY:
122152 // * 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.
124154 // * The topic name and the options are copied by this function, so they can be dropped
125155 // afterwards.
126156 // * The entity lifecycle mutex is locked to protect against the risk of global
@@ -140,7 +170,7 @@ where
140170
141171 let handle = Arc :: new ( ActionServerHandle {
142172 rcl_action_server : Mutex :: new ( rcl_action_server) ,
143- node : node . clone ( ) ,
173+ node_handle : Arc :: clone ( & node . handle ) ,
144174 in_use_by_wait_set : Arc :: new ( AtomicBool :: new ( false ) ) ,
145175 } ) ;
146176
@@ -166,6 +196,7 @@ where
166196 goal_handles : Mutex :: new ( HashMap :: new ( ) ) ,
167197 goal_results : Mutex :: new ( HashMap :: new ( ) ) ,
168198 result_requests : Mutex :: new ( HashMap :: new ( ) ) ,
199+ node : node. clone ( ) ,
169200 } )
170201 }
171202
@@ -684,7 +715,7 @@ where
684715 }
685716}
686717
687- impl < T > ActionServerBase for ActionServer < T >
718+ impl < T > ActionServerBase for ActionServerState < T >
688719where
689720 T : rosidl_runtime_rs:: Action + rosidl_runtime_rs:: ActionImpl ,
690721{
0 commit comments