Skip to content

Commit 37d5e77

Browse files
committed
Streamline API for Timer
Signed-off-by: Michael X. Grey <[email protected]>
1 parent 30a6717 commit 37d5e77

File tree

6 files changed

+637
-237
lines changed

6 files changed

+637
-237
lines changed

rclrs/src/error.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ pub enum RclrsError {
3232
},
3333
/// It was attempted to add a waitable to a wait set twice.
3434
AlreadyAddedToWaitSet,
35+
/// A negative duration was obtained from rcl which should have been positive.
36+
///
37+
/// The value represents nanoseconds.
38+
NegativeDuration(i64),
3539
}
3640

3741
impl Display for RclrsError {
@@ -48,6 +52,9 @@ impl Display for RclrsError {
4852
"Could not add entity to wait set because it was already added to a wait set"
4953
)
5054
}
55+
RclrsError::NegativeDuration(duration) => {
56+
write!(f, "A duration was negative when it should not have been: {duration:?}")
57+
}
5158
}
5259
}
5360
}
@@ -80,6 +87,7 @@ impl Error for RclrsError {
8087
RclrsError::UnknownRclError { msg, .. } => msg.as_ref().map(|e| e as &dyn Error),
8188
RclrsError::StringContainsNul { err, .. } => Some(err).map(|e| e as &dyn Error),
8289
RclrsError::AlreadyAddedToWaitSet => None,
90+
RclrsError::NegativeDuration(_) => None,
8391
}
8492
}
8593
}

rclrs/src/node.rs

Lines changed: 65 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ use crate::{
1616
rcl_bindings::*, Client, ClientBase, Clock, Context, ContextHandle, GuardCondition, LogParams,
1717
Logger, ParameterBuilder, ParameterInterface, ParameterVariant, Parameters, Publisher,
1818
QoSProfile, RclrsError, Service, ServiceBase, Subscription, SubscriptionBase,
19-
SubscriptionCallback, TimeSource, Timer, TimerCallback, ToLogParams, ENTITY_LIFECYCLE_MUTEX,
19+
SubscriptionCallback, TimeSource, Timer, IntoTimerOptions, AnyTimerCallback,
20+
TimerCallRepeating, TimerCallOnce, ToLogParams, ENTITY_LIFECYCLE_MUTEX,
2021
};
2122

2223
// SAFETY: The functions accessing this type, including drop(), shouldn't care about the thread
@@ -341,22 +342,23 @@ impl Node {
341342
Ok(subscription)
342343
}
343344

344-
/// Creates a [`Timer`][1].
345+
/// Creates a [`Timer`].
346+
///
347+
/// For more ergonomic usage see also:
348+
/// * [`Self::create_timer_repeating`]
349+
/// * [`Self::create_timer_oneshot`]
350+
/// * [`Self::create_timer_inert`]
345351
///
346-
/// [1]: crate::Timer
347352
/// TODO: make timer's lifetime depend on node's lifetime.
348-
pub fn create_timer(
353+
pub fn create_timer<'a>(
349354
&self,
350-
period_ns: i64,
351-
context: &Context,
352-
callback: Option<TimerCallback>,
353-
clock: Option<Clock>,
355+
options: impl IntoTimerOptions<'a>,
356+
callback: AnyTimerCallback,
354357
) -> Result<Arc<Timer>, RclrsError> {
355-
let clock_used = match clock {
356-
Some(value) => value,
357-
None => self.get_clock(),
358-
};
359-
let timer = Timer::new(&clock_used, &context, period_ns, callback)?;
358+
let options = options.into_timer_options();
359+
let clock = options.clock.as_clock(self);
360+
361+
let timer = Timer::new(&self.handle.context_handle, options.period, clock, callback)?;
360362
let timer = Arc::new(timer);
361363
self.timers_mtx
362364
.lock()
@@ -365,6 +367,48 @@ impl Node {
365367
Ok(timer)
366368
}
367369

370+
/// Create a [`Timer`] with a repeating callback.
371+
///
372+
/// See also:
373+
/// * [`Self::create_timer_oneshot`]
374+
/// * [`Self::create_timer_inert`]
375+
pub fn create_timer_repeating<'a, Args>(
376+
&self,
377+
options: impl IntoTimerOptions<'a>,
378+
callback: impl TimerCallRepeating<Args>,
379+
) -> Result<Arc<Timer>, RclrsError> {
380+
self.create_timer(options, callback.into_repeating_timer_callback())
381+
}
382+
383+
/// Create a [`Timer`] whose callback will be triggered once after the period
384+
/// of the timer has elapsed. After that you will need to use
385+
/// [`Timer::set_callback`] or a related method or else nothing will happen
386+
/// the following times that the `Timer` elapses.
387+
///
388+
/// See also:
389+
/// * [`Self::create_timer_repeating`]
390+
/// * [`Self::create_time_inert`]
391+
pub fn create_timer_oneshot<'a, Args>(
392+
&self,
393+
options: impl IntoTimerOptions<'a>,
394+
callback: impl TimerCallOnce<Args>,
395+
) -> Result<Arc<Timer>, RclrsError> {
396+
self.create_timer(options, callback.into_oneshot_timer_callback())
397+
}
398+
399+
/// Create a [`Timer`] without a callback. Nothing will happen when this
400+
/// `Timer` elapses until you use [`Timer::set_callback`] or a related method.
401+
///
402+
/// See also:
403+
/// * [`Self::create_timer_repeating`]
404+
/// * [`Self::create_timer_oneshot`]
405+
pub fn create_timer_inert<'a>(
406+
&self,
407+
options: impl IntoTimerOptions<'a>,
408+
) -> Result<Arc<Timer>, RclrsError> {
409+
self.create_timer(options, AnyTimerCallback::None)
410+
}
411+
368412
/// Returns the subscriptions that have not been dropped yet.
369413
pub(crate) fn live_subscriptions(&self) -> Vec<Arc<dyn SubscriptionBase>> {
370414
{ self.subscriptions_mtx.lock().unwrap() }
@@ -532,6 +576,8 @@ mod tests {
532576
use super::*;
533577
use crate::test_helpers::*;
534578

579+
use std::time::Duration;
580+
535581
#[test]
536582
fn traits() {
537583
assert_send::<Node>();
@@ -585,15 +631,16 @@ mod tests {
585631

586632
#[test]
587633
fn test_create_timer_without_clock_source() -> Result<(), RclrsError> {
588-
let timer_period_ns: i64 = 1e6 as i64; // 1 millisecond.
589634
let context = Context::new([])?;
590-
let dut = NodeBuilder::new(&context, "node_with_timer")
635+
let node = NodeBuilder::new(&context, "node_with_timer")
591636
.namespace("test_create_timer")
592637
.build()?;
593638

594-
let _timer =
595-
dut.create_timer(timer_period_ns, &context, Some(Box::new(move |_| {})), None)?;
596-
assert_eq!(dut.live_timers().len(), 1);
639+
let _timer = node.create_timer_repeating(
640+
Duration::from_millis(1),
641+
|| { }
642+
)?;
643+
assert_eq!(node.live_timers().len(), 1);
597644

598645
Ok(())
599646
}

0 commit comments

Comments
 (0)