Struct Simulation

Source
pub struct Simulation { /* private fields */ }
Expand description

Represents a simulation, provides methods for its configuration and execution.

Implementations§

Source§

impl Simulation

Source

pub fn new(seed: u64) -> Self

Creates a new simulation with specified random seed.

Source

pub fn lookup_id(&self, name: &str) -> Id

Returns the identifier of component by its name.

Panics if component with such name does not exist.

§Examples
use simcore::Simulation;

let mut sim = Simulation::new(123);
let comp_ctx = sim.create_context("comp");
let comp_id = sim.lookup_id(comp_ctx.name());
assert_eq!(comp_id, 0);
use simcore::Simulation;

let mut sim = Simulation::new(123);
let comp_ctx = sim.create_context("comp");
let comp1_id = sim.lookup_id("comp1");
Source

pub fn lookup_name(&self, id: Id) -> String

Returns the name of component by its identifier.

Panics if component with such Id does not exist.

§Examples
use simcore::Simulation;

let mut sim = Simulation::new(123);
let comp_ctx = sim.create_context("comp");
let comp_name = sim.lookup_name(comp_ctx.id());
assert_eq!(comp_name, "comp");
use simcore::Simulation;

let mut sim = Simulation::new(123);
let comp_ctx = sim.create_context("comp");
let comp_name = sim.lookup_name(comp_ctx.id() + 1);
Source

pub fn create_context<S>(&mut self, name: S) -> SimulationContext
where S: AsRef<str>,

Creates a new simulation context with specified name.

§Examples
use simcore::Simulation;

let mut sim = Simulation::new(123);
let comp_ctx = sim.create_context("comp");
assert_eq!(comp_ctx.id(), 0); // component ids are assigned sequentially starting from 0
assert_eq!(comp_ctx.name(), "comp");
Source

pub fn add_handler<S>( &mut self, name: S, handler: Rc<RefCell<dyn EventHandler>>, ) -> Id
where S: AsRef<str>,

Registers the event handler implementation for component with specified name, returns the component Id.

§Examples
use std::cell::RefCell;
use std::rc::Rc;
use simcore::{Event, EventHandler, Simulation, SimulationContext};

struct Component {
    ctx: SimulationContext,
}

impl EventHandler for Component {
    fn on(&mut self, event: Event) {
    }
}

let mut sim = Simulation::new(123);
let comp_ctx = sim.create_context("comp");
assert_eq!(comp_ctx.id(), 0);
let comp = Rc::new(RefCell::new(Component { ctx: comp_ctx }));
// When the handler is registered for component with existing context,
// the component Id assigned in create_context() is reused.
let comp_id = sim.add_handler("comp", comp);
assert_eq!(comp_id, 0);
use std::cell::RefCell;
use std::rc::Rc;
use simcore::{Event, EventHandler, Simulation, SimulationContext};

struct Component {
}

impl EventHandler for Component {
    fn on(&mut self, event: Event) {
    }
}

let mut sim = Simulation::new(123);
let comp = Rc::new(RefCell::new(Component {}));
// It is possible to register event handler for component without context.
// In this case the component Id is assigned inside add_handler().
let comp_id = sim.add_handler("comp", comp);
assert_eq!(comp_id, 0);
use std::cell::RefCell;
use std::rc::Rc;
use simcore::{Simulation, SimulationContext};

pub struct Component {
    ctx: SimulationContext,
}

let mut sim = Simulation::new(123);
let comp_ctx = sim.create_context("comp");
let comp = Rc::new(RefCell::new(Component { ctx: comp_ctx }));
// should not compile because Component does not implement EventHandler trait
let comp_id = sim.add_handler("comp", comp);
Source

pub fn add_static_handler<S>( &mut self, name: S, static_handler: Rc<dyn StaticEventHandler>, ) -> Id
where S: AsRef<str>,

Available on crate feature async_mode only.

Registers the static event handler for component with specified name, returns the component Id.

In contrast to EventHandler, StaticEventHandler has 'static lifetime while processing incoming events, which allows spawning asynchronous tasks using component’s context. See SimulationContext::spawn examples.

Source

pub fn remove_handler<S>( &mut self, name: S, cancel_policy: EventCancellationPolicy, )
where S: AsRef<str>,

Removes the event handler for component with specified name.

All subsequent events destined for this component will not be delivered until the handler is added again.

Pending events to be cancelled upon the handler removal are specified via EventCancellationPolicy.

If async mode is enabled, all pending asynchronous tasks and activities related to this component are cancelled. To continue receiving events asynchronously after the handler is re-added, spawn new asynchronous tasks using SimulationContext::spawn. Otherwise, the events will be delivered via EventHandler::on.

§Examples
use std::cell::RefCell;
use std::rc::Rc;
use simcore::{Event, EventCancellationPolicy, EventHandler, Simulation, SimulationContext};

struct Component {
}

impl EventHandler for Component {
    fn on(&mut self, event: Event) {
    }
}

let mut sim = Simulation::new(123);
let comp = Rc::new(RefCell::new(Component {}));
let comp_id1 = sim.add_handler("comp", comp.clone());
sim.remove_handler("comp", EventCancellationPolicy::None);
// Assigned component Id is not changed if we call `add_handler` again.
let comp_id2 = sim.add_handler("comp", comp);
assert_eq!(comp_id1, comp_id2);
Source

pub fn time(&self) -> f64

Returns the current simulation time.

§Examples
use serde::Serialize;
use simcore::Simulation;

#[derive(Clone, Serialize)]
struct SomeEvent {
}

let mut sim = Simulation::new(123);
let mut comp_ctx = sim.create_context("comp");
assert_eq!(sim.time(), 0.0);
comp_ctx.emit_self(SomeEvent {}, 1.2);
sim.step();
assert_eq!(sim.time(), 1.2);
Source

pub fn step(&self) -> bool

Performs a single step through the simulation.

Takes the next event from the queue, advances the simulation time to event time and tries to process it by invoking the EventHandler::on method of the corresponding event handler. If there is no handler registered for component with Id event.dst, logs the undelivered event and discards it.

Returns true if some pending event was found (no matter was it properly processed or not) and false otherwise. The latter means that there are no pending events, so no progress can be made.

§Examples
use serde::Serialize;
use simcore::Simulation;

#[derive(Clone, Serialize)]
struct SomeEvent {
}

let mut sim = Simulation::new(123);
let mut comp_ctx = sim.create_context("comp");
assert_eq!(sim.time(), 0.0);
comp_ctx.emit_self(SomeEvent {}, 1.2);
let mut status = sim.step();
assert!(status);
assert_eq!(sim.time(), 1.2);
status = sim.step();
assert!(!status);
Source

pub fn spawn(&self, future: impl Future<Output = ()> + 'static)

Available on crate feature async_mode only.

Spawns a new asynchronous task.

The task’s type lifetime must be 'static. This means that the spawned task must not contain any references to data owned outside the task.

To spawn methods inside simulation components use SimulationContext::spawn.

§Examples
use simcore::Simulation;

let mut sim = Simulation::new(123);

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

sim.spawn(async move {
    let initial_time = ctx.time();
    ctx.sleep(5.).await;
    assert_eq!(ctx.time(), 5.);
});

sim.step_until_no_events();
assert_eq!(sim.time(), 5.);
Source

pub fn register_key_getter_for<T: EventData>( &self, key_getter: impl Fn(&T) -> EventKey + 'static, )

Available on crate feature async_mode only.

Registers a function that extracts EventKey from events of a type T.

Calling this function is required before using SimulationContext::recv_event_by_key or SimulationContext::recv_event_by_key_from with type T. See examples for these methods.

Source

pub fn create_queue<T, S>(&mut self, name: S) -> UnboundedQueue<T>
where S: AsRef<str>,

Available on crate feature async_mode only.

Creates an UnboundedQueue for producer-consumer communication.

This queue is designed to support convenient communication between several asynchronous tasks within a single simulation component. This enables implementing the component logic as a set of communicating concurrent activities.

The use of this primitive for inter-component communication is discouraged in favor of passing events directly or via intermediate components.

§Examples
use std::rc::Rc;
use std::cell::RefCell;
use simcore::{Simulation, SimulationContext, Event, StaticEventHandler};
use simcore::async_mode::UnboundedQueue;

struct Message {
    payload: u32,
}

struct Component {
    ctx: SimulationContext,
    queue: UnboundedQueue<Message>,
}

impl Component {
    fn start(self: Rc<Self>) {
        self.ctx.spawn(self.clone().producer());
        self.ctx.spawn(self.clone().consumer());
    }

    async fn producer(self: Rc<Self>) {
        for i in 0..10 {
            self.ctx.sleep(5.).await;
            self.queue.put(Message {payload: i});
        }
    }

    async fn consumer(self: Rc<Self>) {
        for i in 0..10 {
            let msg = self.queue.take().await;
            assert_eq!(msg.payload, i);
        }
    }
}

impl StaticEventHandler for Component {
    fn on(self: Rc<Self>, event: Event) {
    }
}

let mut sim = Simulation::new(123);

let comp = Rc::new(Component {
    ctx: sim.create_context("comp"),
    queue: sim.create_queue("comp_queue")
});
sim.add_static_handler("comp", comp.clone());

comp.start();
sim.step_until_no_events();

assert_eq!(sim.time(), 50.);
Source

pub fn steps(&mut self, step_count: u64) -> bool

Performs the specified number of steps through the simulation.

This is a convenient wrapper around step, which invokes this method until the specified number of steps is made, or false is returned (no more pending events).

Returns true if there could be more pending events and false otherwise.

§Examples
use serde::Serialize;
use simcore::Simulation;

#[derive(Clone, Serialize)]
struct SomeEvent {
}

let mut sim = Simulation::new(123);
let mut comp_ctx = sim.create_context("comp");
assert_eq!(sim.time(), 0.0);
comp_ctx.emit_self(SomeEvent {}, 1.2);
comp_ctx.emit_self(SomeEvent {}, 1.3);
comp_ctx.emit_self(SomeEvent {}, 1.4);
let mut status = sim.steps(2);
assert!(status);
assert_eq!(sim.time(), 1.3);
status = sim.steps(2);
assert!(!status);
assert_eq!(sim.time(), 1.4);
Source

pub fn step_until_no_events(&mut self)

Steps through the simulation until there are no pending events left.

This is a convenient wrapper around step, which invokes this method until false is returned.

§Examples
use serde::Serialize;
use simcore::Simulation;

#[derive(Clone, Serialize)]
struct SomeEvent {
}

let mut sim = Simulation::new(123);
let mut comp_ctx = sim.create_context("comp");
assert_eq!(sim.time(), 0.0);
comp_ctx.emit_self(SomeEvent {}, 1.2);
comp_ctx.emit_self(SomeEvent {}, 1.3);
comp_ctx.emit_self(SomeEvent {}, 1.4);
sim.step_until_no_events();
assert_eq!(sim.time(), 1.4);
Source

pub fn step_for_duration(&mut self, duration: f64) -> bool

Steps through the simulation with duration limit.

This is a convenient wrapper around step, which invokes this method until the next event time is above the specified threshold (initial_time + duration) or there are no pending events left.

This method also advances the simulation time to initial_time + duration. Note that the resulted time may slightly differ from the expected value due to the floating point errors. This issue can be avoided by using the step_until_time method.

Returns true if there could be more pending events and false otherwise.

§Examples
use serde::Serialize;
use simcore::Simulation;

#[derive(Clone, Serialize)]
struct SomeEvent {
}

let mut sim = Simulation::new(123);
let mut comp_ctx = sim.create_context("comp");
assert_eq!(sim.time(), 0.0);
comp_ctx.emit_self(SomeEvent {}, 1.0);
comp_ctx.emit_self(SomeEvent {}, 2.0);
comp_ctx.emit_self(SomeEvent {}, 3.5);
let mut status = sim.step_for_duration(1.8);
assert_eq!(sim.time(), 1.8);
assert!(status); // there are more events
status = sim.step_for_duration(1.8);
assert_eq!(sim.time(), 3.6);
assert!(!status); // there are no more events
Source

pub fn step_until_time(&mut self, time: f64) -> bool

Steps through the simulation until the specified time.

This is a convenient wrapper around step, which invokes this method until the next event time is above the specified time or there are no pending events left.

This method also advances the simulation time to the specified time.

Returns true if there could be more pending events and false otherwise.

§Examples
use serde::Serialize;
use simcore::Simulation;

#[derive(Clone, Serialize)]
struct SomeEvent {
}

let mut sim = Simulation::new(123);
let mut comp_ctx = sim.create_context("comp");
assert_eq!(sim.time(), 0.0);
comp_ctx.emit_self(SomeEvent {}, 1.0);
comp_ctx.emit_self(SomeEvent {}, 2.0);
comp_ctx.emit_self(SomeEvent {}, 3.5);
let mut status = sim.step_until_time(1.8);
assert_eq!(sim.time(), 1.8);
assert!(status); // there are more events
status = sim.step_until_time(3.6);
assert_eq!(sim.time(), 3.6);
assert!(!status); // there are no more events
Source

pub fn rand(&mut self) -> f64

Returns a random float in the range [0, 1) using the simulation-wide random number generator.

§Examples
use simcore::Simulation;

let mut sim = Simulation::new(123);
let f: f64 = sim.rand();
assert!(f >= 0.0 && f < 1.0);
Source

pub fn gen_range<T, R>(&mut self, range: R) -> T
where T: SampleUniform, R: SampleRange<T>,

Returns a random number in the specified range using the simulation-wide random number generator.

§Examples
use simcore::Simulation;

let mut sim = Simulation::new(123);
let n: u32 = sim.gen_range(1..=10);
assert!(n >= 1 && n <= 10);
let f: f64 = sim.gen_range(0.1..0.5);
assert!(f >= 0.1 && f < 0.5);
Source

pub fn sample_from_distribution<T, Dist: Distribution<T>>( &mut self, dist: &Dist, ) -> T

Returns a random value from the specified distribution using the simulation-wide random number generator.

Source

pub fn random_string(&mut self, len: usize) -> String

Returns a random alphanumeric string of specified length using the simulation-wide random number generator.

Source

pub fn event_count(&self) -> u64

Returns the total number of created events.

Note that cancelled events are also counted here.

§Examples
use serde::Serialize;
use simcore::Simulation;

#[derive(Clone, Serialize)]
struct SomeEvent {
}

let mut sim = Simulation::new(123);
let mut comp_ctx = sim.create_context("comp");
assert_eq!(sim.time(), 0.0);
comp_ctx.emit_self(SomeEvent {}, 1.0);
comp_ctx.emit_self(SomeEvent {}, 2.0);
comp_ctx.emit_self(SomeEvent {}, 3.5);
assert_eq!(sim.event_count(), 3);
Source

pub fn cancel_events<F>(&mut self, pred: F)
where F: Fn(&Event) -> bool,

Cancels events that satisfy the given predicate function.

Note that already processed events cannot be cancelled.

§Examples
use serde::Serialize;
use simcore::{Event, Simulation, SimulationContext};

#[derive(Clone, Serialize)]
struct SomeEvent {
}

let mut sim = Simulation::new(123);
let mut comp1_ctx = sim.create_context("comp1");
let mut comp2_ctx = sim.create_context("comp2");
comp1_ctx.emit(SomeEvent {}, comp2_ctx.id(), 1.0);
comp1_ctx.emit(SomeEvent {}, comp2_ctx.id(), 2.0);
comp1_ctx.emit(SomeEvent {}, comp2_ctx.id(), 3.0);
sim.cancel_events(|e| e.id < 2);
sim.step();
assert_eq!(sim.time(), 3.0);
Source

pub fn cancel_and_get_events<F>(&mut self, pred: F) -> Vec<Event>
where F: Fn(&Event) -> bool,

Cancels events that satisfy the given predicate function and returns them.

Note that already processed events cannot be cancelled.

§Examples
use serde::Serialize;
use simcore::{Event, Simulation, SimulationContext};

#[derive(Clone, Serialize)]
struct SomeEvent {
}

let mut sim = Simulation::new(123);
let mut comp1_ctx = sim.create_context("comp1");
let mut comp2_ctx = sim.create_context("comp2");
comp1_ctx.emit(SomeEvent {}, comp2_ctx.id(), 1.0);
comp1_ctx.emit(SomeEvent {}, comp2_ctx.id(), 2.0);
comp1_ctx.emit(SomeEvent {}, comp2_ctx.id(), 3.0);
let cancelled = sim.cancel_and_get_events(|e| e.id < 2);
assert_eq!(cancelled.len(), 2);
sim.step();
assert_eq!(sim.time(), 3.0);
Source

pub fn dump_events(&self) -> Vec<Event>

Returns a copy of pending events sorted by time.

Currently used for model checking in dslab-mp.

§Examples
use serde::Serialize;
use simcore::{Event, Simulation, SimulationContext};

#[derive(Clone, Serialize)]
struct SomeEvent {
}

let mut sim = Simulation::new(123);
let mut ctx1 = sim.create_context("comp1");
let mut ctx2 = sim.create_context("comp2");
let event1 = ctx1.emit(SomeEvent {}, ctx2.id(), 1.0);
let event2 = ctx2.emit(SomeEvent {}, ctx1.id(), 1.0);
let event3 = ctx1.emit(SomeEvent {}, ctx2.id(), 2.0);
let events = sim.dump_events();
assert_eq!(events.len(), 3);
assert_eq!((events[0].id, events[0].time), (event1, 1.0));
assert_eq!((events[1].id, events[1].time), (event2, 1.0));
assert_eq!((events[2].id, events[2].time), (event3, 2.0));

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V