Simulation

Struct Simulation 

Source
pub struct Simulation<State, Time>
where State: SimState<Time> + Sync, Time: SimTime + Send + Sync,
{ /* private fields */ }
Expand description

Contains the event queue and other state belonging to a simulation.

This form of simulation behaves very similarly to the serial::Simulation, but is easier to share across thread boundaries for the sake of enabling events to divide-and-conquer parts of their execution.

The expected workflow for a Simulation is:

  1. Initialize a struct that implements SimState and Sync.
  2. Pass this struct and the start time to new().
  3. Schedule at least one initial event.
  4. Call run(). Handle any error it might return.
  5. Use the state() or state_mut() accessors to finish processing the results.

A Simulation is Sync, and will also be Send if and only if the SimState implementation is Send.

Note: in the implementation of Debug, scheduled events will be printed in an arbitrary order and the number of total_events_scheduled is over the entirety of the simulation run, as opposed to the number currently in queue.

Implementations§

Source§

impl<State, Time> Simulation<State, Time>
where State: SimState<Time> + Sync, Time: SimTime + Send + Sync,

Source

pub fn new(initial_state: State, start_time: Time) -> Self

Initialize a Simulation instance with the provided starting state and an empty event queue, with clock set to the provided starting time.

Source

pub fn run(&mut self) -> Result

Execute events from the priority queue, one at a time, in ascending order by execution time.

Follows this loop:

  1. Does state.is_complete() return true? If so, return Ok(()).
  2. Attempt to pop the next event from the queue. If there isn’t one, return Ok(()).
  3. Pass &mut self to event.execute(). If execution results in an error, forward it to the caller; otherwise return to step 1.
§Errors

Errors may occur during execution of events, and if encountered here they will be passed back to the caller, unchanged. The two variants directly supported are:

  1. Error::BackInTime means that client code attempted to schedule an event at some point in the simulation’s past. This error is a likely indicator that client code contains a logical bug, as most discrete-event simulations would never rewind their clocks.
  2. Error::BadExecution wraps a client-generated error in a way that is type-safe to feed back through this method. To handle the underlying error, either unpack the BadExecution or call its source() method.
§Panics

This method requires the ability to lock the Mutex on the internal event queue to find the next event that should be executed on each loop iteration. If that Mutex ever becomes poisoned, this method will panic.

Source

pub fn schedule<EventType>(&self, event: EventType, time: Time) -> Result
where EventType: Event<State, Time> + 'static,

Schedule the provided event at the specified time.

§Errors

If time is less than the current clock time on self, returns an Error::BackInTime to indicate the likely presence of a logical bug at the call site, with no modifications to the queue.

§Panics

This method requires the ability to lock the Mutex on the internal event queue. If that Mutex ever becomes poisoned, this method will panic.

Source

pub unsafe fn schedule_unchecked<EventType>(&self, event: EventType, time: Time)
where EventType: Event<State, Time> + 'static,

Schedule the provided event at the specified time. Assumes that the provided time is valid in the context of the client’s simulation.

§Safety

While this method cannot trigger undefined behaviors, scheduling an event for a time in the past is likely to be a logical bug in client code. Generally, this method should only be invoked if the condition time >= clock is already enforced at the call site through some other means. For example, adding a strictly positive offset to the current clock time to get the time argument for the call.

§Panics

This method requires the ability to lock the Mutex on the internal event queue. If that Mutex ever becomes poisoned, this method will panic.

Source

pub fn schedule_from_boxed( &self, event: Box<dyn Event<State, Time>>, time: Time, ) -> Result

Schedule the provided event at the specified time.

§Errors

If time is less than the current clock time on self, returns an Error::BackInTime to indicate the likely presence of a logical bug at the call site, with no modifications to the queue.

§Panics

This method requires the ability to lock the Mutex on the internal event queue. If that Mutex ever becomes poisoned, this method will panic.

Source

pub unsafe fn schedule_unchecked_from_boxed( &self, event: Box<dyn Event<State, Time>>, time: Time, )

Schedule the provided event at the specified time. Assumes that the provided time is valid in the context of the client’s simulation.

§Safety

While this method cannot trigger undefined behaviors, scheduling an event for a time in the past is likely to be a logical bug in client code. Generally, this method should only be invoked if the condition time >= clock is already enforced at the call site through some other means. For example, adding a strictly positive offset to the current clock time to get the time argument for the call.

§Panics

This method requires the ability to lock the Mutex on the internal event queue. If that Mutex ever becomes poisoned, this method will panic.

Source

pub fn state(&self) -> &State

Get a shared reference to the simulation state.

Source

pub fn state_mut(&mut self) -> &mut State

Get an exclusive reference to the simulation state.

Source

pub fn current_time(&self) -> &Time

Get a shared reference to the current simulation time.

Source§

impl<State, Time> Simulation<State, Time>
where State: SimState<Time> + Sync, Time: SimTime + Send + Sync + Clone,

Source

pub fn schedule_now<EventType>(&self, event: EventType) -> Result
where EventType: Event<State, Time> + 'static,

Schedule the provided event to execute at the current sim time. Events previously scheduled for “now” will still execute before this event does.

§Errors

If the result of calling Clone::clone on the current sim time results in a new value that is somehow less than the current sim time, this method will return an Error::BackInTime. Note that such behavior is not expected from implementations of Clone::clone in most cases.

§Panics

This method requires the ability to lock the Mutex on the internal event queue. If that Mutex ever becomes poisoned, this method will panic.

Source

pub unsafe fn schedule_now_unchecked<EventType>(&self, event: EventType)
where EventType: Event<State, Time> + 'static,

Schedule the provided event to execute at the current sim time. Events previously scheduled for “now” will still execute before this event does.

§Safety

This method cannot directly trigger undefined behaviors, but relies on client implementations of Clone::clone producing new values of SimTime that are not less than the cloned receiver (i.e. the current simulation time). If my_sim_time.clone().cmp(my_sim_time) != Ordering::Less is always true for your chosen type, this method will be safe to call.

§Panics

This method requires the ability to lock the Mutex on the internal event queue. If that Mutex ever becomes poisoned, this method will panic.

Source

pub fn schedule_now_from_boxed( &self, event: Box<dyn Event<State, Time>>, ) -> Result

Schedule the provided event to execute at the current sim time. Events previously scheduled for “now” will still execute before this event does.

§Errors

If the result of calling Clone::clone on the current sim time results in a new value that is somehow less than the current sim time, this method will return an Error::BackInTime. Note that such behavior is not expected from implementations of Clone::clone in most cases.

§Panics

This method requires the ability to lock the Mutex on the internal event queue. If that Mutex ever becomes poisoned, this method will panic.

Source

pub unsafe fn schedule_now_unchecked_from_boxed( &self, event: Box<dyn Event<State, Time>>, )

Schedule the provided event to execute at the current sim time. Events previously scheduled for “now” will still execute before this event does.

§Safety

This method cannot directly trigger undefined behaviors, but relies on client implementations of Clone::clone producing new values of SimTime that are not less than the cloned receiver (i.e. the current simulation time). If my_sim_time.clone().cmp(my_sim_time) != Ordering::Less is always true for your chosen type, this method will be safe to call.

§Panics

This method requires the ability to lock the Mutex on the internal event queue. If that Mutex ever becomes poisoned, this method will panic.

Source§

impl<State, Time> Simulation<State, Time>
where State: SimState<Time> + Sync, Time: SimTime + Send + Sync + Clone + Add<Output = Time>,

Source

pub fn schedule_with_delay<EventType>( &self, event: EventType, delay: Time, ) -> Result
where EventType: Event<State, Time> + 'static,

Schedule the provided event after the specified delay. The event’s execution time will be equal to the result of self.current_time().clone() + delay.

§Errors

If the calculated execution time is less than the current clock time on self, returns an Error::BackInTime to indicate the likely presence of a logical bug at the call site, with no modifications to the queue.

§Panics

This method requires the ability to lock the Mutex on the internal event queue. If that Mutex ever becomes poisoned, this method will panic.

Source

pub unsafe fn schedule_with_delay_unchecked<EventType>( &self, event: EventType, delay: Time, )
where EventType: Event<State, Time> + 'static,

Schedule the provided event after the specified delay. The event’s execution time will be equal to the result of self.current_time().clone() + delay.

§Safety

This method cannot directly trigger undefined behaviors, but relies on the provided delay being “nonnegative;” in other words that self.current_time().cmp(self.current_time().clone() + delay) != Ordering::Greater should always be true. If you are certain that is true for your type, this method will be safe to call. Alternatively, you may call this method to intentionally schedule an event in the past if your use case truly calls for that.

§Panics

This method requires the ability to lock the Mutex on the internal event queue. If that Mutex ever becomes poisoned, this method will panic.

Source

pub fn schedule_with_delay_from_boxed( &self, event: Box<dyn Event<State, Time>>, delay: Time, ) -> Result

Schedule the provided event after the specified delay. The event’s execution time will be equal to the result of self.current_time().clone() + delay.

§Errors

If the calculated execution time is less than the current clock time on self, returns an Error::BackInTime to indicate the likely presence of a logical bug at the call site, with no modifications to the queue.

§Panics

This method requires the ability to lock the Mutex on the internal event queue. If that Mutex ever becomes poisoned, this method will panic.

Source

pub unsafe fn schedule_with_delay_unchecked_from_boxed( &self, event: Box<dyn Event<State, Time>>, delay: Time, )

Schedule the provided event after the specified delay. The event’s execution time will be equal to the result of self.current_time().clone() + delay.

§Safety

This method cannot directly trigger undefined behaviors, but relies on the provided delay being “nonnegative;” in other words that self.current_time().cmp(self.current_time().clone() + delay) != Ordering::Greater should always be true. If you are certain that is true for your type, this method will be safe to call. Alternatively, you may call this method to intentionally schedule an event in the past if your use case truly calls for that.

§Panics

This method requires the ability to lock the Mutex on the internal event queue. If that Mutex ever becomes poisoned, this method will panic.

Trait Implementations§

Source§

impl<State, Time> Debug for Simulation<State, Time>
where State: SimState<Time> + Sync + Debug, Time: SimTime + Send + Sync + Debug,

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<State, Time> Default for Simulation<State, Time>
where State: SimState<Time> + Sync + Default, Time: SimTime + Send + Sync + Default,

Source§

fn default() -> Simulation<State, Time>

Returns the “default value” for a type. Read more
Source§

impl<State, Time> Display for Simulation<State, Time>
where State: SimState<Time> + Sync, Time: SimTime + Send + Sync,

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<State, Time> !Freeze for Simulation<State, Time>

§

impl<State, Time> RefUnwindSafe for Simulation<State, Time>
where State: RefUnwindSafe, Time: RefUnwindSafe,

§

impl<State, Time> Send for Simulation<State, Time>
where State: Send,

§

impl<State, Time> Sync for Simulation<State, Time>

§

impl<State, Time> Unpin for Simulation<State, Time>
where State: Unpin, Time: Unpin,

§

impl<State, Time> UnwindSafe for Simulation<State, Time>
where State: UnwindSafe, Time: UnwindSafe,

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> 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> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
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.