1
1
use crate :: rcl_bindings:: * ;
2
2
use std:: error:: Error ;
3
+ use std:: ffi:: CStr ;
3
4
use std:: fmt:: { self , Display } ;
4
5
6
+ /// The main error type.
7
+ #[ derive( Debug , PartialEq ) ]
8
+ pub struct RclrsError {
9
+ /// The error code.
10
+ pub code : RclReturnCode ,
11
+ /// The error message set in the rcl layer or below.
12
+ pub ( crate ) msg : Option < RclErrorMsg > ,
13
+ }
14
+
15
+ impl Display for RclrsError {
16
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
17
+ write ! ( f, "{}" , self . code)
18
+ }
19
+ }
20
+
21
+ /// Struct encapsulating an error message from the rcl layer or below.
22
+ ///
23
+ /// This struct is intended to be returned by the `source` method in the implementation of the
24
+ /// standard [`Error`][1] trait for [`RclrsError`][2].
25
+ /// By doing this, the error message is printed as a separate item in the error chain.
26
+ /// This avoids an unreadable, inconsistent formatting of error codes and messages that would
27
+ /// likely be produced by a combined display of `RclReturnCode` and message.
28
+ ///
29
+ /// [1]: std::error::Error
30
+ /// [2]: crate::RclrsError
31
+ #[ derive( Debug , PartialEq ) ]
32
+ pub ( crate ) struct RclErrorMsg ( String ) ;
33
+
34
+ impl Display for RclErrorMsg {
35
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
36
+ write ! ( f, "{}" , self . 0 )
37
+ }
38
+ }
39
+
40
+ impl Error for RclErrorMsg { }
41
+
42
+ impl Error for RclrsError {
43
+ fn source ( & self ) -> Option < & ( dyn Error + ' static ) > {
44
+ self . msg . as_ref ( ) . map ( |e| e as & dyn Error )
45
+ }
46
+ }
47
+
5
48
/// RCL specific error codes.
6
49
///
7
50
/// These are the error codes that start at 100.
@@ -42,19 +85,19 @@ impl TryFrom<i32> for RclErrorCode {
42
85
impl Display for RclErrorCode {
43
86
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
44
87
match self {
45
- Self :: AlreadyInit => write ! ( f, "RclError: `rcl_init()` already called! " ) ,
46
- Self :: NotInit => write ! ( f, "RclError: `rcl_init() not yet called! " ) ,
47
- Self :: MismatchedRmwId => write ! ( f, "RclError: Mismatched rmw identifier! " ) ,
88
+ Self :: AlreadyInit => write ! ( f, "RclError: `rcl_init()` already called. " ) ,
89
+ Self :: NotInit => write ! ( f, "RclError: `rcl_init() not yet called. " ) ,
90
+ Self :: MismatchedRmwId => write ! ( f, "RclError: Mismatched rmw identifier. " ) ,
48
91
Self :: TopicNameInvalid => {
49
- write ! ( f, "RclError: Topic name does not pass validation! " )
92
+ write ! ( f, "RclError: Topic name does not pass validation. " )
50
93
}
51
94
Self :: ServiceNameInvalid => {
52
- write ! ( f, "RclError: Service name does not pass validation! " )
95
+ write ! ( f, "RclError: Service name does not pass validation. " )
53
96
}
54
97
Self :: UnknownSubstitution => {
55
- write ! ( f, "RclError: Topic name substitution is unknown! " )
98
+ write ! ( f, "RclError: Topic name substitution is unknown. " )
56
99
}
57
- Self :: AlreadyShutdown => write ! ( f, "RclError: `rcl_shutdown()` already called! " ) ,
100
+ Self :: AlreadyShutdown => write ! ( f, "RclError: `rcl_shutdown()` already called. " ) ,
58
101
}
59
102
}
60
103
}
@@ -90,10 +133,10 @@ impl TryFrom<i32> for NodeErrorCode {
90
133
impl Display for NodeErrorCode {
91
134
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
92
135
match self {
93
- Self :: NodeInvalid => write ! ( f, "NodeError: Invalid `rcl_node_t` given! " ) ,
94
- Self :: NodeInvalidName => write ! ( f, "NodeError: Invalid node name! " ) ,
95
- Self :: NodeInvalidNamespace => write ! ( f, "NodeError: Invalid node namespace! " ) ,
96
- Self :: NodeNameNonexistent => write ! ( f, "NodeError: Failed to find node name! " ) ,
136
+ Self :: NodeInvalid => write ! ( f, "NodeError: Invalid `rcl_node_t` given. " ) ,
137
+ Self :: NodeInvalidName => write ! ( f, "NodeError: Invalid node name. " ) ,
138
+ Self :: NodeInvalidNamespace => write ! ( f, "NodeError: Invalid node namespace. " ) ,
139
+ Self :: NodeNameNonexistent => write ! ( f, "NodeError: Failed to find node name. " ) ,
97
140
}
98
141
}
99
142
}
@@ -124,11 +167,11 @@ impl Display for SubscriberErrorCode {
124
167
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
125
168
match self {
126
169
Self :: SubscriptionInvalid => {
127
- write ! ( f, "SubscriberError: Invalid `rcl_subscription_t` given! " )
170
+ write ! ( f, "SubscriberError: Invalid `rcl_subscription_t` given. " )
128
171
}
129
172
Self :: SubscriptionTakeFailed => write ! (
130
173
f,
131
- "SubscriberError: Failed to take a message from the subscription! "
174
+ "SubscriberError: Failed to take a message from the subscription. "
132
175
) ,
133
176
}
134
177
}
@@ -158,9 +201,9 @@ impl TryFrom<i32> for ClientErrorCode {
158
201
impl Display for ClientErrorCode {
159
202
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
160
203
match self {
161
- Self :: ClientInvalid => write ! ( f, "ClientError: Invalid `rcl_client_t` given! " ) ,
204
+ Self :: ClientInvalid => write ! ( f, "ClientError: Invalid `rcl_client_t` given. " ) ,
162
205
Self :: ClientTakeFailed => {
163
- write ! ( f, "ClientError: Failed to take a response from the client! " )
206
+ write ! ( f, "ClientError: Failed to take a response from the client. " )
164
207
}
165
208
}
166
209
}
@@ -191,10 +234,10 @@ impl TryFrom<i32> for ServiceErrorCode {
191
234
impl Display for ServiceErrorCode {
192
235
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
193
236
match self {
194
- Self :: ServiceInvalid => write ! ( f, "ServiceError: Invalid `rcl_service_t` given! " ) ,
237
+ Self :: ServiceInvalid => write ! ( f, "ServiceError: Invalid `rcl_service_t` given. " ) ,
195
238
Self :: ServiceTakeFailed => write ! (
196
239
f,
197
- "ServiceError: Failed to take a request from the service! "
240
+ "ServiceError: Failed to take a request from the service. "
198
241
) ,
199
242
}
200
243
}
@@ -228,8 +271,8 @@ impl TryFrom<i32> for TimerErrorCode {
228
271
impl Display for TimerErrorCode {
229
272
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
230
273
match self {
231
- Self :: TimerInvalid => write ! ( f, "TimerError: Invalid `rcl_timer_t` given! " ) ,
232
- Self :: TimerCanceled => write ! ( f, "TimerError: Given timer was canceled! " ) ,
274
+ Self :: TimerInvalid => write ! ( f, "TimerError: Invalid `rcl_timer_t` given. " ) ,
275
+ Self :: TimerCanceled => write ! ( f, "TimerError: Given timer was canceled. " ) ,
233
276
}
234
277
}
235
278
}
@@ -262,9 +305,9 @@ impl TryFrom<i32> for WaitSetErrorCode {
262
305
impl Display for WaitSetErrorCode {
263
306
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
264
307
match self {
265
- Self :: WaitSetInvalid => write ! ( f, "WaitSetError: Invalid `rcl_wait_set_t` given! " ) ,
266
- Self :: WaitSetEmpty => write ! ( f, "WaitSetError: Given `rcl_wait_set_t` was empty! " ) ,
267
- Self :: WaitSetFull => write ! ( f, "WaitSetError: Given `rcl_wait_set_t` was full! " ) ,
308
+ Self :: WaitSetInvalid => write ! ( f, "WaitSetError: Invalid `rcl_wait_set_t` given. " ) ,
309
+ Self :: WaitSetEmpty => write ! ( f, "WaitSetError: Given `rcl_wait_set_t` was empty. " ) ,
310
+ Self :: WaitSetFull => write ! ( f, "WaitSetError: Given `rcl_wait_set_t` was full. " ) ,
268
311
}
269
312
}
270
313
}
@@ -304,20 +347,20 @@ impl Display for ParsingErrorCode {
304
347
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
305
348
match self {
306
349
Self :: InvalidRemapRule => {
307
- write ! ( f, "ParsingError: Argument is not a valid remap rule! " )
350
+ write ! ( f, "ParsingError: Argument is not a valid remap rule. " )
308
351
}
309
352
Self :: WrongLexeme => write ! (
310
353
f,
311
- "ParsingError: Expected one type of lexeme, but got another! "
354
+ "ParsingError: Expected one type of lexeme, but got another. "
312
355
) ,
313
356
Self :: InvalidRosArgs => {
314
- write ! ( f, "ParsingError: Found invalid ros argument while parsing! " )
357
+ write ! ( f, "ParsingError: Found invalid ROS argument while parsing. " )
315
358
}
316
359
Self :: InvalidParamRule => {
317
- write ! ( f, "ParsingError: Argument is not a valid parameter rule! " )
360
+ write ! ( f, "ParsingError: Argument is not a valid parameter rule. " )
318
361
}
319
362
Self :: InvalidLogLevelRule => {
320
- write ! ( f, "ParsingError: Argument is not a valid log level rule! " )
363
+ write ! ( f, "ParsingError: Argument is not a valid log level rule. " )
321
364
}
322
365
}
323
366
}
@@ -348,10 +391,10 @@ impl TryFrom<i32> for EventErrorCode {
348
391
impl Display for EventErrorCode {
349
392
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
350
393
match self {
351
- Self :: EventInvalid => write ! ( f, "EventError: Invalid `rcl_event_t` given! " ) ,
394
+ Self :: EventInvalid => write ! ( f, "EventError: Invalid `rcl_event_t` given. " ) ,
352
395
Self :: EventTakeFailed => write ! (
353
396
f,
354
- "EventError: Failed to take an event from the event handle! "
397
+ "EventError: Failed to take an event from the event handle. "
355
398
) ,
356
399
}
357
400
}
@@ -385,10 +428,10 @@ impl Display for LifecycleErrorCode {
385
428
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
386
429
match self {
387
430
Self :: LifecycleStateRegistered => {
388
- write ! ( f, "LifecycleError: `rcl_lifecycle` state registered! " )
431
+ write ! ( f, "LifecycleError: `rcl_lifecycle` state registered. " )
389
432
}
390
433
Self :: LifecycleStateNotRegistered => {
391
- write ! ( f, "LifecycleError: `rcl_lifecycle` state not registered! " )
434
+ write ! ( f, "LifecycleError: `rcl_lifecycle` state not registered. " )
392
435
}
393
436
}
394
437
}
@@ -555,18 +598,18 @@ impl From<LifecycleErrorCode> for RclReturnCode {
555
598
impl Display for RclReturnCode {
556
599
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
557
600
match self {
558
- Self :: Ok => write ! ( f, "RclReturnCode: Operation successful! " ) ,
559
- Self :: Error => write ! ( f, "RclReturnCode: Unspecified error! " ) ,
560
- Self :: Timeout => write ! ( f, "RclReturnCode: Timeout occurred! " ) ,
561
- Self :: Unsupported => write ! ( f, "RclReturnCode: Unsupported return code! " ) ,
562
- Self :: BadAlloc => write ! ( f, "RclReturnCode: Failed to allocate memory! " ) ,
601
+ Self :: Ok => write ! ( f, "RclReturnCode: Operation successful. " ) ,
602
+ Self :: Error => write ! ( f, "RclReturnCode: Unspecified error. " ) ,
603
+ Self :: Timeout => write ! ( f, "RclReturnCode: Timeout occurred. " ) ,
604
+ Self :: Unsupported => write ! ( f, "RclReturnCode: Unsupported return code. " ) ,
605
+ Self :: BadAlloc => write ! ( f, "RclReturnCode: Failed to allocate memory. " ) ,
563
606
Self :: InvalidArgument => {
564
- write ! ( f, "RclReturnCode: Argument to function was invalid! " )
607
+ write ! ( f, "RclReturnCode: Argument to function was invalid. " )
565
608
}
566
609
Self :: RclError ( rcl_err) => write ! ( f, "RclReturnCode::{}" , rcl_err) ,
567
610
Self :: NodeError ( node_err) => write ! ( f, "RclReturnCode::{}" , node_err) ,
568
611
Self :: PublisherInvalid => {
569
- write ! ( f, "RclReturnCode: Invalid `rcl_publisher_t` given! " )
612
+ write ! ( f, "RclReturnCode: Invalid `rcl_publisher_t` given. " )
570
613
}
571
614
Self :: SubscriberError ( subscriber_err) => {
572
615
write ! ( f, "RclReturnCode::{}" , subscriber_err)
@@ -589,27 +632,40 @@ impl Display for RclReturnCode {
589
632
590
633
impl Error for RclReturnCode { }
591
634
592
- pub ( crate ) fn to_rcl_result ( code : i32 ) -> Result < ( ) , RclReturnCode > {
635
+ pub ( crate ) fn to_rcl_result ( code : i32 ) -> Result < ( ) , RclrsError > {
593
636
match RclReturnCode :: from ( code) {
594
637
RclReturnCode :: Ok => Ok ( ( ) ) ,
595
638
anything_else => {
639
+ let mut msg = None ;
640
+ // SAFETY: No preconditions for this function.
641
+ let error_state_ptr = unsafe { rcutils_get_error_state ( ) } ;
642
+ // The returned pointer may be null if the error state has not been set.
643
+ if !error_state_ptr. is_null ( ) {
644
+ // SAFETY: Dereferencing the pointer is safe since it was checked to be non-null.
645
+ let msg_ptr = unsafe { ( * error_state_ptr) . message . as_ptr ( ) } ;
646
+ // SAFETY: Pointer has been created from an array, no lifetime issues due to
647
+ // immediate conversion to owned string.
648
+ let s = unsafe { CStr :: from_ptr ( msg_ptr) }
649
+ . to_string_lossy ( )
650
+ . into_owned ( ) ;
651
+ msg = Some ( RclErrorMsg ( s) ) ;
652
+ }
596
653
// SAFETY: No preconditions for this function.
597
654
unsafe { rcutils_reset_error ( ) } ;
598
- Err ( anything_else)
655
+ Err ( RclrsError {
656
+ code : anything_else,
657
+ msg,
658
+ } )
599
659
}
600
660
}
601
661
}
602
662
603
663
pub ( crate ) trait ToResult {
604
- fn ok ( & self ) -> Result < ( ) , RclReturnCode > ;
605
-
606
- fn unwrap ( & self ) {
607
- self . ok ( ) . unwrap ( ) ;
608
- }
664
+ fn ok ( & self ) -> Result < ( ) , RclrsError > ;
609
665
}
610
666
611
667
impl ToResult for rcl_ret_t {
612
- fn ok ( & self ) -> Result < ( ) , RclReturnCode > {
668
+ fn ok ( & self ) -> Result < ( ) , RclrsError > {
613
669
to_rcl_result ( * self as i32 )
614
670
}
615
671
}
0 commit comments