use std::f64::INFINITY;
use js_sys::Array;
use serde::{Deserialize, Serialize};
use wasm_bindgen::prelude::*;
use crate::input_modeling::uniform_rng::UniformRNG;
use crate::models::model::Model;
use crate::models::ModelMessage;
use crate::utils;
use crate::utils::error::SimulationError;
mod test_simulations;
#[derive(Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Simulation {
models: Vec<Box<dyn Model>>,
connectors: Vec<Connector>,
messages: Vec<Message>,
global_time: f64,
#[serde(skip_serializing)]
uniform_rng: UniformRNG,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Connector {
id: String,
#[serde(rename = "sourceID")]
source_id: String,
#[serde(rename = "targetID")]
target_id: String,
source_port: String,
target_port: String,
}
#[wasm_bindgen]
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Message {
source_id: String,
source_port: String,
target_id: String,
target_port: String,
time: f64,
message: String,
}
impl Simulation {
pub fn post(models: Vec<Box<dyn Model>>, connectors: Vec<Connector>) -> Self {
utils::set_panic_hook();
Self {
models,
connectors,
..Self::default()
}
}
pub fn put(&mut self, models: Vec<Box<dyn Model>>, connectors: Vec<Connector>) {
self.models = models;
self.connectors = connectors;
}
pub fn get_messages(&self) -> &Vec<Message> {
&self.messages
}
pub fn get_global_time(&self) -> f64 {
self.global_time
}
pub fn status(&self, model_id: &str) -> Result<String, SimulationError> {
Ok(self
.models
.iter()
.find(|model| model.id() == model_id)
.ok_or_else(|| SimulationError::ModelNotFound)?
.status())
}
pub fn reset(&mut self) {
self.reset_messages();
self.reset_global_time();
}
pub fn reset_messages(&mut self) {
self.messages = Vec::new();
}
pub fn reset_global_time(&mut self) {
self.global_time = 0.0;
}
pub fn models(&mut self) -> Vec<&mut Box<dyn Model>> {
self.models.iter_mut().collect()
}
fn get_message_target_ids(&self, source_id: &str, source_port: &str) -> Vec<String> {
self.connectors
.iter()
.filter_map(|connector| {
if connector.source_id == source_id && connector.source_port == source_port {
Some(connector.target_id.to_string())
} else {
None
}
})
.collect()
}
fn get_message_target_ports(&self, source_id: &str, source_port: &str) -> Vec<String> {
self.connectors
.iter()
.filter_map(|connector| {
if connector.source_id == source_id && connector.source_port == source_port {
Some(connector.target_port.to_string())
} else {
None
}
})
.collect()
}
pub fn inject_input(&mut self, message: Message) {
self.messages.push(message);
}
pub fn step(&mut self) -> Result<Vec<Message>, SimulationError> {
let messages = self.messages.clone();
let mut next_messages: Vec<Message> = Vec::new();
if !messages.is_empty() {
(0..self.models.len())
.map(|model_index| -> Result<(), SimulationError> {
let model_messages: Vec<ModelMessage> = messages
.iter()
.filter_map(|message| {
if message.target_id == self.models[model_index].id() {
Some(ModelMessage {
port_name: message.target_port.clone(),
message: message.message.clone(),
})
} else {
None
}
})
.collect();
model_messages
.iter()
.map(|model_message| -> Result<(), SimulationError> {
self.models[model_index]
.events_ext(&mut self.uniform_rng, model_message.clone())?
.iter()
.for_each(|outgoing_message| {
let target_ids = self.get_message_target_ids(
&self.models[model_index].id(), &outgoing_message.port_name, );
let target_ports = self.get_message_target_ports(
&self.models[model_index].id(), &outgoing_message.port_name, );
target_ids.iter().zip(target_ports.iter()).for_each(
|(target_id, target_port)| {
next_messages.push(Message {
source_id: self.models[model_index].id(),
source_port: outgoing_message.port_name.clone(),
target_id: target_id.clone(),
target_port: target_port.clone(),
time: self.global_time,
message: outgoing_message.message.clone(),
});
},
);
});
Ok(())
})
.fold(Ok(()), |a, b| b.and(a))
})
.fold(Ok(()), |a, b| b.and(a))?
}
let until_next_event: f64;
if self.messages.is_empty() {
until_next_event = self.models().iter().fold(INFINITY, |min, model| {
f64::min(min, model.until_next_event())
});
} else {
until_next_event = 0.0;
}
self.models().iter_mut().for_each(|model| {
model.time_advance(until_next_event);
});
self.global_time += until_next_event;
(0..self.models.len())
.map(|model_index| -> Result<(), SimulationError> {
self.models[model_index]
.events_int(&mut self.uniform_rng)?
.iter()
.for_each(|outgoing_message| {
let target_ids = self.get_message_target_ids(
&self.models[model_index].id(), &outgoing_message.port_name, );
let target_ports = self.get_message_target_ports(
&self.models[model_index].id(), &outgoing_message.port_name, );
target_ids.iter().zip(target_ports.iter()).for_each(
|(target_id, target_port)| {
next_messages.push(Message {
source_id: self.models[model_index].id(),
source_port: outgoing_message.port_name.clone(),
target_id: target_id.clone(),
target_port: target_port.clone(),
time: self.global_time,
message: outgoing_message.message.clone(),
});
},
);
});
Ok(())
})
.fold(Ok(()), |a, b| b.and(a))?;
self.messages = next_messages;
Ok(self.get_messages().to_vec())
}
pub fn step_until(&mut self, until: f64) -> Result<Vec<Message>, SimulationError> {
let mut message_records: Vec<Message> = Vec::new();
loop {
self.step()?;
if self.global_time < until {
message_records.extend(self.get_messages().clone());
} else {
break;
}
}
Ok(message_records)
}
fn step_n(&mut self, n: usize) -> Result<Vec<Message>, SimulationError> {
let mut message_records: Vec<Message> = Vec::new();
(0..n)
.map(|_| -> Result<Vec<Message>, SimulationError> {
self.step()?;
message_records.extend(self.messages.clone());
Ok(Vec::new())
})
.find(|result| result.is_err())
.unwrap_or(Ok(message_records))
}
}
#[wasm_bindgen]
#[derive(Default, Serialize, Deserialize)]
pub struct WebSimulation {
simulation: Simulation,
}
#[wasm_bindgen]
impl WebSimulation {
pub fn post_json(models: &str, connectors: &str) -> Self {
utils::set_panic_hook();
Self {
simulation: Simulation {
models: serde_json::from_str(models).unwrap(),
connectors: serde_json::from_str(connectors).unwrap(),
..Simulation::default()
},
}
}
pub fn put_json(&mut self, models: &str, connectors: &str) {
self.simulation.models = serde_json::from_str(models).unwrap();
self.simulation.connectors = serde_json::from_str(connectors).unwrap();
}
pub fn get_json(&self) -> String {
serde_json::to_string_pretty(&self.simulation).unwrap()
}
pub fn post_yaml(models: &str, connectors: &str) -> WebSimulation {
utils::set_panic_hook();
Self {
simulation: Simulation {
models: serde_yaml::from_str(models).unwrap(),
connectors: serde_yaml::from_str(connectors).unwrap(),
..Simulation::default()
},
}
}
pub fn put_yaml(&mut self, models: &str, connectors: &str) {
self.simulation.models = serde_yaml::from_str(models).unwrap();
self.simulation.connectors = serde_yaml::from_str(connectors).unwrap();
}
pub fn get_yaml(&self) -> String {
serde_yaml::to_string(&self.simulation).unwrap()
}
pub fn get_messages_js(&self) -> Array {
self.simulation
.get_messages()
.clone()
.into_iter()
.map(JsValue::from)
.collect()
}
pub fn get_messages_json(&self) -> String {
serde_json::to_string(&self.simulation.get_messages()).unwrap()
}
pub fn get_messages_yaml(&self) -> String {
serde_yaml::to_string(&self.simulation.get_messages()).unwrap()
}
pub fn get_global_time(&self) -> f64 {
self.simulation.get_global_time()
}
pub fn status(&self, model_id: &str) -> String {
self.simulation.status(model_id).unwrap()
}
pub fn reset(&mut self) {
self.simulation.reset();
}
pub fn reset_messages(&mut self) {
self.simulation.reset_messages();
}
pub fn reset_global_time(&mut self) {
self.simulation.reset_global_time();
}
pub fn inject_input_json(&mut self, message: &str) {
self.simulation
.inject_input(serde_json::from_str(message).unwrap());
}
pub fn inject_input_yaml(&mut self, message: &str) {
self.simulation
.inject_input(serde_yaml::from_str(message).unwrap());
}
pub fn step_js(&mut self) -> Array {
self.simulation
.step()
.unwrap()
.into_iter()
.map(JsValue::from)
.collect()
}
pub fn step_json(&mut self) -> String {
serde_json::to_string(&self.simulation.step().unwrap()).unwrap()
}
pub fn step_yaml(&mut self) -> String {
serde_yaml::to_string(&self.simulation.step().unwrap()).unwrap()
}
pub fn step_until_js(&mut self, until: f64) -> Array {
self.simulation
.step_until(until)
.unwrap()
.into_iter()
.map(JsValue::from)
.collect()
}
pub fn step_until_json(&mut self, until: f64) -> String {
serde_json::to_string(&self.simulation.step_until(until).unwrap()).unwrap()
}
pub fn step_until_yaml(&mut self, until: f64) -> String {
serde_yaml::to_string(&self.simulation.step_until(until).unwrap()).unwrap()
}
pub fn step_n_js(&mut self, n: usize) -> Array {
self.simulation
.step_n(n)
.unwrap()
.into_iter()
.map(JsValue::from)
.collect()
}
pub fn step_n_json(&mut self, n: usize) -> String {
serde_json::to_string(&self.simulation.step_n(n).unwrap()).unwrap()
}
pub fn step_n_yaml(&mut self, n: usize) -> String {
serde_yaml::to_string(&self.simulation.step_n(n).unwrap()).unwrap()
}
}