1
0
forked from ROMEO/nexosim
nexosim/asynchronix/tests/model_scheduling.rs
2023-08-14 12:31:35 +02:00

234 lines
6.6 KiB
Rust

//! Event scheduling within `Model` input methods.
use std::time::Duration;
use asynchronix::model::{Model, Output};
use asynchronix::simulation::{Mailbox, SimInit};
use asynchronix::time::{EventKey, MonotonicTime, Scheduler};
#[test]
fn model_schedule_event() {
#[derive(Default)]
struct TestModel {
output: Output<()>,
}
impl TestModel {
fn trigger(&mut self, _: (), scheduler: &Scheduler<Self>) {
scheduler
.schedule_event_at(scheduler.time() + Duration::from_secs(2), Self::action, ())
.unwrap();
}
async fn action(&mut self) {
self.output.send(()).await;
}
}
impl Model for TestModel {}
let mut model = TestModel::default();
let mbox = Mailbox::new();
let mut output = model.output.connect_stream().0;
let addr = mbox.address();
let t0 = MonotonicTime::EPOCH;
let mut simu = SimInit::new().add_model(model, mbox).init(t0);
simu.send_event(TestModel::trigger, (), addr);
simu.step();
assert_eq!(simu.time(), t0 + Duration::from_secs(2));
assert!(output.next().is_some());
simu.step();
assert!(output.next().is_none());
}
#[test]
fn model_cancel_future_keyed_event() {
#[derive(Default)]
struct TestModel {
output: Output<i32>,
key: Option<EventKey>,
}
impl TestModel {
fn trigger(&mut self, _: (), scheduler: &Scheduler<Self>) {
scheduler
.schedule_event_at(scheduler.time() + Duration::from_secs(1), Self::action1, ())
.unwrap();
self.key = scheduler
.schedule_keyed_event_at(
scheduler.time() + Duration::from_secs(2),
Self::action2,
(),
)
.ok();
}
async fn action1(&mut self) {
self.output.send(1).await;
// Cancel the call to `action2`.
self.key.take().unwrap().cancel();
}
async fn action2(&mut self) {
self.output.send(2).await;
}
}
impl Model for TestModel {}
let mut model = TestModel::default();
let mbox = Mailbox::new();
let mut output = model.output.connect_stream().0;
let addr = mbox.address();
let t0 = MonotonicTime::EPOCH;
let mut simu = SimInit::new().add_model(model, mbox).init(t0);
simu.send_event(TestModel::trigger, (), addr);
simu.step();
assert_eq!(simu.time(), t0 + Duration::from_secs(1));
assert_eq!(output.next(), Some(1));
simu.step();
assert_eq!(simu.time(), t0 + Duration::from_secs(1));
assert!(output.next().is_none());
}
#[test]
fn model_cancel_same_time_keyed_event() {
#[derive(Default)]
struct TestModel {
output: Output<i32>,
key: Option<EventKey>,
}
impl TestModel {
fn trigger(&mut self, _: (), scheduler: &Scheduler<Self>) {
scheduler
.schedule_event_at(scheduler.time() + Duration::from_secs(2), Self::action1, ())
.unwrap();
self.key = scheduler
.schedule_keyed_event_at(
scheduler.time() + Duration::from_secs(2),
Self::action2,
(),
)
.ok();
}
async fn action1(&mut self) {
self.output.send(1).await;
// Cancel the call to `action2`.
self.key.take().unwrap().cancel();
}
async fn action2(&mut self) {
self.output.send(2).await;
}
}
impl Model for TestModel {}
let mut model = TestModel::default();
let mbox = Mailbox::new();
let mut output = model.output.connect_stream().0;
let addr = mbox.address();
let t0 = MonotonicTime::EPOCH;
let mut simu = SimInit::new().add_model(model, mbox).init(t0);
simu.send_event(TestModel::trigger, (), addr);
simu.step();
assert_eq!(simu.time(), t0 + Duration::from_secs(2));
assert_eq!(output.next(), Some(1));
assert!(output.next().is_none());
simu.step();
assert!(output.next().is_none());
}
#[test]
fn model_schedule_periodic_event() {
#[derive(Default)]
struct TestModel {
output: Output<i32>,
}
impl TestModel {
fn trigger(&mut self, _: (), scheduler: &Scheduler<Self>) {
scheduler
.schedule_periodic_event_at(
scheduler.time() + Duration::from_secs(2),
Duration::from_secs(3),
Self::action,
42,
)
.unwrap();
}
async fn action(&mut self, payload: i32) {
self.output.send(payload).await;
}
}
impl Model for TestModel {}
let mut model = TestModel::default();
let mbox = Mailbox::new();
let mut output = model.output.connect_stream().0;
let addr = mbox.address();
let t0 = MonotonicTime::EPOCH;
let mut simu = SimInit::new().add_model(model, mbox).init(t0);
simu.send_event(TestModel::trigger, (), addr);
// Move to the next events at t0 + 2s + k*3s.
for k in 0..10 {
simu.step();
assert_eq!(
simu.time(),
t0 + Duration::from_secs(2) + k * Duration::from_secs(3)
);
assert_eq!(output.next(), Some(42));
assert!(output.next().is_none());
}
}
#[test]
fn model_cancel_periodic_event() {
#[derive(Default)]
struct TestModel {
output: Output<()>,
key: Option<EventKey>,
}
impl TestModel {
fn trigger(&mut self, _: (), scheduler: &Scheduler<Self>) {
self.key = scheduler
.schedule_periodic_keyed_event_at(
scheduler.time() + Duration::from_secs(2),
Duration::from_secs(3),
Self::action,
(),
)
.ok();
}
async fn action(&mut self) {
self.output.send(()).await;
// Cancel the next events.
self.key.take().unwrap().cancel();
}
}
impl Model for TestModel {}
let mut model = TestModel::default();
let mbox = Mailbox::new();
let mut output = model.output.connect_stream().0;
let addr = mbox.address();
let t0 = MonotonicTime::EPOCH;
let mut simu = SimInit::new().add_model(model, mbox).init(t0);
simu.send_event(TestModel::trigger, (), addr);
simu.step();
assert_eq!(simu.time(), t0 + Duration::from_secs(2));
assert!(output.next().is_some());
assert!(output.next().is_none());
simu.step();
assert_eq!(simu.time(), t0 + Duration::from_secs(2));
assert!(output.next().is_none());
}