simcore 0.1.0

A generic discrete-event simulation framework
Documentation
//! Simulation events.

use std::cmp::Ordering;

use downcast_rs::{impl_downcast, Downcast};
use dyn_clone::{clone_trait_object, DynClone};
use serde::ser::Serialize;

use crate::component::Id;

/// Event identifier.
pub type EventId = u64;

/// Trait that should be implemented by event payload.
pub trait EventData: Downcast + DynClone + erased_serde::Serialize {}

impl_downcast!(EventData);

clone_trait_object!(EventData);

erased_serde::serialize_trait_object!(EventData);

impl<T: Serialize + DynClone + 'static> EventData for T {}

/// Representation of event.
#[derive(Clone)]
pub struct Event {
    /// Unique event identifier.
    ///
    /// Events are numbered sequentially starting from 0.
    pub id: EventId,
    /// Time of event occurrence.
    pub time: f64,
    /// Identifier of event source.
    pub src: Id,
    /// Identifier of event destination.
    pub dst: Id,
    /// Event payload.
    pub data: Box<dyn EventData>,
}

impl Eq for Event {}

impl PartialEq for Event {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id
    }
}

impl Ord for Event {
    fn cmp(&self, other: &Self) -> Ordering {
        other.time.total_cmp(&self.time).then_with(|| other.id.cmp(&self.id))
    }
}

impl PartialOrd for Event {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

/// Typed version of [`crate::Event`].
pub struct TypedEvent<T>
where
    T: EventData,
{
    /// Unique event identifier.
    ///
    /// Events are numbered sequentially starting from 0.
    pub id: EventId,
    /// Time of event occurrence.
    pub time: f64,
    /// Identifier of event source.
    pub src: Id,
    /// Identifier of event destination.
    pub dst: Id,
    /// Event payload.
    pub data: T,
}

impl Event {
    /// Converts [`Event`] to [`TypedEvent`] of type `T`.
    ///
    /// Panics on downcast error.
    pub fn downcast<T>(e: Event) -> TypedEvent<T>
    where
        T: EventData,
    {
        match e.data.downcast::<T>() {
            Ok(data) => TypedEvent {
                id: e.id,
                time: e.time,
                src: e.src,
                dst: e.dst,
                data: *data,
            },
            Err(_) => {
                panic!("Event downcast error");
            }
        }
    }
}