forked from ROMEO/nexosim
Introduce ProtoModel trait, remove Model::setup
The external_input example has been as well adapted and (at least temporarily) simplifiedi/modified to remove the dependencies on `atomic_wait` and `mio`.
This commit is contained in:
@ -1,19 +1,39 @@
|
||||
//! Model components.
|
||||
//!
|
||||
//! # Model trait
|
||||
//! # Models and model prototypes
|
||||
//!
|
||||
//! Every model must implement the [`Model`] trait. This trait defines
|
||||
//! * a setup method, [`Model::setup()`], which main purpose is to create,
|
||||
//! connect and add to the simulation bench submodels and perform other setup
|
||||
//! steps,
|
||||
//! * an asynchronous initialization method, [`Model::init()`], which main
|
||||
//! purpose is to enable models to perform specific actions only once all
|
||||
//! models have been connected and migrated to the simulation, but before the
|
||||
//! simulation actually starts.
|
||||
//! Every model must implement the [`Model`] trait. This trait defines an
|
||||
//! asynchronous initialization method, [`Model::init`], which main purpose is
|
||||
//! to enable models to perform specific actions when the simulation starts,
|
||||
//! i.e. after all models have been connected and added to the simulation.
|
||||
//!
|
||||
//! It is frequently convenient to expose to users a model builder type—called a
|
||||
//! *model prototype*—rather than the final model. This can be done by
|
||||
//! implementing the `ProtoModel`, which defines the associated model
|
||||
//! type and a [`ProtoModel::build` method`] invoked when a model is added the
|
||||
//! the simulation and returning the actual model instance.
|
||||
//!
|
||||
//! Prototype models can be used whenever the Rust builder pattern is helpful,
|
||||
//! for instance to set optional parameters. One of the use-cases that may
|
||||
//! benefit from the use of prototype models, however, is hierarchical model
|
||||
//! building. When a parent model contains sub-models, these sub-models are
|
||||
//! often an implementation detail that needs not be exposed to the user. One
|
||||
//! may then define a prototype model that contains all outputs and requestors
|
||||
//! ports, which upon invocation of `ProtoModel::build()` are moved to the
|
||||
//! appropriate sub-models (note that the `build` method also allows adding
|
||||
//! sub-models to the simulation).
|
||||
//!
|
||||
//! Note that a trivial `ProtoModel` implementation is generated by default for
|
||||
//! any object implementing the `Model` trait, where the associated
|
||||
//! `ProtoModel::Model` type is the model type itself and where
|
||||
//! `ProtoModel::build` simply returns the model instance. This is what makes it
|
||||
//! possible to use either an explicitly-defined `ProtoModel` as argument to the
|
||||
//! [`SimInit::add_model`](crate::simulation::SimInit::add_model) method, or a
|
||||
//! plain `Model` type.
|
||||
//!
|
||||
//! #### Examples
|
||||
//!
|
||||
//! A model that does not require setup and initialization can simply use the
|
||||
//! A model that does not require initialization or building can simply use the
|
||||
//! default implementation of the `Model` trait:
|
||||
//!
|
||||
//! ```
|
||||
@ -25,27 +45,19 @@
|
||||
//! impl Model for MyModel {}
|
||||
//! ```
|
||||
//!
|
||||
//! Otherwise, custom `setup()` or `init()` methods can be implemented:
|
||||
//! If a default action is required during simulation initialization, the `init`
|
||||
//! methods can be explicitly implemented:
|
||||
//!
|
||||
//! ```
|
||||
//! use std::future::Future;
|
||||
//! use std::pin::Pin;
|
||||
//!
|
||||
//! use asynchronix::model::{Context, InitializedModel, Model, SetupContext};
|
||||
//! use asynchronix::model::{Context, InitializedModel, Model};
|
||||
//!
|
||||
//! pub struct MyModel {
|
||||
//! // ...
|
||||
//! }
|
||||
//! impl Model for MyModel {
|
||||
//! fn setup(
|
||||
//! &mut self,
|
||||
//! setup_context: &SetupContext<Self>) {
|
||||
//! println!("...setup...");
|
||||
//! }
|
||||
//!
|
||||
//! async fn init(
|
||||
//! mut self,
|
||||
//! context: &Context<Self>
|
||||
//! ctx: &Context<Self>
|
||||
//! ) -> InitializedModel<Self> {
|
||||
//! println!("...initialization...");
|
||||
//!
|
||||
@ -54,6 +66,61 @@
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Finally, if a model builder is required, the `ProtoModel` trait can be
|
||||
//! explicitly implemented:
|
||||
//!
|
||||
//! ```
|
||||
//! use asynchronix::model::{BuildContext, InitializedModel, Model, ProtoModel};
|
||||
//! use asynchronix::ports::Output;
|
||||
//!
|
||||
//! /// The final model.
|
||||
//! pub struct Multiplier {
|
||||
//! // Private outputs and requestors stored in a form that constitutes an
|
||||
//! // implementation detail and should not be exposed to the user.
|
||||
//! my_outputs: Vec<Output<usize>>
|
||||
//! }
|
||||
//! impl Multiplier {
|
||||
//! // Private constructor: the final model is only built by the prototype
|
||||
//! // model.
|
||||
//! fn new(
|
||||
//! value_times_1: Output<usize>,
|
||||
//! value_times_2: Output<usize>,
|
||||
//! value_times_3: Output<usize>,
|
||||
//! ) -> Self {
|
||||
//! Self {
|
||||
//! my_outputs: vec![value_times_1, value_times_2, value_times_3]
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! // Public inputs and repliers to be used by the user during bench
|
||||
//! // construction.
|
||||
//! pub async fn my_input(&mut self, my_data: usize) {
|
||||
//! for (i, output) in self.my_outputs.iter_mut().enumerate() {
|
||||
//! output.send(my_data*(i + 1)).await;
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
//! impl Model for Multiplier {}
|
||||
//!
|
||||
//! pub struct ProtoMultiplier {
|
||||
//! // Prettyfied outputs exposed to the user.
|
||||
//! pub value_times_1: Output<usize>,
|
||||
//! pub value_times_2: Output<usize>,
|
||||
//! pub value_times_3: Output<usize>,
|
||||
//! }
|
||||
//! impl ProtoModel for ProtoMultiplier {
|
||||
//! type Model = Multiplier;
|
||||
//!
|
||||
//! fn build(
|
||||
//! mut self,
|
||||
//! _: &BuildContext<Self>
|
||||
//! ) -> Multiplier {
|
||||
//! Multiplier::new(self.value_times_1, self.value_times_2, self.value_times_3)
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//!
|
||||
//! # Events and queries
|
||||
//!
|
||||
//! Models can exchange data via *events* and *queries*.
|
||||
@ -169,57 +236,22 @@
|
||||
|
||||
use std::future::Future;
|
||||
|
||||
pub use context::{Context, SetupContext};
|
||||
pub use context::{BuildContext, Context};
|
||||
|
||||
mod context;
|
||||
|
||||
/// Trait to be implemented by all models.
|
||||
/// Trait to be implemented by simulation models.
|
||||
///
|
||||
/// This trait enables models to perform specific actions during setup and
|
||||
/// initialization. The [`Model::setup()`] method is run only once when models
|
||||
/// are being added to the simulation bench. This method allows in particular
|
||||
/// sub-models to be created, connected and added to the simulation.
|
||||
///
|
||||
/// The [`Model::init()`] method is run only once all models have been connected and
|
||||
/// migrated to the simulation bench, but before the simulation actually starts.
|
||||
/// A common use for `init` is to send messages to connected models at the
|
||||
/// beginning of the simulation.
|
||||
/// This trait enables models to perform specific actions during initialization.
|
||||
/// The [`Model::init()`] method is run only once all models have been connected
|
||||
/// and migrated to the simulation bench, but before the simulation actually
|
||||
/// starts. A common use for `init` is to send messages to connected models at
|
||||
/// the beginning of the simulation.
|
||||
///
|
||||
/// The `init` function converts the model to the opaque `InitializedModel` type
|
||||
/// to prevent an already initialized model from being added to the simulation
|
||||
/// bench.
|
||||
pub trait Model: Sized + Send + 'static {
|
||||
/// Performs model setup.
|
||||
///
|
||||
/// This method is executed exactly once for all models of the simulation
|
||||
/// when the [`SimInit::add_model()`](crate::simulation::SimInit::add_model)
|
||||
/// method is called.
|
||||
///
|
||||
/// The default implementation does nothing.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::future::Future;
|
||||
/// use std::pin::Pin;
|
||||
///
|
||||
/// use asynchronix::model::{InitializedModel, Model, SetupContext};
|
||||
///
|
||||
/// pub struct MyModel {
|
||||
/// // ...
|
||||
/// }
|
||||
///
|
||||
/// impl Model for MyModel {
|
||||
/// fn setup(
|
||||
/// &mut self,
|
||||
/// setup_context: &SetupContext<Self>
|
||||
/// ) {
|
||||
/// println!("...setup...");
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
fn setup(&mut self, _: &SetupContext<Self>) {}
|
||||
|
||||
/// Performs asynchronous model initialization.
|
||||
///
|
||||
/// This asynchronous method is executed exactly once for all models of the
|
||||
@ -271,3 +303,36 @@ impl<M: Model> From<M> for InitializedModel<M> {
|
||||
InitializedModel(model)
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait to be implemented by model prototypes.
|
||||
///
|
||||
/// This trait makes it possible to build the final model from a builder type
|
||||
/// when it is added to the simulation.
|
||||
///
|
||||
/// The [`ProtoModel::build()`] method consumes the prototype. It is
|
||||
/// automatically called when a model or submodel prototype is added to the
|
||||
/// simulation using
|
||||
/// [`Simulation::add_model()`](crate::simulation::SimInit::add_model) or
|
||||
/// [`BuildContext::add_submodel`].
|
||||
///
|
||||
/// The
|
||||
pub trait ProtoModel: Sized {
|
||||
/// Type of the model to be built.
|
||||
type Model: Model;
|
||||
|
||||
/// Builds the model.
|
||||
///
|
||||
/// This method is invoked when the
|
||||
/// [`SimInit::add_model()`](crate::simulation::SimInit::add_model) or
|
||||
/// [`BuildContext::add_submodel`] method is called.
|
||||
fn build(self, ctx: &BuildContext<Self>) -> Self::Model;
|
||||
}
|
||||
|
||||
// Every model can be used as a prototype for itself.
|
||||
impl<M: Model> ProtoModel for M {
|
||||
type Model = Self;
|
||||
|
||||
fn build(self, _: &BuildContext<Self>) -> Self::Model {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use std::fmt;
|
||||
use crate::executor::Executor;
|
||||
use crate::simulation::{self, LocalScheduler, Mailbox};
|
||||
|
||||
use super::Model;
|
||||
use super::{Model, ProtoModel};
|
||||
|
||||
/// A local context for models.
|
||||
///
|
||||
@ -95,75 +95,102 @@ impl<M: Model> fmt::Debug for Context<M> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A setup context for models.
|
||||
/// Context available when building a model from a model prototype.
|
||||
///
|
||||
/// A `SetupContext` can be used by models during the setup stage to
|
||||
/// create submodels and add them to the simulation bench.
|
||||
/// A `BuildContext` can be used to add the sub-models of a hierarchical model
|
||||
/// to the simulation bench.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// A model that contains two connected submodels.
|
||||
/// A model that multiplies its input by four using two sub-models that each
|
||||
/// multiply their input by two.
|
||||
///
|
||||
/// ```text
|
||||
/// ┌───────────────────────────────────────┐
|
||||
/// │ MyltiplyBy4 │
|
||||
/// │ ┌─────────────┐ ┌─────────────┐ │
|
||||
/// │ │ │ │ │ │
|
||||
/// Input ●─────┼──►│ MultiplyBy2 ├──►│ MultiplyBy2 ├───┼─────► Output
|
||||
/// f64 │ │ │ │ │ │ f64
|
||||
/// │ └─────────────┘ └─────────────┘ │
|
||||
/// │ │
|
||||
/// └───────────────────────────────────────┘
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use std::time::Duration;
|
||||
/// use asynchronix::model::{Model, SetupContext};
|
||||
/// use asynchronix::model::{BuildContext, Model, ProtoModel};
|
||||
/// use asynchronix::ports::Output;
|
||||
/// use asynchronix::simulation::Mailbox;
|
||||
///
|
||||
/// #[derive(Default)]
|
||||
/// pub struct SubmodelA {
|
||||
/// out: Output<u32>,
|
||||
/// struct MultiplyBy2 {
|
||||
/// pub output: Output<i32>,
|
||||
/// }
|
||||
/// impl MultiplyBy2 {
|
||||
/// pub async fn input(&mut self, value: i32) {
|
||||
/// self.output.send(value * 2).await;
|
||||
/// }
|
||||
/// }
|
||||
/// impl Model for MultiplyBy2 {}
|
||||
///
|
||||
/// impl Model for SubmodelA {}
|
||||
/// pub struct MultiplyBy4 {
|
||||
/// // Private forwarding output.
|
||||
/// forward: Output<i32>,
|
||||
/// }
|
||||
/// impl MultiplyBy4 {
|
||||
/// pub async fn input(&mut self, value: i32) {
|
||||
/// self.forward.send(value).await;
|
||||
/// }
|
||||
/// }
|
||||
/// impl Model for MultiplyBy4 {}
|
||||
///
|
||||
/// #[derive(Default)]
|
||||
/// pub struct SubmodelB {}
|
||||
/// pub struct ProtoMultiplyBy4 {
|
||||
/// pub output: Output<i32>,
|
||||
/// }
|
||||
/// impl ProtoModel for ProtoMultiplyBy4 {
|
||||
/// type Model = MultiplyBy4;
|
||||
///
|
||||
/// impl SubmodelB {
|
||||
/// pub async fn input(&mut self, value: u32) {
|
||||
/// println!("Received {}", value);
|
||||
/// fn build(
|
||||
/// self,
|
||||
/// ctx: &BuildContext<Self>)
|
||||
/// -> MultiplyBy4 {
|
||||
/// let mut mult = MultiplyBy4 { forward: Output::default() };
|
||||
/// let mut submult1 = MultiplyBy2::default();
|
||||
///
|
||||
/// // Move the prototype's output to the second multiplier.
|
||||
/// let mut submult2 = MultiplyBy2 { output: self.output };
|
||||
///
|
||||
/// // Forward the parent's model input to the first multiplier.
|
||||
/// let submult1_mbox = Mailbox::new();
|
||||
/// mult.forward.connect(MultiplyBy2::input, &submult1_mbox);
|
||||
///
|
||||
/// // Connect the two multiplier submodels.
|
||||
/// let submult2_mbox = Mailbox::new();
|
||||
/// submult1.output.connect(MultiplyBy2::input, &submult2_mbox);
|
||||
///
|
||||
/// // Add the submodels to the simulation.
|
||||
/// ctx.add_submodel(submult1, submult1_mbox, "submultiplier 1");
|
||||
/// ctx.add_submodel(submult2, submult2_mbox, "submultiplier 2");
|
||||
///
|
||||
/// mult
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// impl Model for SubmodelB {}
|
||||
///
|
||||
/// #[derive(Default)]
|
||||
/// pub struct Parent {}
|
||||
///
|
||||
/// impl Model for Parent {
|
||||
/// fn setup(
|
||||
/// &mut self,
|
||||
/// setup_context: &SetupContext<Self>) {
|
||||
/// let mut a = SubmodelA::default();
|
||||
/// let b = SubmodelB::default();
|
||||
/// let a_mbox = Mailbox::new();
|
||||
/// let b_mbox = Mailbox::new();
|
||||
/// let a_name = setup_context.name().to_string() + "::a";
|
||||
/// let b_name = setup_context.name().to_string() + "::b";
|
||||
///
|
||||
/// a.out.connect(SubmodelB::input, &b_mbox);
|
||||
///
|
||||
/// setup_context.add_model(a, a_mbox, a_name);
|
||||
/// setup_context.add_model(b, b_mbox, b_name);
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// ```
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SetupContext<'a, M: Model> {
|
||||
pub struct BuildContext<'a, P: ProtoModel> {
|
||||
/// Mailbox of the model.
|
||||
pub mailbox: &'a Mailbox<M>,
|
||||
context: &'a Context<M>,
|
||||
pub mailbox: &'a Mailbox<P::Model>,
|
||||
context: &'a Context<P::Model>,
|
||||
executor: &'a Executor,
|
||||
}
|
||||
|
||||
impl<'a, M: Model> SetupContext<'a, M> {
|
||||
impl<'a, P: ProtoModel> BuildContext<'a, P> {
|
||||
/// Creates a new local context.
|
||||
pub(crate) fn new(
|
||||
mailbox: &'a Mailbox<M>,
|
||||
context: &'a Context<M>,
|
||||
mailbox: &'a Mailbox<P::Model>,
|
||||
context: &'a Context<P::Model>,
|
||||
executor: &'a Executor,
|
||||
) -> Self {
|
||||
Self {
|
||||
@ -178,16 +205,26 @@ impl<'a, M: Model> SetupContext<'a, M> {
|
||||
&self.context.name
|
||||
}
|
||||
|
||||
/// Adds a new model and its mailbox to the simulation bench.
|
||||
/// Adds a sub-model to the simulation bench.
|
||||
///
|
||||
/// The `name` argument needs not be unique (it can be an empty string) and
|
||||
/// is used for convenience for model instance identification (e.g. for
|
||||
/// logging purposes).
|
||||
pub fn add_model<N: Model>(&self, model: N, mailbox: Mailbox<N>, name: impl Into<String>) {
|
||||
/// The `name` argument needs not be unique. If an empty string is provided,
|
||||
/// it is replaced by the string `<unknown>`.
|
||||
///
|
||||
/// The provided name is appended to that of the parent model using a dot as
|
||||
/// a separator (e.g. `parent_name.child_name`) to build an identifier. This
|
||||
/// identifier is used for logging or error-reporting purposes.
|
||||
pub fn add_submodel<S: ProtoModel>(
|
||||
&self,
|
||||
model: S,
|
||||
mailbox: Mailbox<S::Model>,
|
||||
name: impl Into<String>,
|
||||
) {
|
||||
let mut submodel_name = name.into();
|
||||
if !self.context.name().is_empty() && !submodel_name.is_empty() {
|
||||
submodel_name = self.context.name().to_string() + "." + &submodel_name;
|
||||
}
|
||||
if submodel_name.is_empty() {
|
||||
submodel_name = String::from("<unknown>");
|
||||
};
|
||||
submodel_name = self.context.name().to_string() + "." + &submodel_name;
|
||||
|
||||
simulation::add_model(
|
||||
model,
|
||||
mailbox,
|
||||
|
@ -19,18 +19,18 @@
|
||||
//!
|
||||
//! #### Example
|
||||
//!
|
||||
//! This example demonstrates a submodel inside a parent model. The output of
|
||||
//! the submodel is a clone of the parent model output. Both outputs remain
|
||||
//! therefore always connected to the same inputs.
|
||||
//! This example demonstrates two submodels inside a parent model. The output of
|
||||
//! the submodel and of the main model are clones and remain therefore always
|
||||
//! connected to the same inputs.
|
||||
//!
|
||||
//! For a more comprehensive example demonstrating output cloning in submodels
|
||||
//! For a more comprehensive example demonstrating hierarchical model
|
||||
//! assemblies, see the [`assembly example`][assembly].
|
||||
//!
|
||||
//! [assembly]:
|
||||
//! https://github.com/asynchronics/asynchronix/tree/main/asynchronix/examples/assembly.rs
|
||||
//!
|
||||
//! ```
|
||||
//! use asynchronix::model::{Model, SetupContext};
|
||||
//! use asynchronix::model::{BuildContext, Model, ProtoModel};
|
||||
//! use asynchronix::ports::Output;
|
||||
//! use asynchronix::simulation::Mailbox;
|
||||
//!
|
||||
@ -39,9 +39,9 @@
|
||||
//! }
|
||||
//!
|
||||
//! impl ChildModel {
|
||||
//! pub fn new() -> Self {
|
||||
//! pub fn new(output: Output<u64>) -> Self {
|
||||
//! Self {
|
||||
//! output: Default::default(),
|
||||
//! output,
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
@ -49,10 +49,16 @@
|
||||
//! impl Model for ChildModel {}
|
||||
//!
|
||||
//! pub struct ParentModel {
|
||||
//! output: Output<u64>,
|
||||
//! }
|
||||
//!
|
||||
//! impl Model for ParentModel {}
|
||||
//!
|
||||
//! pub struct ProtoParentModel {
|
||||
//! pub output: Output<u64>,
|
||||
//! }
|
||||
//!
|
||||
//! impl ParentModel {
|
||||
//! impl ProtoParentModel {
|
||||
//! pub fn new() -> Self {
|
||||
//! Self {
|
||||
//! output: Default::default(),
|
||||
@ -60,13 +66,15 @@
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! impl Model for ParentModel {
|
||||
//! fn setup(&mut self, setup_context: &SetupContext<Self>) {
|
||||
//! let mut child = ChildModel::new();
|
||||
//! let child_mbox = Mailbox::new();
|
||||
//! child.output = self.output.clone();
|
||||
//! let child_name = setup_context.name().to_string() + "::child";
|
||||
//! setup_context.add_model(child, child_mbox, child_name);
|
||||
//! impl ProtoModel for ProtoParentModel {
|
||||
//! type Model = ParentModel;
|
||||
//!
|
||||
//! fn build(self, ctx: &BuildContext<Self>) -> ParentModel {
|
||||
//! let mut child = ChildModel::new(self.output.clone());
|
||||
//!
|
||||
//! ctx.add_submodel(child, Mailbox::new(), "child");
|
||||
//!
|
||||
//! ParentModel { output: self.output }
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
|
@ -146,7 +146,7 @@ use recycle_box::{coerce_box, RecycleBox};
|
||||
|
||||
use crate::channel::ChannelObserver;
|
||||
use crate::executor::{Executor, ExecutorError};
|
||||
use crate::model::{Context, Model, SetupContext};
|
||||
use crate::model::{BuildContext, Context, Model, ProtoModel};
|
||||
use crate::ports::{InputFn, ReplierFn};
|
||||
use crate::time::{AtomicTime, Clock, MonotonicTime};
|
||||
use crate::util::seq_futures::SeqFuture;
|
||||
@ -647,9 +647,9 @@ impl From<SchedulingError> for SimulationError {
|
||||
}
|
||||
|
||||
/// Adds a model and its mailbox to the simulation bench.
|
||||
pub(crate) fn add_model<M: Model>(
|
||||
mut model: M,
|
||||
mailbox: Mailbox<M>,
|
||||
pub(crate) fn add_model<P: ProtoModel>(
|
||||
model: P,
|
||||
mailbox: Mailbox<P::Model>,
|
||||
name: String,
|
||||
scheduler: Scheduler,
|
||||
executor: &Executor,
|
||||
@ -658,9 +658,9 @@ pub(crate) fn add_model<M: Model>(
|
||||
let span = tracing::span!(target: env!("CARGO_PKG_NAME"), tracing::Level::INFO, "model", name);
|
||||
|
||||
let context = Context::new(name, LocalScheduler::new(scheduler, mailbox.address()));
|
||||
let setup_context = SetupContext::new(&mailbox, &context, executor);
|
||||
let build_context = BuildContext::new(&mailbox, &context, executor);
|
||||
|
||||
model.setup(&setup_context);
|
||||
let model = model.build(&build_context);
|
||||
|
||||
let mut receiver = mailbox.0;
|
||||
let fut = async move {
|
||||
|
@ -3,7 +3,7 @@ use std::sync::{Arc, Mutex};
|
||||
|
||||
use crate::channel::ChannelObserver;
|
||||
use crate::executor::{Executor, SimulationContext};
|
||||
use crate::model::Model;
|
||||
use crate::model::ProtoModel;
|
||||
use crate::time::{AtomicTime, MonotonicTime, TearableAtomicTime};
|
||||
use crate::time::{Clock, NoClock};
|
||||
use crate::util::priority_queue::PriorityQueue;
|
||||
@ -57,13 +57,13 @@ impl SimInit {
|
||||
|
||||
/// Adds a model and its mailbox to the simulation bench.
|
||||
///
|
||||
/// The `name` argument needs not be unique (it can be the empty string) and
|
||||
/// is used for convenience for the model instance identification (e.g. for
|
||||
/// logging purposes).
|
||||
pub fn add_model<M: Model>(
|
||||
/// The `name` argument needs not be unique. If an empty string is provided,
|
||||
/// it is replaced by the string `<unknown>`. This name serves an identifier
|
||||
/// for logging or error-reporting purposes.
|
||||
pub fn add_model<P: ProtoModel>(
|
||||
mut self,
|
||||
model: M,
|
||||
mailbox: Mailbox<M>,
|
||||
model: P,
|
||||
mailbox: Mailbox<P::Model>,
|
||||
name: impl Into<String>,
|
||||
) -> Self {
|
||||
let name = name.into();
|
||||
|
@ -22,7 +22,7 @@ pub(crate) struct CachedRwLock<T: Clone> {
|
||||
}
|
||||
|
||||
impl<T: Clone> CachedRwLock<T> {
|
||||
/// Creates a new cached read-write lock in an ulocked state.
|
||||
/// Creates a new cached read-write lock in unlocked state.
|
||||
pub(crate) fn new(t: T) -> Self {
|
||||
let shared = t.clone();
|
||||
Self {
|
||||
|
Reference in New Issue
Block a user