diff --git a/README.md b/README.md index 945a9ea..2c04d19 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ pub struct DelayedMultiplier { impl DelayedMultiplier { pub fn input(&mut self, value: f64, scheduler: &Scheduler) { scheduler - .schedule_event_in(Duration::from_secs(1), Self::send, 2.0 * value) + .schedule_event(Duration::from_secs(1), Self::send, 2.0 * value) .unwrap(); } async fn send(&mut self, value: f64) { diff --git a/asynchronix/examples/espresso_machine.rs b/asynchronix/examples/espresso_machine.rs index 6e9af84..8167717 100644 --- a/asynchronix/examples/espresso_machine.rs +++ b/asynchronix/examples/espresso_machine.rs @@ -141,7 +141,7 @@ impl Controller { // Schedule the `stop_brew()` method and turn on the pump. self.stop_brew_key = Some( scheduler - .schedule_keyed_event_in(self.brew_time, Self::stop_brew, ()) + .schedule_keyed_event(self.brew_time, Self::stop_brew, ()) .unwrap(), ); self.pump_cmd.send(PumpCommand::On).await; @@ -274,7 +274,7 @@ impl Tank { let duration_until_empty = Duration::from_secs_f64(duration_until_empty); // Schedule the next update. - match scheduler.schedule_keyed_event_in(duration_until_empty, Self::set_empty, ()) { + match scheduler.schedule_keyed_event(duration_until_empty, Self::set_empty, ()) { Ok(set_empty_key) => { let state = TankDynamicState { last_volume_update: time, @@ -431,7 +431,7 @@ fn main() { assert_eq!(flow_rate.take(), Some(0.0)); // Interrupt the brew after 15s by pressing again the brew button. - simu.schedule_event_in( + simu.schedule_event( Duration::from_secs(15), Controller::brew_cmd, (), diff --git a/asynchronix/examples/stepper_motor.rs b/asynchronix/examples/stepper_motor.rs index a232d88..c9937db 100644 --- a/asynchronix/examples/stepper_motor.rs +++ b/asynchronix/examples/stepper_motor.rs @@ -174,7 +174,7 @@ impl Driver { // Schedule the next pulse. scheduler - .schedule_event_in(pulse_duration, Self::send_pulse, ()) + .schedule_event(pulse_duration, Self::send_pulse, ()) .unwrap(); } } @@ -224,7 +224,7 @@ fn main() { assert!(position.next().is_none()); // Start the motor in 2s with a PPS of 10Hz. - simu.schedule_event_in( + simu.schedule_event( Duration::from_secs(2), Driver::pulse_rate, 10.0, diff --git a/asynchronix/src/lib.rs b/asynchronix/src/lib.rs index 2ce3bac..76974d8 100644 --- a/asynchronix/src/lib.rs +++ b/asynchronix/src/lib.rs @@ -113,7 +113,7 @@ //! } //! impl Delay { //! pub fn input(&mut self, value: f64, scheduler: &Scheduler) { -//! scheduler.schedule_event_in(Duration::from_secs(1), Self::send, value).unwrap(); +//! scheduler.schedule_event(Duration::from_secs(1), Self::send, value).unwrap(); //! } //! //! async fn send(&mut self, value: f64) { @@ -184,7 +184,7 @@ //! # } //! # impl Delay { //! # pub fn input(&mut self, value: f64, scheduler: &Scheduler) { -//! # scheduler.schedule_event_in(Duration::from_secs(1), Self::send, value).unwrap(); +//! # scheduler.schedule_event(Duration::from_secs(1), Self::send, value).unwrap(); //! # } //! # async fn send(&mut self, value: f64) { // this method can be private //! # self.output.send(value).await; @@ -242,7 +242,7 @@ //! [`Simulation::send_event()`](simulation::Simulation::send_event) or //! [`Simulation::send_query()`](simulation::Simulation::send_query), //! 3. by scheduling events, using for instance -//! [`Simulation::schedule_event_in()`](simulation::Simulation::schedule_event_in). +//! [`Simulation::schedule_event()`](simulation::Simulation::schedule_event). //! //! Simulation outputs can be monitored using //! [`EventSlot`](simulation::EventSlot)s and @@ -275,7 +275,7 @@ //! # } //! # impl Delay { //! # pub fn input(&mut self, value: f64, scheduler: &Scheduler) { -//! # scheduler.schedule_event_in(Duration::from_secs(1), Self::send, value).unwrap(); +//! # scheduler.schedule_event(Duration::from_secs(1), Self::send, value).unwrap(); //! # } //! # async fn send(&mut self, value: f64) { // this method can be private //! # self.output.send(value).await; @@ -354,10 +354,10 @@ //! //! The first guarantee (and only the first) also extends to events scheduled //! from a simulation with a -//! [`Simulation::schedule_*()`](simulation::Simulation::schedule_event_at) -//! method: if the scheduler contains several events to be delivered at the same -//! time to the same model, these events will always be processed in the order -//! in which they were scheduled. +//! [`Simulation::schedule_*()`](simulation::Simulation::schedule_event) method: +//! if the scheduler contains several events to be delivered at the same time to +//! the same model, these events will always be processed in the order in which +//! they were scheduled. //! //! [actor_model]: https://en.wikipedia.org/wiki/Actor_model //! [pony]: https://www.ponylang.io/ diff --git a/asynchronix/src/simulation.rs b/asynchronix/src/simulation.rs index 2d7e22d..d3ff941 100644 --- a/asynchronix/src/simulation.rs +++ b/asynchronix/src/simulation.rs @@ -137,7 +137,7 @@ use recycle_box::{coerce_box, RecycleBox}; use crate::executor::Executor; use crate::model::{InputFn, Model, ReplierFn}; use crate::time::{ - self, EventKey, MonotonicTime, ScheduledEvent, SchedulerQueue, SchedulingError, + self, Deadline, EventKey, MonotonicTime, ScheduledEvent, SchedulerQueue, SchedulingError, TearableAtomicTime, }; use crate::util::futures::SeqFuture; @@ -156,8 +156,8 @@ use crate::util::sync_cell::SyncCell; /// itself, but also from models via the optional /// [`&Scheduler`][time::Scheduler] argument of input and replier port methods. /// Likewise, simulation time can be accessed with the [`Simulation::time()`] -/// method, or from models with the -/// [`Scheduler::time()`](time::Scheduler::time) method. +/// method, or from models with the [`Scheduler::time()`](time::Scheduler::time) +/// method. /// /// Events and queries can be scheduled immediately, *i.e.* for the current /// simulation time, using [`send_event()`](Simulation::send_event) and @@ -166,8 +166,8 @@ use crate::util::sync_cell::SyncCell; /// the case of queries, the response is returned. /// /// Events can also be scheduled at a future simulation time using one of the -/// [`schedule_*()`](Simulation::schedule_event_at) method. These methods queue -/// an event without blocking. +/// [`schedule_*()`](Simulation::schedule_event) method. These methods queue an +/// event without blocking. /// /// Finally, the [`Simulation`] instance manages simulation time. Calling /// [`step()`](Simulation::step) will increment simulation time until that of @@ -247,10 +247,10 @@ impl Simulation { /// Events scheduled for the same time and targeting the same model are /// guaranteed to be processed according to the scheduling order. /// - /// See also: [`time::Scheduler::schedule_event_at`]. - pub fn schedule_event_at( + /// See also: [`time::Scheduler::schedule_event`]. + pub fn schedule_event( &mut self, - time: MonotonicTime, + deadline: impl Deadline, func: F, arg: T, address: impl Into>, @@ -261,7 +261,9 @@ impl Simulation { T: Send + Clone + 'static, S: Send + 'static, { - if self.time.read() >= time { + let now = self.time(); + let time = deadline.into_time(now); + if now >= time { return Err(SchedulingError::InvalidScheduledTime); } time::schedule_event_at_unchecked(time, func, arg, address.into().0, &self.scheduler_queue); @@ -269,37 +271,6 @@ impl Simulation { Ok(()) } - /// Schedules an event at the lapse of the specified duration. - /// - /// An error is returned if the specified delay is null. - /// - /// Events scheduled for the same time and targeting the same model are - /// guaranteed to be processed according to the scheduling order. - /// - /// See also: [`time::Scheduler::schedule_event_in`]. - pub fn schedule_event_in( - &mut self, - delay: Duration, - func: F, - arg: T, - address: impl Into>, - ) -> Result<(), SchedulingError> - where - M: Model, - F: for<'a> InputFn<'a, M, T, S>, - T: Send + Clone + 'static, - S: Send + 'static, - { - if delay.is_zero() { - return Err(SchedulingError::InvalidScheduledTime); - } - let time = self.time.read() + delay; - - time::schedule_event_at_unchecked(time, func, arg, address.into().0, &self.scheduler_queue); - - Ok(()) - } - /// Schedules a cancellable event at a future time and returns an event key. /// /// An error is returned if the specified time is not in the future of the @@ -308,10 +279,10 @@ impl Simulation { /// Events scheduled for the same time and targeting the same model are /// guaranteed to be processed according to the scheduling order. /// - /// See also: [`time::Scheduler::schedule_keyed_event_at`]. - pub fn schedule_keyed_event_at( + /// See also: [`time::Scheduler::schedule_keyed_event`]. + pub fn schedule_keyed_event( &mut self, - time: MonotonicTime, + deadline: impl Deadline, func: F, arg: T, address: impl Into>, @@ -322,7 +293,9 @@ impl Simulation { T: Send + Clone + 'static, S: Send + 'static, { - if self.time.read() >= time { + let now = self.time(); + let time = deadline.into_time(now); + if now >= time { return Err(SchedulingError::InvalidScheduledTime); } let event_key = time::schedule_keyed_event_at_unchecked( @@ -336,44 +309,6 @@ impl Simulation { Ok(event_key) } - /// Schedules a cancellable event at the lapse of the specified duration and - /// returns an event key. - /// - /// An error is returned if the specified delay is null. - /// - /// Events scheduled for the same time and targeting the same model are - /// guaranteed to be processed according to the scheduling order. - /// - /// See also: [`time::Scheduler::schedule_keyed_event_in`]. - pub fn schedule_keyed_event_in( - &mut self, - delay: Duration, - func: F, - arg: T, - address: impl Into>, - ) -> Result - where - M: Model, - F: for<'a> InputFn<'a, M, T, S>, - T: Send + Clone + 'static, - S: Send + 'static, - { - if delay.is_zero() { - return Err(SchedulingError::InvalidScheduledTime); - } - let time = self.time.read() + delay; - - let event_key = time::schedule_keyed_event_at_unchecked( - time, - func, - arg, - address.into().0, - &self.scheduler_queue, - ); - - Ok(event_key) - } - /// Schedules a periodically recurring event at a future time. /// /// An error is returned if the specified time is not in the future of the @@ -382,10 +317,10 @@ impl Simulation { /// Events scheduled for the same time and targeting the same model are /// guaranteed to be processed according to the scheduling order. /// - /// See also: [`time::Scheduler::schedule_periodic_event_at`]. - pub fn schedule_periodic_event_at( + /// See also: [`time::Scheduler::schedule_periodic_event`]. + pub fn schedule_periodic_event( &mut self, - time: MonotonicTime, + deadline: impl Deadline, period: Duration, func: F, arg: T, @@ -397,7 +332,9 @@ impl Simulation { T: Send + Clone + 'static, S: Send + 'static, { - if self.time.read() >= time { + let now = self.time(); + let time = deadline.into_time(now); + if now >= time { return Err(SchedulingError::InvalidScheduledTime); } if period.is_zero() { @@ -415,50 +352,6 @@ impl Simulation { Ok(()) } - /// Schedules a periodically recurring event at the lapse of the specified - /// duration. - /// - /// An error is returned if the specified delay or the specified period are - /// null. - /// - /// Events scheduled for the same time and targeting the same model are - /// guaranteed to be processed according to the scheduling order. - /// - /// See also: [`time::Scheduler::schedule_periodic_event_in`]. - pub fn schedule_periodic_event_in( - &mut self, - delay: Duration, - period: Duration, - func: F, - arg: T, - address: impl Into>, - ) -> Result<(), SchedulingError> - where - M: Model, - F: for<'a> InputFn<'a, M, T, S> + Clone, - T: Send + Clone + 'static, - S: Send + 'static, - { - if delay.is_zero() { - return Err(SchedulingError::InvalidScheduledTime); - } - if period.is_zero() { - return Err(SchedulingError::NullRepetitionPeriod); - } - let time = self.time.read() + delay; - - time::schedule_periodic_event_at_unchecked( - time, - period, - func, - arg, - address.into().0, - &self.scheduler_queue, - ); - - Ok(()) - } - /// Schedules a cancellable, periodically recurring event at a future time /// and returns an event key. /// @@ -468,10 +361,10 @@ impl Simulation { /// Events scheduled for the same time and targeting the same model are /// guaranteed to be processed according to the scheduling order. /// - /// See also: [`time::Scheduler::schedule_periodic_keyed_event_at`]. - pub fn schedule_periodic_keyed_event_at( + /// See also: [`time::Scheduler::schedule_keyed_periodic_event`]. + pub fn schedule_keyed_periodic_event( &mut self, - time: MonotonicTime, + deadline: impl Deadline, period: Duration, func: F, arg: T, @@ -483,7 +376,9 @@ impl Simulation { T: Send + Clone + 'static, S: Send + 'static, { - if self.time.read() >= time { + let now = self.time(); + let time = deadline.into_time(now); + if now >= time { return Err(SchedulingError::InvalidScheduledTime); } if period.is_zero() { @@ -501,50 +396,6 @@ impl Simulation { Ok(event_key) } - /// Schedules a cancellable, periodically recurring event at the lapse of - /// the specified duration and returns an event key. - /// - /// An error is returned if the specified delay or the specified period are - /// null. - /// - /// Events scheduled for the same time and targeting the same model are - /// guaranteed to be processed according to the scheduling order. - /// - /// See also: [`time::Scheduler::schedule_periodic_keyed_event_in`]. - pub fn schedule_periodic_keyed_event_in( - &mut self, - delay: Duration, - period: Duration, - func: F, - arg: T, - address: impl Into>, - ) -> Result - where - M: Model, - F: for<'a> InputFn<'a, M, T, S> + Clone, - T: Send + Clone + 'static, - S: Send + 'static, - { - if delay.is_zero() { - return Err(SchedulingError::InvalidScheduledTime); - } - if period.is_zero() { - return Err(SchedulingError::NullRepetitionPeriod); - } - let time = self.time.read() + delay; - - let event_key = time::schedule_periodic_keyed_event_at_unchecked( - time, - period, - func, - arg, - address.into().0, - &self.scheduler_queue, - ); - - Ok(event_key) - } - /// Sends and processes an event, blocking until completion. /// /// Simulation time remains unchanged. diff --git a/asynchronix/src/time.rs b/asynchronix/src/time.rs index 5ff4dcd..dc63e5b 100644 --- a/asynchronix/src/time.rs +++ b/asynchronix/src/time.rs @@ -31,7 +31,7 @@ //! //! // Sets an alarm [input port]. //! pub fn set(&mut self, setting: MonotonicTime, scheduler: &Scheduler) { -//! if scheduler.schedule_event_at(setting, Self::ring, ()).is_err() { +//! if scheduler.schedule_event(setting, Self::ring, ()).is_err() { //! println!("The alarm clock can only be set for a future time"); //! } //! } @@ -55,4 +55,4 @@ pub(crate) use scheduler::{ schedule_periodic_event_at_unchecked, schedule_periodic_keyed_event_at_unchecked, ScheduledEvent, SchedulerQueue, }; -pub use scheduler::{EventKey, Scheduler, SchedulingError}; +pub use scheduler::{Deadline, EventKey, Scheduler, SchedulingError}; diff --git a/asynchronix/src/time/scheduler.rs b/asynchronix/src/time/scheduler.rs index af5dac8..4f4cf9b 100644 --- a/asynchronix/src/time/scheduler.rs +++ b/asynchronix/src/time/scheduler.rs @@ -23,6 +23,30 @@ use crate::util::sync_cell::SyncCellReader; /// Shorthand for the scheduler queue type. pub(crate) type SchedulerQueue = PriorityQueue<(MonotonicTime, ChannelId), Box>; +/// Trait abstracting over time-absolute and time-relative deadlines. +/// +/// This trait is implemented by [`std::time::Duration`] and +/// [`MonotonicTime`]. +pub trait Deadline { + /// Make this deadline into an absolute timestamp, using the provided + /// current time as a reference. + fn into_time(self, now: MonotonicTime) -> MonotonicTime; +} + +impl Deadline for Duration { + #[inline(always)] + fn into_time(self, now: MonotonicTime) -> MonotonicTime { + now + self + } +} + +impl Deadline for MonotonicTime { + #[inline(always)] + fn into_time(self, _: MonotonicTime) -> MonotonicTime { + self + } +} + /// A local scheduler for models. /// /// A `Scheduler` is a handle to the global scheduler associated to a model @@ -73,7 +97,7 @@ pub(crate) type SchedulerQueue = PriorityQueue<(MonotonicTime, ChannelId), Box Scheduler { /// Schedules an event at a future time. /// - /// An error is returned if the specified time is not in the future of the - /// current simulation time. - /// - /// # Examples - /// - /// ``` - /// use asynchronix::model::Model; - /// use asynchronix::time::{MonotonicTime, Scheduler}; - /// - /// // An alarm clock. - /// pub struct AlarmClock {} - /// - /// impl AlarmClock { - /// // Sets an alarm [input port]. - /// pub fn set(&mut self, setting: MonotonicTime, scheduler: &Scheduler) { - /// if scheduler.schedule_event_at(setting, Self::ring, ()).is_err() { - /// println!("The alarm clock can only be set for a future time"); - /// } - /// } - /// - /// // Rings the alarm [private input port]. - /// fn ring(&mut self) { - /// println!("Brringggg"); - /// } - /// } - /// - /// impl Model for AlarmClock {} - /// ``` - pub fn schedule_event_at( - &self, - time: MonotonicTime, - func: F, - arg: T, - ) -> Result<(), SchedulingError> - where - F: for<'a> InputFn<'a, M, T, S>, - T: Send + Clone + 'static, - S: Send + 'static, - { - if self.time() >= time { - return Err(SchedulingError::InvalidScheduledTime); - } - let sender = self.sender.clone(); - schedule_event_at_unchecked(time, func, arg, sender, &self.scheduler_queue); - - Ok(()) - } - - /// Schedules an event at the lapse of the specified duration. - /// - /// An error is returned if the specified delay is null. + /// An error is returned if the specified deadline is not in the future of + /// the current simulation time. /// /// # Examples /// /// ``` /// use std::time::Duration; - /// use std::future::Future; + /// /// use asynchronix::model::Model; /// use asynchronix::time::Scheduler; /// - /// // A model that logs the value of a counter every second after being - /// // triggered the first time. - /// pub struct CounterLogger {} + /// // A timer. + /// pub struct Timer {} /// - /// impl CounterLogger { - /// // Triggers the logging of a timestamp every second [input port]. - /// pub fn trigger(&mut self, counter: u64, scheduler: &Scheduler) { - /// println!("counter: {}", counter); + /// impl Timer { + /// // Sets an alarm [input port]. + /// pub fn set(&mut self, setting: Duration, scheduler: &Scheduler) { + /// if scheduler.schedule_event(setting, Self::ring, ()).is_err() { + /// println!("The alarm clock can only be set for a future time"); + /// } + /// } /// - /// // Schedule this method again in 1s with an incremented counter. - /// scheduler - /// .schedule_event_in(Duration::from_secs(1), Self::trigger, counter + 1) - /// .unwrap(); + /// // Rings [private input port]. + /// fn ring(&mut self) { + /// println!("Brringggg"); /// } /// } /// - /// impl Model for CounterLogger {} + /// impl Model for Timer {} /// ``` - pub fn schedule_event_in( + pub fn schedule_event( &self, - delay: Duration, + deadline: impl Deadline, func: F, arg: T, ) -> Result<(), SchedulingError> @@ -216,10 +192,11 @@ impl Scheduler { T: Send + Clone + 'static, S: Send + 'static, { - if delay.is_zero() { + let now = self.time(); + let time = deadline.into_time(now); + if now >= time { return Err(SchedulingError::InvalidScheduledTime); } - let time = self.time() + delay; let sender = self.sender.clone(); schedule_event_at_unchecked(time, func, arg, sender, &self.scheduler_queue); @@ -228,8 +205,8 @@ impl Scheduler { /// Schedules a cancellable event at a future time and returns an event key. /// - /// An error is returned if the specified time is not in the future of the - /// current simulation time. + /// An error is returned if the specified deadline is not in the future of + /// the current simulation time. /// /// # Examples /// @@ -247,7 +224,7 @@ impl Scheduler { /// // Sets an alarm [input port]. /// pub fn set(&mut self, setting: MonotonicTime, scheduler: &Scheduler) { /// self.cancel(); - /// match scheduler.schedule_keyed_event_at(setting, Self::ring, ()) { + /// match scheduler.schedule_keyed_event(setting, Self::ring, ()) { /// Ok(event_key) => self.event_key = Some(event_key), /// Err(_) => println!("The alarm clock can only be set for a future time"), /// }; @@ -266,9 +243,9 @@ impl Scheduler { /// /// impl Model for CancellableAlarmClock {} /// ``` - pub fn schedule_keyed_event_at( + pub fn schedule_keyed_event( &self, - time: MonotonicTime, + deadline: impl Deadline, func: F, arg: T, ) -> Result @@ -277,7 +254,9 @@ impl Scheduler { T: Send + Clone + 'static, S: Send + 'static, { - if self.time() >= time { + let now = self.time(); + let time = deadline.into_time(now); + if now >= time { return Err(SchedulingError::InvalidScheduledTime); } let sender = self.sender.clone(); @@ -287,40 +266,10 @@ impl Scheduler { Ok(event_key) } - /// Schedules a cancellable event at the lapse of the specified duration and - /// returns an event key. - /// - /// An error is returned if the specified delay is null. - /// - /// See also: - /// [`schedule_keyed_event_at`][Scheduler::schedule_keyed_event_at], - /// [`schedule_event_in`][Scheduler::schedule_event_in]. - pub fn schedule_keyed_event_in( - &self, - delay: Duration, - func: F, - arg: T, - ) -> Result - where - F: for<'a> InputFn<'a, M, T, S>, - T: Send + Clone + 'static, - S: Send + 'static, - { - if delay.is_zero() { - return Err(SchedulingError::InvalidScheduledTime); - } - let time = self.time() + delay; - let sender = self.sender.clone(); - let event_key = - schedule_keyed_event_at_unchecked(time, func, arg, sender, &self.scheduler_queue); - - Ok(event_key) - } - /// Schedules a periodically recurring event at a future time. /// - /// An error is returned if the specified time is not in the future of the - /// current simulation time or if the specified period is null. + /// An error is returned if the specified deadline is not in the future of + /// the current simulation time or if the specified period is null. /// /// # Examples /// @@ -336,7 +285,7 @@ impl Scheduler { /// impl BeepingAlarmClock { /// // Sets an alarm [input port]. /// pub fn set(&mut self, setting: MonotonicTime, scheduler: &Scheduler) { - /// if scheduler.schedule_periodic_event_at( + /// if scheduler.schedule_periodic_event( /// setting, /// Duration::from_secs(1), // 1Hz = 1/1s /// Self::beep, @@ -354,9 +303,9 @@ impl Scheduler { /// /// impl Model for BeepingAlarmClock {} /// ``` - pub fn schedule_periodic_event_at( + pub fn schedule_periodic_event( &self, - time: MonotonicTime, + deadline: impl Deadline, period: Duration, func: F, arg: T, @@ -366,7 +315,9 @@ impl Scheduler { T: Send + Clone + 'static, S: Send + 'static, { - if self.time() >= time { + let now = self.time(); + let time = deadline.into_time(now); + if now >= time { return Err(SchedulingError::InvalidScheduledTime); } if period.is_zero() { @@ -385,52 +336,11 @@ impl Scheduler { Ok(()) } - /// Schedules a periodically recurring event at the lapse of the specified - /// duration. - /// - /// An error is returned if the specified delay or the specified period are - /// null. - /// - /// See also: - /// [`schedule_periodic_event_at`][Scheduler::schedule_periodic_event_at], - /// [`schedule_event_in`][Scheduler::schedule_event_in]. - pub fn schedule_periodic_event_in( - &self, - delay: Duration, - period: Duration, - func: F, - arg: T, - ) -> Result<(), SchedulingError> - where - F: for<'a> InputFn<'a, M, T, S> + Clone, - T: Send + Clone + 'static, - S: Send + 'static, - { - if delay.is_zero() { - return Err(SchedulingError::InvalidScheduledTime); - } - if period.is_zero() { - return Err(SchedulingError::NullRepetitionPeriod); - } - let time = self.time() + delay; - let sender = self.sender.clone(); - schedule_periodic_event_at_unchecked( - time, - period, - func, - arg, - sender, - &self.scheduler_queue, - ); - - Ok(()) - } - /// Schedules a cancellable, periodically recurring event at a future time /// and returns an event key. /// - /// An error is returned if the specified time is not in the future of the - /// current simulation time or if the specified period is null. + /// An error is returned if the specified deadline is not in the future of + /// the current simulation time or if the specified period is null. /// /// # Examples /// @@ -451,7 +361,7 @@ impl Scheduler { /// // Sets an alarm [input port]. /// pub fn set(&mut self, setting: MonotonicTime, scheduler: &Scheduler) { /// self.cancel(); - /// match scheduler.schedule_periodic_keyed_event_at( + /// match scheduler.schedule_keyed_periodic_event( /// setting, /// Duration::from_secs(1), // 1Hz = 1/1s /// Self::beep, @@ -475,9 +385,9 @@ impl Scheduler { /// /// impl Model for CancellableBeepingAlarmClock {} /// ``` - pub fn schedule_periodic_keyed_event_at( + pub fn schedule_keyed_periodic_event( &self, - time: MonotonicTime, + deadline: impl Deadline, period: Duration, func: F, arg: T, @@ -487,7 +397,9 @@ impl Scheduler { T: Send + Clone + 'static, S: Send + 'static, { - if self.time() >= time { + let now = self.time(); + let time = deadline.into_time(now); + if now >= time { return Err(SchedulingError::InvalidScheduledTime); } if period.is_zero() { @@ -505,47 +417,6 @@ impl Scheduler { Ok(event_key) } - - /// Schedules a cancellable, periodically recurring event at the lapse of - /// the specified duration and returns an event key. - /// - /// An error is returned if the specified delay or the specified period are - /// null. - /// - /// See also: - /// [`schedule_periodic_keyed_event_at`][Scheduler::schedule_periodic_keyed_event_at], - /// [`schedule_event_in`][Scheduler::schedule_event_in]. - pub fn schedule_periodic_keyed_event_in( - &self, - delay: Duration, - period: Duration, - func: F, - arg: T, - ) -> Result - where - F: for<'a> InputFn<'a, M, T, S> + Clone, - T: Send + Clone + 'static, - S: Send + 'static, - { - if delay.is_zero() { - return Err(SchedulingError::InvalidScheduledTime); - } - if period.is_zero() { - return Err(SchedulingError::NullRepetitionPeriod); - } - let time = self.time() + delay; - let sender = self.sender.clone(); - let event_key = schedule_periodic_keyed_event_at_unchecked( - time, - period, - func, - arg, - sender, - &self.scheduler_queue, - ); - - Ok(event_key) - } } impl fmt::Debug for Scheduler { diff --git a/asynchronix/tests/model_scheduling.rs b/asynchronix/tests/model_scheduling.rs index 642a7e8..6ff9b44 100644 --- a/asynchronix/tests/model_scheduling.rs +++ b/asynchronix/tests/model_scheduling.rs @@ -15,7 +15,7 @@ fn model_schedule_event() { impl TestModel { fn trigger(&mut self, _: (), scheduler: &Scheduler) { scheduler - .schedule_event_at(scheduler.time() + Duration::from_secs(2), Self::action, ()) + .schedule_event(scheduler.time() + Duration::from_secs(2), Self::action, ()) .unwrap(); } async fn action(&mut self) { @@ -51,14 +51,10 @@ fn model_cancel_future_keyed_event() { impl TestModel { fn trigger(&mut self, _: (), scheduler: &Scheduler) { scheduler - .schedule_event_at(scheduler.time() + Duration::from_secs(1), Self::action1, ()) + .schedule_event(scheduler.time() + Duration::from_secs(1), Self::action1, ()) .unwrap(); self.key = scheduler - .schedule_keyed_event_at( - scheduler.time() + Duration::from_secs(2), - Self::action2, - (), - ) + .schedule_keyed_event(scheduler.time() + Duration::from_secs(2), Self::action2, ()) .ok(); } async fn action1(&mut self) { @@ -100,14 +96,10 @@ fn model_cancel_same_time_keyed_event() { impl TestModel { fn trigger(&mut self, _: (), scheduler: &Scheduler) { scheduler - .schedule_event_at(scheduler.time() + Duration::from_secs(2), Self::action1, ()) + .schedule_event(scheduler.time() + Duration::from_secs(2), Self::action1, ()) .unwrap(); self.key = scheduler - .schedule_keyed_event_at( - scheduler.time() + Duration::from_secs(2), - Self::action2, - (), - ) + .schedule_keyed_event(scheduler.time() + Duration::from_secs(2), Self::action2, ()) .ok(); } async fn action1(&mut self) { @@ -148,7 +140,7 @@ fn model_schedule_periodic_event() { impl TestModel { fn trigger(&mut self, _: (), scheduler: &Scheduler) { scheduler - .schedule_periodic_event_at( + .schedule_periodic_event( scheduler.time() + Duration::from_secs(2), Duration::from_secs(3), Self::action, @@ -195,7 +187,7 @@ fn model_cancel_periodic_event() { impl TestModel { fn trigger(&mut self, _: (), scheduler: &Scheduler) { self.key = scheduler - .schedule_periodic_keyed_event_at( + .schedule_keyed_periodic_event( scheduler.time() + Duration::from_secs(2), Duration::from_secs(3), Self::action, diff --git a/asynchronix/tests/simulation_scheduling.rs b/asynchronix/tests/simulation_scheduling.rs index 5df71f9..59b5003 100644 --- a/asynchronix/tests/simulation_scheduling.rs +++ b/asynchronix/tests/simulation_scheduling.rs @@ -49,9 +49,9 @@ fn simulation_schedule_events() { let (mut simu, t0, addr, mut output) = simple_bench(); // Queue 2 events at t0+3s and t0+2s, in reverse order. - simu.schedule_event_in(Duration::from_secs(3), PassThroughModel::input, (), &addr) + simu.schedule_event(Duration::from_secs(3), PassThroughModel::input, (), &addr) .unwrap(); - simu.schedule_event_at( + simu.schedule_event( t0 + Duration::from_secs(2), PassThroughModel::input, (), @@ -65,7 +65,7 @@ fn simulation_schedule_events() { assert!(output.next().is_some()); // Schedule another event in 4s (at t0+6s). - simu.schedule_event_in(Duration::from_secs(4), PassThroughModel::input, (), &addr) + simu.schedule_event(Duration::from_secs(4), PassThroughModel::input, (), &addr) .unwrap(); // Move to the 2nd event at t0+3s. @@ -85,7 +85,7 @@ fn simulation_schedule_keyed_events() { let (mut simu, t0, addr, mut output) = simple_bench(); let event_t1 = simu - .schedule_keyed_event_at( + .schedule_keyed_event( t0 + Duration::from_secs(1), PassThroughModel::input, 1, @@ -94,10 +94,10 @@ fn simulation_schedule_keyed_events() { .unwrap(); let event_t2_1 = simu - .schedule_keyed_event_in(Duration::from_secs(2), PassThroughModel::input, 21, &addr) + .schedule_keyed_event(Duration::from_secs(2), PassThroughModel::input, 21, &addr) .unwrap(); - simu.schedule_event_in(Duration::from_secs(2), PassThroughModel::input, 22, &addr) + simu.schedule_event(Duration::from_secs(2), PassThroughModel::input, 22, &addr) .unwrap(); // Move to the 1st event at t0+1. @@ -123,7 +123,7 @@ fn simulation_schedule_periodic_events() { let (mut simu, t0, addr, mut output) = simple_bench(); // Queue 2 periodic events at t0 + 3s + k*2s. - simu.schedule_periodic_event_in( + simu.schedule_periodic_event( Duration::from_secs(3), Duration::from_secs(2), PassThroughModel::input, @@ -131,7 +131,7 @@ fn simulation_schedule_periodic_events() { &addr, ) .unwrap(); - simu.schedule_periodic_event_at( + simu.schedule_periodic_event( t0 + Duration::from_secs(3), Duration::from_secs(2), PassThroughModel::input, @@ -158,7 +158,7 @@ fn simulation_schedule_periodic_keyed_events() { let (mut simu, t0, addr, mut output) = simple_bench(); // Queue 2 periodic events at t0 + 3s + k*2s. - simu.schedule_periodic_event_in( + simu.schedule_periodic_event( Duration::from_secs(3), Duration::from_secs(2), PassThroughModel::input, @@ -167,7 +167,7 @@ fn simulation_schedule_periodic_keyed_events() { ) .unwrap(); let event2_key = simu - .schedule_periodic_keyed_event_at( + .schedule_keyed_periodic_event( t0 + Duration::from_secs(3), Duration::from_secs(2), PassThroughModel::input,