1
- use crate :: { rcl_bindings:: * , RclrsError } ;
1
+ use crate :: { rcl_bindings:: * , RclrsError , ToResult } ;
2
2
use std:: {
3
3
marker:: PhantomData ,
4
4
sync:: { Arc , Mutex } ,
@@ -10,13 +10,25 @@ unsafe impl Send for rcl_action_goal_handle_t {}
10
10
11
11
unsafe impl Sync for rcl_action_goal_handle_t { }
12
12
13
+ // Values defined by `action_msgs/msg/GoalStatus`
14
+ #[ repr( i8 ) ]
15
+ #[ derive( Debug , Clone , Hash , PartialEq , Eq ) ]
16
+ enum GoalStatus {
17
+ Unknown = 0 ,
18
+ Accepted = 1 ,
19
+ Executing = 2 ,
20
+ Canceling = 3 ,
21
+ Succeeded = 4 ,
22
+ Canceled = 5 ,
23
+ Aborted = 6 ,
24
+ }
25
+
13
26
pub struct ServerGoalHandle < T >
14
27
where
15
28
T : rosidl_runtime_rs:: Action ,
16
29
{
17
30
rcl_handle : Arc < Mutex < rcl_action_goal_handle_t > > ,
18
31
goal_request : Arc < T > ,
19
- _marker : PhantomData < T > ,
20
32
}
21
33
22
34
impl < T > ServerGoalHandle < T >
@@ -27,27 +39,104 @@ where
27
39
Self {
28
40
rcl_handle,
29
41
goal_request : Arc :: clone ( & goal_request) ,
30
- _marker : Default :: default ( ) ,
31
42
}
32
43
}
33
44
45
+ /// Returns the goal state.
46
+ fn get_state ( & self ) -> Result < GoalStatus , RclrsError > {
47
+ let mut state = GoalStatus :: Unknown as rcl_action_goal_state_t ;
48
+ {
49
+ let rcl_handle = self . rcl_handle . lock ( ) . unwrap ( ) ;
50
+ // SAFETY: The provided goal handle is properly initialized by construction.
51
+ unsafe { rcl_action_goal_handle_get_status ( & * rcl_handle, & mut state) . ok ( ) ? }
52
+ }
53
+ // SAFETY: state is initialized to a valid GoalStatus value and will only ever by set by
54
+ // rcl_action_goal_handle_get_status to a valid GoalStatus value.
55
+ Ok ( unsafe { std:: mem:: transmute ( state) } )
56
+ }
57
+
58
+ /// Returns whether the client has requested that this goal be cancelled.
34
59
pub fn is_canceling ( & self ) -> bool {
35
- false
60
+ self . get_state ( ) . unwrap ( ) == GoalStatus :: Canceling
36
61
}
37
62
63
+ /// Returns true if the goal is either pending or executing, or false if it has reached a
64
+ /// terminal state.
38
65
pub fn is_active ( & self ) -> bool {
39
- false
66
+ let rcl_handle = self . rcl_handle . lock ( ) . unwrap ( ) ;
67
+ // SAFETY: The provided goal handle is properly initialized by construction.
68
+ unsafe { rcl_action_goal_handle_is_active ( & * rcl_handle) }
40
69
}
41
70
71
+ /// Returns whether the goal is executing.
42
72
pub fn is_executing ( & self ) -> bool {
43
- false
73
+ self . get_state ( ) . unwrap ( ) == GoalStatus :: Executing
74
+ }
75
+
76
+ /// Attempt to perform the given goal state transition.
77
+ fn update_state ( & self , event : rcl_action_goal_event_t ) -> Result < ( ) , RclrsError > {
78
+ let mut rcl_handle = self . rcl_handle . lock ( ) . unwrap ( ) ;
79
+ // SAFETY: The provided goal handle is properly initialized by construction.
80
+ unsafe { rcl_action_update_goal_state ( & mut * rcl_handle, event) . ok ( ) }
81
+ }
82
+
83
+ pub fn abort ( & self , result : & T :: Result ) -> Result < ( ) , RclrsError > {
84
+ self . update_state ( rcl_action_goal_event_t:: GOAL_EVENT_ABORT ) ?;
85
+
86
+ // TODO: Invoke on_terminal_state callback
87
+ Ok ( ( ) )
44
88
}
45
89
46
90
pub fn succeed ( & self , result : & T :: Result ) -> Result < ( ) , RclrsError > {
91
+ self . update_state ( rcl_action_goal_event_t:: GOAL_EVENT_SUCCEED ) ?;
92
+
93
+ // TODO: Invoke on_terminal_state callback
47
94
Ok ( ( ) )
48
95
}
49
96
50
97
pub fn canceled ( & self , result : & T :: Result ) -> Result < ( ) , RclrsError > {
98
+ self . update_state ( rcl_action_goal_event_t:: GOAL_EVENT_CANCELED ) ?;
99
+
100
+ // TODO: Invoke on_terminal_state callback
101
+ Ok ( ( ) )
102
+ }
103
+
104
+ pub fn execute ( & self , result : & T :: Result ) -> Result < ( ) , RclrsError > {
105
+ self . update_state ( rcl_action_goal_event_t:: GOAL_EVENT_EXECUTE ) ?;
106
+
107
+ // TODO: Invoke on_executing callback
51
108
Ok ( ( ) )
52
109
}
110
+
111
+ /// Try canceling the goal if possible.
112
+ fn try_canceling ( & mut self ) -> Result < bool , RclrsError > {
113
+ let rcl_handle = self . rcl_handle . lock ( ) . unwrap ( ) ;
114
+
115
+ // If the goal is in a cancelable state, transition to canceling.
116
+ // SAFETY: The provided goal handle is properly initialized by construction.
117
+ let is_cancelable = unsafe { rcl_action_goal_handle_is_cancelable ( & * rcl_handle) } ;
118
+ if is_cancelable {
119
+ self . update_state ( rcl_action_goal_event_t:: GOAL_EVENT_CANCEL_GOAL ) ?;
120
+ }
121
+
122
+ // If the goal is canceling, transition to canceled.
123
+ if self . get_state ( ) ? == GoalStatus :: Canceling {
124
+ self . update_state ( rcl_action_goal_event_t:: GOAL_EVENT_CANCELED ) ?;
125
+ Ok ( true )
126
+ } else {
127
+ Ok ( false )
128
+ }
129
+ }
130
+ }
131
+
132
+ impl < T > Drop for ServerGoalHandle < T >
133
+ where
134
+ T : rosidl_runtime_rs:: Action ,
135
+ {
136
+ /// Cancel the goal if its handle is dropped without reaching a terminal state.
137
+ fn drop ( & mut self ) {
138
+ if self . try_canceling ( ) == Ok ( true ) {
139
+ // TODO: Invoke on_terminal_state callback
140
+ }
141
+ }
53
142
}
0 commit comments