Skip to main content

simu/
lib.rs

1// SPDX-FileCopyrightText: Copyright (c) Siemens 2026 contributed by Christoph Kuhmuench christoph.kuhmuench@gmail.com
2//
3// SPDX-License-Identifier: MIT OR Apache-2.0
4
5//! `simu` is a library for **discrete-event simulation** (DES), inspired by
6//! Python's [SimPy](https://simpy.readthedocs.io/) but built to be idiomatic
7//! Rust, fast, and reproducible.
8//!
9//! Simulation processes are ordinary `async` blocks driven by a custom,
10//! single-threaded executor over *simulated* time — there is no tokio/async-std
11//! and no wall-clock waiting. Processes interact through timeouts, manual
12//! events, and shared resources; the event queue is ordered by
13//! `(time, insertion)` so a run is fully deterministic given the same seed and
14//! logic.
15//!
16//! **New to simu? Start with the [`tutorial`] module** — five short chapters
17//! modeled on SimPy's "SimPy in 10 minutes", every snippet a running doc-test.
18//!
19//! The crates.io package is named **`simu-des`** (the name `simu` was taken)
20//! but the library target is `simu`: depend on `simu-des = "0.1"` and write
21//! `use simu::…` exactly as in the examples here.
22//!
23//! # Quick start
24//!
25//! ```
26//! use simu::{SimEnv, Resource};
27//!
28//! let mut env = SimEnv::with_seed(42);
29//! let machine = Resource::new(1); // a pool of one unit, shared by cloning
30//!
31//! let h = env.handle();
32//! let m = machine.clone();
33//! env.spawn(async move {
34//!     let _guard = m.request().await; // queue for the machine (FIFO)
35//!     h.timeout(2.0).await;           // hold it for 2 simulated time units
36//! }); // guard drops here → unit released
37//!
38//! env.run(); // drive the event loop until the queue drains
39//! assert_eq!(env.now(), 2.0);
40//! ```
41//!
42//! # Core types
43//!
44//! | Type | Role |
45//! |------|------|
46//! | [`SimEnv`] | Owns the event loop, current time, and the seeded RNG. Not `Clone`; one per thread. |
47//! | [`EnvHandle`] | Cheap `Clone` handle passed into processes: `now` / `timeout` / `event` / `spawn` / `rng`. |
48//! | [`Timeout`] | Future resolving after a simulated delay. |
49//! | [`EventTrigger`] / [`EventAwaitable`] | Manual inter-process signalling (multi-waiter, fire-before-await latch). |
50//! | [`Resource`] / [`ResourceGuard`] | FIFO capacity-limited pool; RAII release on guard drop. |
51//! | [`PriorityResource`] | Priority-scheduled pool (lower number = higher priority; FIFO within a level). |
52//! | [`PreemptiveResource`] / [`PreemptiveGuard`] | Priority pool whose in-use units can be preempted (cooperative-at-yield). |
53//! | [`Container`] | Reservoir of continuous quantity (`put` / `get`, strict head-of-line FIFO). |
54//! | [`ProcessHandle`] | Observable spawn: `await` for the return value, drop to detach. |
55//! | [`AnyOf`] / [`AllOf`] | Future combinators, built via the [`any_of!`] / [`all_of!`] macros. |
56//!
57//! # Threading and Monte Carlo
58//!
59//! [`SimEnv`] (and the resource handles) are `!Send + !Sync` — a simulation
60//! lives entirely on one thread, which is why the executor needs no locking.
61//! Parallelism comes from running *independent* simulations across threads:
62//! [`monte_carlo::run`] executes a closure once per seed and returns the results
63//! in seed order (one `std::thread` per seed by default; enable the
64//! `monte-carlo` feature for a rayon-backed pool).
65//!
66//! # Randomness
67//!
68//! By default a [`SimEnv`] draws from `rand`'s `StdRng`. For cross-language
69//! reproducibility, plug in a [`RandomSource`] via [`SimEnv::with_source`] — e.g.
70//! the portable [`SplitMix64`] feed, whose stream and the [`rng::sample`]
71//! transforms are mirrored in Python for exact SimPy comparison.
72//!
73//! # Feature flags
74//!
75//! | Feature | Default | Effect |
76//! |---------|---------|--------|
77//! | `monte-carlo` | off | Switches [`monte_carlo::run`] from one-`std::thread`-per-seed to rayon's bounded work-stealing pool — preferable for hundreds or thousands of seeds. |
78//!
79//! # Examples
80//!
81//! Four beginner examples (`intro_car`, `intro_charging`, `intro_cancellation`,
82//! `intro_charging_station`) accompany the [`tutorial`] chapters. Three
83//! end-to-end models combine everything: `hospital` (priority triage +
84//! bed eviction + blood-bank `Container`), `brewery` (a bio-reactor production
85//! line), and `warehouse` (a forklift fleet exercising [`PreemptiveResource`]).
86
87#![warn(missing_docs)]
88
89mod combinator;
90mod env;
91mod event;
92pub mod monte_carlo;
93mod process;
94mod resource;
95pub mod rng;
96mod timeout;
97pub mod tutorial;
98
99pub use combinator::{AllOf, AnyOf};
100pub use env::{EnvHandle, SimEnv};
101pub use event::{EventAwaitable, EventTrigger};
102pub use process::ProcessHandle;
103pub use resource::{Container, ContainerGetRequest, ContainerPutRequest};
104pub use resource::{PreemptiveGuard, PreemptiveRequest, PreemptiveResource};
105pub use resource::{PriorityResource, PriorityResourceGuard, PriorityResourceRequest};
106pub use resource::{Resource, ResourceGuard, ResourceRequest};
107pub use rng::{RandomSource, SplitMix64};
108pub use timeout::Timeout;
109
110mod executor;