@@ -34,6 +34,33 @@ pub enum RclrsError {
34
34
AlreadyAddedToWaitSet ,
35
35
}
36
36
37
+ impl RclrsError {
38
+ /// Returns true if the error was due to a timeout, otherwise returns false.
39
+ pub fn is_timeout ( & self ) -> bool {
40
+ matches ! (
41
+ self ,
42
+ RclrsError :: RclError {
43
+ code: RclReturnCode :: Timeout ,
44
+ ..
45
+ }
46
+ )
47
+ }
48
+
49
+ /// Returns true if the error was because a subscription, service, or client
50
+ /// take failed, otherwise returns false.
51
+ pub fn is_take_failed ( & self ) -> bool {
52
+ matches ! (
53
+ self ,
54
+ RclrsError :: RclError {
55
+ code: RclReturnCode :: SubscriptionTakeFailed
56
+ | RclReturnCode :: ServiceTakeFailed
57
+ | RclReturnCode :: ClientTakeFailed ,
58
+ ..
59
+ }
60
+ )
61
+ }
62
+ }
63
+
37
64
impl Display for RclrsError {
38
65
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
39
66
match self {
@@ -355,27 +382,77 @@ impl ToResult for rcl_ret_t {
355
382
356
383
/// A helper trait to disregard timeouts as not an error.
357
384
pub trait RclrsErrorFilter {
385
+ /// Get the first error available, or Ok(()) if there are no errors.
386
+ fn first_error ( self ) -> Result < ( ) , RclrsError > ;
387
+
358
388
/// If the result was a timeout error, change it to `Ok(())`.
359
- fn timeout_ok ( self ) -> Result < ( ) , RclrsError > ;
389
+ fn timeout_ok ( self ) -> Self ;
390
+
391
+ /// If a subscription, service, or client take failed, change the result
392
+ /// to be `Ok(())`.
393
+ fn take_failed_ok ( self ) -> Self ;
394
+
395
+ /// Some error types just indicate an early termination but do not indicate
396
+ /// that anything in the system has misbehaved. This filters out anything
397
+ /// that is part of the normal operation of rcl.
398
+ fn ignore_non_errors ( self ) -> Self
399
+ where
400
+ Self : Sized ,
401
+ {
402
+ self . timeout_ok ( ) . take_failed_ok ( )
403
+ }
360
404
}
361
405
362
406
impl RclrsErrorFilter for Result < ( ) , RclrsError > {
407
+ fn first_error ( self ) -> Result < ( ) , RclrsError > {
408
+ self
409
+ }
410
+
363
411
fn timeout_ok ( self ) -> Result < ( ) , RclrsError > {
364
412
match self {
365
413
Ok ( ( ) ) => Ok ( ( ) ) ,
366
414
Err ( err) => {
367
- if matches ! (
368
- err,
369
- RclrsError :: RclError {
370
- code: RclReturnCode :: Timeout ,
371
- ..
372
- }
373
- ) {
374
- return Ok ( ( ) ) ;
415
+ if err. is_timeout ( ) {
416
+ Ok ( ( ) )
417
+ } else {
418
+ Err ( err)
375
419
}
420
+ }
421
+ }
422
+ }
376
423
377
- Err ( err)
424
+ fn take_failed_ok ( self ) -> Result < ( ) , RclrsError > {
425
+ match self {
426
+ Err ( err) => {
427
+ if err. is_take_failed ( ) {
428
+ // Spurious wakeup - this may happen even when a waitset indicated that
429
+ // work was ready, so we won't report it as an error
430
+ Ok ( ( ) )
431
+ } else {
432
+ Err ( err)
433
+ }
378
434
}
435
+ other => other,
436
+ }
437
+ }
438
+ }
439
+
440
+ impl RclrsErrorFilter for Vec < RclrsError > {
441
+ fn first_error ( mut self ) -> Result < ( ) , RclrsError > {
442
+ if self . is_empty ( ) {
443
+ return Ok ( ( ) ) ;
379
444
}
445
+
446
+ Err ( self . remove ( 0 ) )
447
+ }
448
+
449
+ fn timeout_ok ( mut self ) -> Self {
450
+ self . retain ( |err| !err. is_timeout ( ) ) ;
451
+ self
452
+ }
453
+
454
+ fn take_failed_ok ( mut self ) -> Self {
455
+ self . retain ( |err| !err. is_take_failed ( ) ) ;
456
+ self
380
457
}
381
458
}
0 commit comments