use std::fmt;
use std::sync::{Arc, Mutex};
use crate::executor::Executor;
use crate::model::Model;
use crate::time::{Clock, Scheduler};
use crate::time::{MonotonicTime, SchedulerQueue, TearableAtomicTime};
use crate::util::priority_queue::PriorityQueue;
use crate::util::sync_cell::SyncCell;
use super::{Mailbox, Simulation};
pub struct SimInit {
executor: Executor,
scheduler_queue: Arc<Mutex<SchedulerQueue>>,
time: SyncCell<TearableAtomicTime>,
}
impl SimInit {
pub fn new() -> Self {
Self::with_num_threads(num_cpus::get())
}
pub fn with_num_threads(num_threads: usize) -> Self {
let num_threads = num_threads.min(usize::BITS as usize);
Self {
executor: Executor::new(num_threads),
scheduler_queue: Arc::new(Mutex::new(PriorityQueue::new())),
time: SyncCell::new(TearableAtomicTime::new(MonotonicTime::EPOCH)),
}
}
pub fn add_model<M: Model>(self, model: M, mailbox: Mailbox<M>) -> Self {
let scheduler_queue = self.scheduler_queue.clone();
let time = self.time.reader();
let mut receiver = mailbox.0;
self.executor.spawn_and_forget(async move {
let sender = receiver.sender();
let scheduler = Scheduler::new(sender, scheduler_queue, time);
let mut model = model.init(&scheduler).await.0;
while receiver.recv(&mut model, &scheduler).await.is_ok() {}
});
self
}
pub fn init(mut self, start_time: MonotonicTime) -> Simulation {
self.time.write(start_time);
self.executor.run();
Simulation::new(self.executor, self.scheduler_queue, self.time)
}
pub fn init_with_clock(
mut self,
start_time: MonotonicTime,
mut clock: impl Clock + 'static,
) -> Simulation {
self.time.write(start_time);
clock.synchronize(start_time);
self.executor.run();
Simulation::with_clock(self.executor, self.scheduler_queue, self.time, clock)
}
}
impl Default for SimInit {
fn default() -> Self {
Self::new()
}
}
impl fmt::Debug for SimInit {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SimInit").finish_non_exhaustive()
}
}