1pub mod async_runtime;
52pub mod dists;
53pub mod error;
54pub mod execute;
55pub mod ids;
56pub mod logging;
57pub mod randomness;
58pub mod request;
59pub mod scheduler;
60pub mod task;
61pub mod time;
62pub mod types;
63pub mod waker;
64
65pub mod formal;
66
67use std::any::Any;
68use std::collections::HashMap;
69use std::sync::{
70 atomic::{AtomicU64, Ordering as AtomicOrdering},
71 Arc, Mutex,
72};
73use tracing::{debug, info, instrument, trace, warn};
74
75pub use error::{EventError, SimError};
77pub use execute::{Execute, Executor};
80pub use logging::{
81 component_span, event_span, init_detailed_simulation_logging, init_simulation_logging,
82 init_simulation_logging_with_level, simulation_span, task_span,
83};
84pub use randomness::{DrawSite, RandomProvider};
85pub use request::{
86 AttemptStatus, Request, RequestAttempt, RequestAttemptId, RequestId, RequestStatus, Response,
87 ResponseStatus,
88};
89pub use scheduler::{
90 current_time, defer_wake, defer_wake_after, in_scheduler_context, ClockRef, EventEntry,
91 EventFrontierPolicy, FifoFrontierPolicy, FrontierEvent, FrontierEventKind, FrontierSignature,
92 Scheduler, SchedulerHandle, UniformRandomFrontierPolicy,
93};
94pub use task::{ClosureTask, PeriodicTask, RetryTask, Task, TaskHandle, TaskId, TimeoutTask};
95pub use time::SimTime;
96pub use types::EventId;
97pub use waker::create_des_waker;
98
99pub use formal::{CertificateError, LyapunovError, VerificationError};
100
101use uuid::Uuid;
102
103#[derive(Debug, Clone)]
109pub struct SimulationConfig {
110 pub seed: u64,
112}
113
114impl Default for SimulationConfig {
115 fn default() -> Self {
116 Self { seed: 1 }
117 }
118}
119
120#[derive(Debug)]
121pub struct Key<T> {
122 id: Uuid,
123 _marker: std::marker::PhantomData<T>,
124}
125
126impl<T> Key<T> {
127 pub fn new() -> Self {
132 static NEXT_KEY_ID: AtomicU64 = AtomicU64::new(0);
133 let counter = NEXT_KEY_ID.fetch_add(1, AtomicOrdering::Relaxed) + 1;
134 let id = crate::ids::deterministic_uuid(0, crate::ids::UUID_DOMAIN_KEY, counter);
135 Self::new_with_id(id)
136 }
137
138 pub fn new_with_id(id: Uuid) -> Self {
139 Self {
140 id,
141 _marker: std::marker::PhantomData,
142 }
143 }
144
145 pub fn id(&self) -> Uuid {
147 self.id
148 }
149}
150
151impl<T> Default for Key<T> {
152 fn default() -> Self {
153 Self::new()
154 }
155}
156
157impl<T> Clone for Key<T> {
158 fn clone(&self) -> Self {
159 *self
160 }
161}
162impl<T> Copy for Key<T> {}
163
164pub trait ProcessEventEntry: Any {
165 fn process_event_entry(&mut self, entry: EventEntry, scheduler: &mut Scheduler);
166 fn as_any_mut(&mut self) -> &mut dyn Any;
167}
168
169pub trait Component: ProcessEventEntry {
170 type Event: 'static;
171
172 fn process_event(
173 &mut self,
174 self_id: Key<Self::Event>,
175 event: &Self::Event,
176 scheduler: &mut Scheduler,
177 );
178
179 }
181
182impl<E, C> ProcessEventEntry for C
183where
184 E: std::fmt::Debug + 'static,
185 C: Component<Event = E> + 'static,
186{
187 fn process_event_entry(&mut self, entry: EventEntry, scheduler: &mut Scheduler) {
188 if let EventEntry::Component(component_entry) = entry {
189 let typed_entry = component_entry
190 .downcast::<E>()
191 .expect("Failed to downcast event entry.");
192 self.process_event(typed_entry.component_key, typed_entry.event, scheduler);
193 }
194 }
195
196 fn as_any_mut(&mut self) -> &mut dyn Any {
197 self
198 }
199}
200
201#[derive(Default)]
203pub struct Components {
204 components: HashMap<Uuid, Box<dyn ProcessEventEntry>>,
205 next_component_id: u64,
206 id_seed: u64,
207}
208
209impl Components {
210 #[allow(clippy::missing_panics_doc)]
211 pub fn process_event_entry(&mut self, entry: EventEntry, scheduler: &mut Scheduler) {
213 match entry {
214 EventEntry::Component(component_entry) => {
215 if let Some(component) = self.components.get_mut(&component_entry.component) {
216 component
217 .process_event_entry(EventEntry::Component(component_entry), scheduler);
218 }
219 }
220 EventEntry::Task(task_entry) => {
221 scheduler.execute_task(task_entry.task_id);
223 }
224 }
225 }
226
227 #[must_use]
229 pub fn register_with_id<E: std::fmt::Debug + 'static, C: Component<Event = E> + 'static>(
230 &mut self,
231 id: Uuid,
232 component: C,
233 ) -> Key<E> {
234 self.components.insert(id, Box::new(component));
235 Key::new_with_id(id)
236 }
237
238 #[must_use]
243 pub fn register<E: std::fmt::Debug + 'static, C: Component<Event = E> + 'static>(
244 &mut self,
245 component: C,
246 ) -> Key<E> {
247 self.next_component_id += 1;
248 let id = crate::ids::deterministic_uuid(
249 self.id_seed,
250 crate::ids::UUID_DOMAIN_COMPONENT,
251 self.next_component_id,
252 );
253 self.register_with_id(id, component)
254 }
255
256 pub fn remove<E: 'static, C: Component<Event = E> + 'static>(
257 &mut self,
258 key: Key<E>,
259 ) -> Option<C> {
260 self.components.remove(&key.id).and_then(|boxed_trait| {
261 let boxed_any: Box<dyn std::any::Any> = boxed_trait;
263 boxed_any.downcast::<C>().ok().map(|boxed_c| *boxed_c)
264 })
265 }
266
267 pub fn get_component_mut<E: 'static, C: Component<Event = E> + 'static>(
269 &mut self,
270 key: Key<E>,
271 ) -> Option<&mut C> {
272 self.components.get_mut(&key.id).and_then(|boxed_trait| {
273 let any_ref = boxed_trait.as_any_mut();
275 any_ref.downcast_mut::<C>()
276 })
277 }
278}
279
280pub struct Simulation {
284 scheduler: Arc<Mutex<Scheduler>>,
286 frontier_policy: Box<dyn scheduler::EventFrontierPolicy>,
288 next_component_id: u64,
290 pub components: Components,
292 config: SimulationConfig,
294}
295
296impl Default for Simulation {
297 fn default() -> Self {
298 Self::new(SimulationConfig { seed: 42 })
302 }
303}
304
305#[allow(clippy::arc_with_non_send_sync)]
306impl Simulation {
307 #[must_use]
309 pub fn new(config: SimulationConfig) -> Self {
310 Self {
311 scheduler: Arc::new(Mutex::new(Scheduler::with_seed(config.seed))),
312 frontier_policy: Box::new(scheduler::FifoFrontierPolicy),
313 next_component_id: 0,
314 components: Components::default(),
315 config,
316 }
317 }
318
319 pub fn set_frontier_policy(&mut self, policy: Box<dyn scheduler::EventFrontierPolicy>) {
323 self.frontier_policy = policy;
324 }
325
326 #[must_use]
328 pub fn config(&self) -> &SimulationConfig {
329 &self.config
330 }
331
332 #[must_use]
350 pub fn scheduler_handle(&self) -> SchedulerHandle {
351 SchedulerHandle::new(Arc::clone(&self.scheduler))
352 }
353
354 #[must_use]
356 pub fn time(&self) -> SimTime {
357 self.scheduler.lock().unwrap().time()
358 }
359
360 pub fn step(&mut self) -> bool {
364 let event = {
366 let mut scheduler = self.scheduler.lock().unwrap();
367 scheduler.pop_with_policy(self.frontier_policy.as_mut())
368 };
369
370 event.is_some_and(|event| {
371 trace!(
372 event_time = ?event.time(),
373 event_type = match &event {
374 EventEntry::Component(_) => "Component",
375 EventEntry::Task(_) => "Task",
376 },
377 "Processing simulation step"
378 );
379
380 {
382 let scheduler = self.scheduler.lock().unwrap();
383 scheduler::set_scheduler_context(&scheduler);
384 }
385
386 {
388 let mut scheduler = self.scheduler.lock().unwrap();
389 self.components.process_event_entry(event, &mut scheduler);
390 }
391
392 scheduler::clear_scheduler_context();
394
395 {
397 let mut scheduler = self.scheduler.lock().unwrap();
398 scheduler::drain_deferred_wakes(&mut scheduler);
399 }
400
401 true
402 })
403 }
404
405 #[instrument(skip(self, executor), fields(
410 initial_time = ?self.time()
411 ))]
412 pub fn execute<E: Execute>(&mut self, executor: E) {
413 info!("Starting simulation execution");
414 executor.execute(self);
415 info!(
416 final_time = ?self.time(),
417 "Simulation execution completed"
418 );
419 }
420
421 #[must_use]
423 #[instrument(skip(self, component), fields(component_type = std::any::type_name::<C>()))]
424 pub fn add_component<E: std::fmt::Debug + 'static, C: Component<Event = E> + 'static>(
425 &mut self,
426 component: C,
427 ) -> Key<E> {
428 self.next_component_id += 1;
429 let id = crate::ids::deterministic_uuid(
430 self.config.seed,
431 crate::ids::UUID_DOMAIN_COMPONENT,
432 self.next_component_id,
433 );
434
435 let key = self.components.register_with_id(id, component);
436 debug!(component_id = ?key.id(), "Added component to simulation");
437 key
438 }
439
440 #[must_use]
442 #[instrument(skip(self), fields(component_id = ?key.id()))]
443 pub fn remove_component<E: std::fmt::Debug + 'static, C: Component<Event = E> + 'static>(
444 &mut self,
445 key: Key<E>,
446 ) -> Option<C> {
447 let result = self.components.remove(key);
448 if result.is_some() {
449 debug!("Removed component from simulation");
450 } else {
451 warn!("Attempted to remove non-existent component");
452 }
453 result
454 }
455
456 pub fn get_component_mut<E: std::fmt::Debug + 'static, C: Component<Event = E> + 'static>(
458 &mut self,
459 key: Key<E>,
460 ) -> Option<&mut C> {
461 self.components.get_component_mut(key)
462 }
463
464 pub fn schedule<E: std::fmt::Debug + 'static>(
466 &mut self,
467 time: SimTime,
468 component: Key<E>,
469 event: E,
470 ) {
471 let mut scheduler = self.scheduler.lock().unwrap();
472 scheduler.schedule(time, component, event);
473 }
474
475 pub fn schedule_now<E: std::fmt::Debug + 'static>(&mut self, component: Key<E>, event: E) {
477 let mut scheduler = self.scheduler.lock().unwrap();
478 scheduler.schedule(SimTime::zero(), component, event);
479 }
480
481 pub fn peek_next_event_time(&self) -> Option<SimTime> {
483 let mut scheduler = self.scheduler.lock().unwrap();
484 scheduler.peek().map(|e| e.time())
485 }
486
487 pub fn clock(&self) -> scheduler::ClockRef {
489 let scheduler = self.scheduler.lock().unwrap();
490 scheduler.clock()
491 }
492
493 pub fn schedule_closure<F, R>(&mut self, delay: SimTime, closure: F) -> task::TaskHandle<R>
495 where
496 F: FnOnce(&mut Scheduler) -> R + 'static,
497 R: 'static,
498 {
499 let mut scheduler = self.scheduler.lock().unwrap();
500 scheduler.schedule_closure(delay, closure)
501 }
502
503 pub fn timeout<F>(&mut self, delay: SimTime, callback: F) -> task::TaskHandle<()>
505 where
506 F: FnOnce(&mut Scheduler) + 'static,
507 {
508 let mut scheduler = self.scheduler.lock().unwrap();
509 scheduler.timeout(delay, callback)
510 }
511
512 pub fn schedule_task<T: task::Task>(
514 &mut self,
515 delay: SimTime,
516 task: T,
517 ) -> task::TaskHandle<T::Output> {
518 let mut scheduler = self.scheduler.lock().unwrap();
519 scheduler.schedule_task(delay, task)
520 }
521
522 pub fn cancel_task<T>(&mut self, handle: task::TaskHandle<T>) -> bool {
524 let mut scheduler = self.scheduler.lock().unwrap();
525 scheduler.cancel_task(handle)
526 }
527
528 pub fn get_task_result<T: 'static>(&mut self, handle: task::TaskHandle<T>) -> Option<T> {
530 let mut scheduler = self.scheduler.lock().unwrap();
531 scheduler.get_task_result(handle)
532 }
533
534 pub fn has_pending_events(&self) -> bool {
536 let mut scheduler = self.scheduler.lock().unwrap();
537 scheduler.peek().is_some()
538 }
539}