pub struct Simulation { /* private fields */ }
Expand description
Represents a simulation, provides methods for its configuration and execution.
Implementations§
Source§impl Simulation
impl Simulation
Sourcepub fn lookup_id(&self, name: &str) -> Id
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");
Sourcepub fn lookup_name(&self, id: Id) -> String
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);
Sourcepub fn create_context<S>(&mut self, name: S) -> SimulationContext
pub fn create_context<S>(&mut self, name: S) -> SimulationContext
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");
Sourcepub fn add_handler<S>(
&mut self,
name: S,
handler: Rc<RefCell<dyn EventHandler>>,
) -> Id
pub fn add_handler<S>( &mut self, name: S, handler: Rc<RefCell<dyn EventHandler>>, ) -> Id
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);
Sourcepub fn add_static_handler<S>(
&mut self,
name: S,
static_handler: Rc<dyn StaticEventHandler>,
) -> Id
Available on crate feature async_mode
only.
pub fn add_static_handler<S>( &mut self, name: S, static_handler: Rc<dyn StaticEventHandler>, ) -> Id
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.
Sourcepub fn remove_handler<S>(
&mut self,
name: S,
cancel_policy: EventCancellationPolicy,
)
pub fn remove_handler<S>( &mut self, name: S, cancel_policy: EventCancellationPolicy, )
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);
Sourcepub fn time(&self) -> f64
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);
Sourcepub fn step(&self) -> bool
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);
Sourcepub fn spawn(&self, future: impl Future<Output = ()> + 'static)
Available on crate feature async_mode
only.
pub fn spawn(&self, future: impl Future<Output = ()> + 'static)
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.);
Sourcepub fn register_key_getter_for<T: EventData>(
&self,
key_getter: impl Fn(&T) -> EventKey + 'static,
)
Available on crate feature async_mode
only.
pub fn register_key_getter_for<T: EventData>( &self, key_getter: impl Fn(&T) -> EventKey + 'static, )
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.
Sourcepub fn create_queue<T, S>(&mut self, name: S) -> UnboundedQueue<T>
Available on crate feature async_mode
only.
pub fn create_queue<T, S>(&mut self, name: S) -> UnboundedQueue<T>
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.);
Sourcepub fn steps(&mut self, step_count: u64) -> bool
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);
Sourcepub fn step_until_no_events(&mut self)
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);
Sourcepub fn step_for_duration(&mut self, duration: f64) -> bool
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
Sourcepub fn step_until_time(&mut self, time: f64) -> bool
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
Sourcepub fn rand(&mut self) -> f64
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);
Sourcepub fn gen_range<T, R>(&mut self, range: R) -> Twhere
T: SampleUniform,
R: SampleRange<T>,
pub fn gen_range<T, R>(&mut self, range: R) -> Twhere
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);
Sourcepub fn sample_from_distribution<T, Dist: Distribution<T>>(
&mut self,
dist: &Dist,
) -> T
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.
Sourcepub fn random_string(&mut self, len: usize) -> String
pub fn random_string(&mut self, len: usize) -> String
Returns a random alphanumeric string of specified length using the simulation-wide random number generator.
Sourcepub fn event_count(&self) -> u64
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);
Sourcepub fn cancel_events<F>(&mut self, pred: F)
pub fn cancel_events<F>(&mut self, pred: F)
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);
Sourcepub fn cancel_and_get_events<F>(&mut self, pred: F) -> Vec<Event>
pub fn cancel_and_get_events<F>(&mut self, pred: F) -> Vec<Event>
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);
Sourcepub fn dump_events(&self) -> Vec<Event>
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§
impl Freeze for Simulation
impl !RefUnwindSafe for Simulation
impl !Send for Simulation
impl !Sync for Simulation
impl Unpin for Simulation
impl !UnwindSafe for Simulation
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
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>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
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)
fn as_any(&self) -> &(dyn Any + 'static)
&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)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &mut Any
’s vtable from &mut Trait
’s.