From 26a961108f32a6db6ec3dd4a9df970f189ad0471 Mon Sep 17 00:00:00 2001 From: Kyrylo Polezhaiev Date: Tue, 30 Mar 2021 03:34:14 +0300 Subject: [PATCH] Replace inner concrete model enum with trait object and dynamic dispatch --- Cargo.toml | 2 +- src/models/mod.rs | 2 +- src/models/model.rs | 91 ++++++++++++++++++---------- tests/simulations.rs | 139 ++++++++++++++++++++++--------------------- 4 files changed, 131 insertions(+), 103 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ad9ce7d..642cb9b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ crate-type = ["cdylib", "rlib"] default = ["console_error_panic_hook"] [dependencies] -enum_dispatch = "0.3" +# enum_dispatch = "0.3" getrandom = { version = "0.2", features = ["js"] } js-sys = "0.3" num-traits = "0.2" diff --git a/src/models/mod.rs b/src/models/mod.rs index f2d2bbd..e7b4b56 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -17,7 +17,7 @@ pub use self::exclusive_gateway::ExclusiveGateway; pub use self::gate::Gate; pub use self::generator::Generator; pub use self::load_balancer::LoadBalancer; -pub use self::model::{AsModel, Model, ModelType}; +pub use self::model::{AsModel, Model/*, ModelType*/}; pub use self::parallel_gateway::ParallelGateway; pub use self::processor::Processor; pub use self::stochastic_gate::StochasticGate; diff --git a/src/models/model.rs b/src/models/model.rs index fa8c2f2..20e402f 100644 --- a/src/models/model.rs +++ b/src/models/model.rs @@ -1,30 +1,32 @@ -use enum_dispatch::enum_dispatch; -use serde::{Deserialize, Serialize}; +// use enum_dispatch::enum_dispatch; +use serde::{Serialize, Serializer}; +use serde::de::{self, Deserialize, Deserializer}; +use std::rc::Rc; +use std::cell::RefCell; -use super::ExclusiveGateway; -use super::Gate; -use super::Generator; -use super::LoadBalancer; +// use super::ExclusiveGateway; +// use super::Gate; +// use super::Generator; +// use super::LoadBalancer; use super::ModelMessage; -use super::ParallelGateway; -use super::Processor; -use super::StochasticGate; -use super::Storage; +// use super::ParallelGateway; +// use super::Processor; +// use super::StochasticGate; +// use super::Storage; use crate::input_modeling::UniformRNG; use crate::utils::error::SimulationError; /// `Model` wraps `ModelType` and provides common ID functionality (a struct /// field and associated accessor method). The simulator requires all models /// to have an ID. -#[derive(Debug, Clone, Serialize, Deserialize)] +//#[derive(/*Debug, Clone, Serialize, Deserialize*/)] pub struct Model { id: String, - #[serde(flatten)] - inner: ModelType, + inner: Rc>, } impl Model { - pub fn new(id: String, inner: ModelType) -> Self { + pub fn new(id: String, inner: Rc>) -> Self { Self { id, inner } } @@ -33,9 +35,32 @@ impl Model { } } +impl Clone for Model { + fn clone(&self) -> Self { + // Fix self.inner cloning + Model { + id: self.id.clone(), + inner: self.inner.clone() + } + } +} + +impl Serialize for Model { + fn serialize(&self, serializer: S) -> Result { + serializer.serialize_str(&self.id) + } +} + +impl<'de> Deserialize<'de> for Model { + fn deserialize>(_: D) -> Result { + Err(de::Error::missing_field("type")) + // deserializer.deserialize_struct(name: &'static str, fields: &'static [&'static str], visitor: V) + } +} + impl AsModel for Model { fn status(&self) -> String { - self.inner.status() + self.inner.borrow().status() } fn events_ext( @@ -43,47 +68,47 @@ impl AsModel for Model { uniform_rng: &mut UniformRNG, incoming_message: ModelMessage, ) -> Result, SimulationError> { - self.inner.events_ext(uniform_rng, incoming_message) + self.inner.borrow_mut().events_ext(uniform_rng, incoming_message) } fn events_int( &mut self, uniform_rng: &mut UniformRNG, ) -> Result, SimulationError> { - self.inner.events_int(uniform_rng) + self.inner.borrow_mut().events_int(uniform_rng) } fn time_advance(&mut self, time_delta: f64) { - self.inner.time_advance(time_delta) + self.inner.borrow_mut().time_advance(time_delta) } fn until_next_event(&self) -> f64 { - self.inner.until_next_event() + self.inner.borrow_mut().until_next_event() } } /// `ModelType` is an enum encompassing all the available model types. Each /// variant holds a concrete type that implements AsModel. -#[enum_dispatch(AsModel)] -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(tag = "type")] -pub enum ModelType { - ExclusiveGateway, - Gate, - Generator, - LoadBalancer, - ParallelGateway, - Processor, - StochasticGate, - Storage, -} +// #[enum_dispatch(AsModel)] +// #[derive(Serialize, Deserialize, Clone, Debug)] +// #[serde(tag = "type")] +// pub enum ModelType { +// ExclusiveGateway, +// Gate, +// Generator, +// LoadBalancer, +// ParallelGateway, +// Processor, +// StochasticGate, +// Storage, +// } /// The `AsModel` trait defines everything required for a model to operate /// within the discrete event simulation. The simulator formalism (Discrete /// Event System Specification) requires `events_ext`, `events_int`, /// `time_advance`, and `until_next_event`. The additional `status` is for /// facilitation of simulation reasoning, reporting, and debugging. -#[enum_dispatch] +// #[enum_dispatch] pub trait AsModel { fn status(&self) -> String; fn events_ext( diff --git a/tests/simulations.rs b/tests/simulations.rs index 8a4475a..097f241 100644 --- a/tests/simulations.rs +++ b/tests/simulations.rs @@ -6,6 +6,9 @@ use sim::models::*; use sim::output_analysis::*; use sim::simulator::*; +use std::rc::Rc; +use std::cell::RefCell; + #[derive(Clone, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] struct ProcessorMetrics { @@ -29,34 +32,34 @@ fn poisson_generator_processor_with_capacity() { let models = [ Model::new( String::from("generator-01"), - ModelType::Generator(Generator::new( + Rc::new(RefCell::new(Generator::new( ContinuousRandomVariable::Exp { lambda: 0.5 }, None, String::from("job"), false, false, - )), + ))), ), Model::new( String::from("processor-01"), - ModelType::Processor(Processor::new( + Rc::new(RefCell::new(Processor::new( ContinuousRandomVariable::Exp { lambda: 0.333333 }, 14, String::from("job"), String::from("processed"), false, false, - )), + ))), ), Model::new( String::from("storage-01"), - ModelType::Storage(Storage::new( + Rc::new(RefCell::new(Storage::new( String::from("store"), String::from("read"), String::from("stored"), false, false, - )), + ))), ), ]; let connectors = [ @@ -516,23 +519,23 @@ fn step_until_activities() { let models = [ Model::new( String::from("generator-01"), - ModelType::Generator(Generator::new( + Rc::new(RefCell::new(Generator::new( ContinuousRandomVariable::Exp { lambda: 0.5 }, None, String::from("job"), false, false, - )), + ))), ), Model::new( String::from("storage-01"), - ModelType::Storage(Storage::new( + Rc::new(RefCell::new(Storage::new( String::from("store"), String::from("read"), String::from("stored"), false, false, - )), + ))), ), ]; let connectors = [Connector::new( @@ -616,34 +619,34 @@ fn non_stationary_generation() { let models = [ Model::new( String::from("generator-01"), - ModelType::Generator(Generator::new( + Rc::new(RefCell::new(Generator::new( ContinuousRandomVariable::Exp { lambda: 0.0957 }, None, String::from("job"), false, false, - )), + ))), ), Model::new( String::from("processor-01"), - ModelType::Processor(Processor::new( + Rc::new(RefCell::new(Processor::new( ContinuousRandomVariable::Exp { lambda: 0.1659 }, 14, String::from("job"), String::from("processed"), false, false, - )), + ))), ), Model::new( String::from("storage-01"), - ModelType::Storage(Storage::new( + Rc::new(RefCell::new(Storage::new( String::from("store"), String::from("read"), String::from("stored"), false, false, - )), + ))), ), ]; let connectors = [ @@ -696,17 +699,17 @@ fn exclusive_gateway_proportions_chi_square() { let models = [ Model::new( String::from("generator-01"), - ModelType::Generator(Generator::new( + Rc::new(RefCell::new(Generator::new( ContinuousRandomVariable::Exp { lambda: 5.0 }, None, String::from("job"), false, false, - )), + ))), ), Model::new( String::from("exclusive-01"), - ModelType::ExclusiveGateway(ExclusiveGateway::new( + Rc::new(RefCell::new(ExclusiveGateway::new( vec![String::from("in")], vec![ String::from("s01"), @@ -718,37 +721,37 @@ fn exclusive_gateway_proportions_chi_square() { }, false, false, - )), + ))), ), Model::new( String::from("storage-01"), - ModelType::Storage(Storage::new( + Rc::new(RefCell::new(Storage::new( String::from("store"), String::from("read"), String::from("stored"), false, false, - )), + ))), ), Model::new( String::from("storage-02"), - ModelType::Storage(Storage::new( + Rc::new(RefCell::new(Storage::new( String::from("store"), String::from("read"), String::from("stored"), false, false, - )), + ))), ), Model::new( String::from("storage-03"), - ModelType::Storage(Storage::new( + Rc::new(RefCell::new(Storage::new( String::from("store"), String::from("read"), String::from("stored"), false, false, - )), + ))), ), ]; let connectors = [ @@ -1046,54 +1049,54 @@ fn gate_blocking_proportions() { let models = [ Model::new( String::from("generator-01"), - ModelType::Generator(Generator::new( + Rc::new(RefCell::new(Generator::new( ContinuousRandomVariable::Exp { lambda: 10.0 }, None, String::from("job"), false, false, - )), + ))), ), Model::new( String::from("generator-02"), - ModelType::Generator(Generator::new( + Rc::new(RefCell::new(Generator::new( ContinuousRandomVariable::Exp { lambda: 10.0 }, None, String::from("job"), false, false, - )), + ))), ), Model::new( String::from("generator-03"), - ModelType::Generator(Generator::new( + Rc::new(RefCell::new(Generator::new( ContinuousRandomVariable::Exp { lambda: 1.0 }, None, String::from("job"), false, false, - )), + ))), ), Model::new( String::from("gate-01"), - ModelType::Gate(Gate::new( + Rc::new(RefCell::new(Gate::new( String::from("job"), String::from("activation"), String::from("deactivation"), String::from("job"), false, false, - )), + ))), ), Model::new( String::from("storage-01"), - ModelType::Storage(Storage::new( + Rc::new(RefCell::new(Storage::new( String::from("store"), String::from("read"), String::from("stored"), false, false, - )), + ))), ), ]; let connectors = [ @@ -1167,17 +1170,17 @@ fn load_balancer_round_robin_outputs() { let models = [ Model::new( String::from("generator-01"), - ModelType::Generator(Generator::new( + Rc::new(RefCell::new(Generator::new( ContinuousRandomVariable::Exp { lambda: 0.01 }, None, String::from("job"), false, false, - )), + ))), ), Model::new( String::from("load-balancer-01"), - ModelType::LoadBalancer(LoadBalancer::new( + Rc::new(RefCell::new(LoadBalancer::new( String::from("request"), vec![ String::from("server-1"), @@ -1186,37 +1189,37 @@ fn load_balancer_round_robin_outputs() { ], false, false, - )), + ))), ), Model::new( String::from("storage-01"), - ModelType::Storage(Storage::new( + Rc::new(RefCell::new(Storage::new( String::from("store"), String::from("read"), String::from("stored"), false, false, - )), + ))), ), Model::new( String::from("storage-02"), - ModelType::Storage(Storage::new( + Rc::new(RefCell::new(Storage::new( String::from("store"), String::from("read"), String::from("stored"), false, false, - )), + ))), ), Model::new( String::from("storage-03"), - ModelType::Storage(Storage::new( + Rc::new(RefCell::new(Storage::new( String::from("store"), String::from("read"), String::from("stored"), false, false, - )), + ))), ), ]; let connectors = [ @@ -1278,23 +1281,23 @@ fn injection_initiated_stored_value_exchange() { let models = [ Model::new( String::from("storage-01"), - ModelType::Storage(Storage::new( + Rc::new(RefCell::new(Storage::new( String::from("store"), String::from("read"), String::from("stored"), false, false, - )), + ))), ), Model::new( String::from("storage-02"), - ModelType::Storage(Storage::new( + Rc::new(RefCell::new(Storage::new( String::from("store"), String::from("read"), String::from("stored"), false, false, - )), + ))), ), ]; let connectors = [ @@ -1352,17 +1355,17 @@ fn parallel_gateway_splits_and_joins() { let models = [ Model::new( String::from("generator-01"), - ModelType::Generator(Generator::new( + Rc::new(RefCell::new(Generator::new( ContinuousRandomVariable::Exp { lambda: 5.0 }, None, String::from("job"), false, false, - )), + ))), ), Model::new( String::from("parallel-01"), - ModelType::ParallelGateway(ParallelGateway::new( + Rc::new(RefCell::new(ParallelGateway::new( vec![String::from("in")], vec![ String::from("alpha"), @@ -1371,11 +1374,11 @@ fn parallel_gateway_splits_and_joins() { ], false, false, - )), + ))), ), Model::new( String::from("parallel-02"), - ModelType::ParallelGateway(ParallelGateway::new( + Rc::new(RefCell::new(ParallelGateway::new( vec![ String::from("alpha"), String::from("beta"), @@ -1384,17 +1387,17 @@ fn parallel_gateway_splits_and_joins() { vec![String::from("out")], false, false, - )), + ))), ), Model::new( String::from("storage-01"), - ModelType::Storage(Storage::new( + Rc::new(RefCell::new(Storage::new( String::from("store"), String::from("read"), String::from("stored"), false, false, - )), + ))), ), ]; let connectors = [ @@ -1463,17 +1466,17 @@ fn match_status_reporting() { let models = [ Model::new( String::from("generator-01"), - ModelType::Generator(Generator::new( + Rc::new(RefCell::new(Generator::new( ContinuousRandomVariable::Exp { lambda: 5.0 }, None, String::from("job"), false, false, - )), + ))), ), Model::new( String::from("load-balancer-01"), - ModelType::LoadBalancer(LoadBalancer::new( + Rc::new(RefCell::new(LoadBalancer::new( String::from("request"), vec![ String::from("alpha"), @@ -1482,7 +1485,7 @@ fn match_status_reporting() { ], false, false, - )), + ))), ), ]; let connectors = []; @@ -1496,33 +1499,33 @@ fn stochastic_gate_blocking() { let models = [ Model::new( String::from("generator-01"), - ModelType::Generator(Generator::new( + Rc::new(RefCell::new(Generator::new( ContinuousRandomVariable::Exp { lambda: 5.0 }, None, String::from("job"), false, false, - )), + ))), ), Model::new( String::from("stochastic-gate-01"), - ModelType::StochasticGate(StochasticGate::new( + Rc::new(RefCell::new(StochasticGate::new( BooleanRandomVariable::Bernoulli { p: 0.2 }, String::from("job"), String::from("job"), false, false, - )), + ))), ), Model::new( String::from("storage-01"), - ModelType::Storage(Storage::new( + Rc::new(RefCell::new(Storage::new( String::from("store"), String::from("read"), String::from("stored"), false, false, - )), + ))), ), ]; let connectors = [