use std::f64::INFINITY;
use serde::{Deserialize, Serialize};
use wasm_bindgen::prelude::*;
use crate::input_modeling::uniform_rng::UniformRNG;
use crate::models::model::Model;
use crate::models::ModelMessage;
mod test_simulations;
#[wasm_bindgen]
#[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")]
struct Connector {
id: String,
#[serde(rename = "sourceID")]
source_id: String,
#[serde(rename = "targetID")]
target_id: String,
source_port: String,
target_port: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
struct Message {
source_id: String,
source_port: String,
target_id: String,
target_port: String,
time: f64,
message: String,
}
#[wasm_bindgen]
impl Simulation {
pub fn post_json(models: String, connectors: String) -> Simulation {
Simulation {
models: serde_json::from_str(&models).unwrap(),
connectors: serde_json::from_str(&connectors).unwrap(),
..Default::default()
}
}
pub fn put_json(&mut self, models: String, connectors: String) {
self.models = serde_json::from_str(&models).unwrap();
self.connectors = serde_json::from_str(&connectors).unwrap();
}
pub fn get_json(&self) -> String {
serde_json::to_string_pretty(self).unwrap()
}
pub fn post_yaml(models: String, connectors: String) -> Simulation {
Simulation {
models: serde_yaml::from_str(&models).unwrap(),
connectors: serde_yaml::from_str(&connectors).unwrap(),
..Default::default()
}
}
pub fn put_yaml(&mut self, models: String, connectors: String) {
self.models = serde_yaml::from_str(&models).unwrap();
self.connectors = serde_yaml::from_str(&connectors).unwrap();
}
pub fn get_yaml(&self) -> String {
serde_yaml::to_string(self).unwrap()
}
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;
}
fn models(&mut self) -> Vec<&mut Box<dyn Model>> {
self.models.iter_mut().collect()
}
pub fn messages(&self) -> String {
serde_json::to_string(&self.messages).unwrap()
}
pub fn global_time(&self) -> f64 {
self.global_time
}
pub fn status(&self, id: String) -> String {
self.models
.iter()
.find(|model| model.id() == id)
.unwrap()
.status()
}
fn get_message_target_ids(&self, source_id: String, source_port: String) -> Vec<String> {
self.connectors
.iter()
.filter(|connector| {
connector.source_id == source_id && connector.source_port == source_port
})
.map(|connector| connector.target_id.clone())
.collect()
}
fn get_message_target_ports(&self, source_id: String, source_port: String) -> Vec<String> {
self.connectors
.iter()
.filter(|connector| {
connector.source_id == source_id && connector.source_port == source_port
})
.map(|connector| connector.target_port.clone())
.collect()
}
pub fn inject_input(&mut self, message: String) {
self.messages.push(serde_json::from_str(&message).unwrap());
}
pub fn step(&mut self) {
let messages = self.messages.clone();
let mut next_messages: Vec<Message> = Vec::new();
if !messages.is_empty() {
(0..self.models.len()).for_each(|model_index| {
let model_messages: Vec<ModelMessage> = messages
.iter()
.filter(|message| message.target_id == self.models[model_index].id())
.map(|message| ModelMessage {
port_name: message.target_port.clone(),
message: message.message.clone(),
})
.collect();
model_messages.iter().for_each(|model_message| {
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.clone(), );
let target_ports = self.get_message_target_ports(
self.models[model_index].id(), outgoing_message.port_name.clone(), );
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(),
});
},
);
});
});
});
}
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()).for_each(|model_index| {
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.clone(), );
let target_ports = self.get_message_target_ports(
self.models[model_index].id(), outgoing_message.port_name.clone(), );
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(),
});
},
);
});
});
self.messages = next_messages;
}
pub fn step_until(&mut self, until: f64) -> String {
let mut message_records: Vec<Message> = Vec::new();
loop {
self.step();
if self.global_time < until {
let messages_set: Vec<Message> = serde_json::from_str(&self.messages()).unwrap();
message_records.extend(messages_set);
} else {
break;
}
}
serde_json::to_string(&message_records).unwrap()
}
pub fn step_n(&mut self, n: usize) -> String {
let mut message_records: Vec<Message> = Vec::new();
(0..n).for_each(|_| {
self.step();
let messages_set: Vec<Message> = serde_json::from_str(&self.messages()).unwrap();
message_records.extend(messages_set);
});
serde_json::to_string(&message_records).unwrap()
}
}