simcore 0.1.0

A generic discrete-event simulation framework
Documentation
use std::cell::RefCell;
use std::rc::Rc;

use serde::Serialize;

use simcore::async_mode::AwaitResult;
use simcore::{cast, Event, Id, Simulation, SimulationContext, StaticEventHandler};

#[derive(Clone, Serialize)]
struct TestEvent {
    value: u32,
}

struct Listener {
    event_src: Id,
    timeout: f64,
    continue_listening: RefCell<bool>,
    expect_timeout: RefCell<bool>,
    next_expected_value: RefCell<u32>,
    ctx: SimulationContext,
}

impl Listener {
    fn new(event_src: Id, timeout: f64, ctx: SimulationContext) -> Self {
        Self {
            event_src,
            timeout,
            continue_listening: RefCell::new(true),
            expect_timeout: RefCell::new(false),
            next_expected_value: RefCell::new(0),
            ctx,
        }
    }

    fn start(self: Rc<Self>) {
        self.ctx.spawn(self.clone().listen_with_timeout());
    }

    async fn listen_with_timeout(self: Rc<Self>) {
        while *self.continue_listening.borrow() {
            match self
                .ctx
                .recv_event_from::<TestEvent>(self.event_src)
                .with_timeout(self.timeout)
                .await
            {
                AwaitResult::Ok(event) => {
                    assert!(!*self.expect_timeout.borrow());
                    assert_eq!(event.src, self.event_src);
                    assert_eq!(event.data.value, *self.next_expected_value.borrow());
                }
                AwaitResult::Timeout {
                    src,
                    event_key,
                    timeout,
                } => {
                    assert!(*self.expect_timeout.borrow());
                    assert_eq!(src, Some(self.event_src));
                    assert_eq!(event_key, None);
                    assert_eq!(timeout, self.timeout);
                }
            }
        }
    }
}

impl StaticEventHandler for Listener {
    fn on(self: Rc<Self>, event: Event) {
        cast!(match event.data {
            TestEvent { value } => {
                assert_eq!(value, *self.next_expected_value.borrow());
            }
        })
    }
}

#[test]
fn test_recv_event() {
    let mut sim = Simulation::new(123);
    let timeout = 5.;

    let ctx = sim.create_context("main");

    let listener = Rc::new(Listener::new(ctx.id(), timeout, sim.create_context("listener")));
    let listener_id = sim.add_static_handler("listener", listener.clone());
    listener.clone().start();

    *listener.expect_timeout.borrow_mut() = true;
    sim.step_until_time(100.);
    assert_eq!(ctx.time(), 100.);

    sim.spawn(async move {
        let start_time = 202.;
        ctx.sleep(start_time - ctx.time()).await;
        assert_eq!(ctx.time(), start_time);

        *listener.expect_timeout.borrow_mut() = false;

        let mut next_value = 1;
        for _ in 0..=5 {
            next_value += 1;
            *listener.next_expected_value.borrow_mut() = next_value;
            ctx.emit_now(TestEvent { value: next_value }, listener_id);
            ctx.sleep(timeout - 1.).await;
        }

        *listener.expect_timeout.borrow_mut() = true;
        *listener.continue_listening.borrow_mut() = false;

        ctx.sleep(100.).await;

        *listener.expect_timeout.borrow_mut() = false;

        for _ in 0..=5 {
            next_value += 1;
            *listener.next_expected_value.borrow_mut() = next_value;
            ctx.emit_now(TestEvent { value: next_value }, listener_id);
            ctx.sleep(timeout + 1.).await;
        }
    });

    sim.step_until_time(500.);
}