gwr_engine/lib.rs
1// Copyright (c) 2023 Graphcore Ltd. All rights reserved.
2
3// TODO: enable this warning to ensure all public interfaces are documented.
4// Enable warnings for missing documentation
5// #![warn(missing_docs)]
6
7#![doc(test(attr(warn(unused))))]
8
9//! `GWR` - The Great Western Runtime
10//!
11//! This library provides the core of the [GWR Engine](crate::engine) which
12//! executes event driven asynchronous simulation
13//! [components].
14//!
15//! # Features
16//!
17//! - `global_allocator`: When enabled this feature causes applications
18//! dependendant on `gwr-engine` to use a global allocator selected to
19//! deliver optimal runtime performace of the GWR engine. Currently this is
20//! the [mimalloc](https://github.com/microsoft/mimalloc) allocator.
21//!
22//! This feature is enabled by default. Should an application wish to use a
23//! alternative global allocator the feature must be explicitly disabled.
24//!
25//! # Developer Guide
26//!
27//! The Developer Guide provides a document that goes through the GWR engine
28//! and related libraries in a more directed approach than the API guide can.
29//! See the `gwr-developer-guide/` folder.
30//!
31//! # Examples
32//!
33//! Make sure you look at the **examples/** folder which includes
34//! worked/documented examples. The current examples are:
35//! - [examples/flaky-component]: a worked example of a simple two-port
36//! component.
37//! - [examples/flaky-with-delay]: a worked example of a simple two-port
38//! component that has some subcomponents.
39//! - [examples/scrambler]: a worked example of a component that registers a a
40//! vector of subcomponents.
41//! - [examples/sim-pipe]: simulate a flow-controlled pipeline.
42//! - [examples/sim-restaurant]: simulate a fast food restaurant and explore
43//! staffing profitability.
44//! - [examples/sim-ring]: simulate a device comprising a ring of nodes.
45//! - [examples/sim-fabric]: simulate a device comprising a rectangular fabric.
46//!
47//! [components]: ../gwr_components/index.html
48//! [examples/flaky-component]: ../flaky_component/index.html
49//! [examples/flaky-with-delay]: ../flaky_with_delay/index.html
50//! [examples/scrambler]: ../scrambler/index.html
51//! [examples/sim-pipe]: ../sim_pipe/index.html
52//! [examples/sim-restaurant]: ../sim_restaurant/index.html
53//! [examples/sim-ring]: ../sim_ring/index.html
54//! [examples/sim-fabric]: ../sim_fabric/index.html
55
56//! # Simple Application
57//!
58//! A very simple application would look like:
59//!
60//! ```rust
61//! use gwr_components::sink::Sink;
62//! use gwr_components::source::Source;
63//! use gwr_components::{connect_port, option_box_repeat};
64//! use gwr_engine::engine::Engine;
65//! use gwr_engine::run_simulation;
66//!
67//! let mut engine = Engine::default();
68//! let clock = engine.default_clock();
69//! let mut source = Source::new_and_register(&engine, engine.top(), "source", option_box_repeat!(0x123 ; 10))
70//! .expect("should be able to create and register `Source`");
71//! let sink = Sink::new_and_register(&engine, &clock, engine.top(), "sink")
72//! .expect("should be able to create and register `Sink`");
73//! connect_port!(source, tx => sink, rx)
74//! .expect("should be able to connect `Source` to `Sink`");
75//! run_simulation!(engine);
76//! assert_eq!(sink.num_sunk(), 10);
77//! ```
78
79//! Simulations can be run as purely event driven (where one event triggers one
80//! or more others) or the use of clocks can be introduced to model time. The
81//! combination of both is the most common.
82//!
83//! The [engine](crate::engine::Engine) manages the
84//! [clocks](crate::time::clock). A simple example of a component that uses the
85//! clock is the
86//! [rate limiter](../gwr_components/flow_controls/rate_limiter/index.html)
87//! which models the amount of time it takes for objects to pass through it.
88
89pub mod engine;
90pub mod events;
91pub mod executor;
92#[cfg(feature = "global_allocator")]
93mod global_allocator;
94pub mod port;
95pub mod test_helpers;
96pub mod time;
97pub mod traits;
98pub mod types;
99
100/// Spawn all component run() functions and then run the simulation.
101#[macro_export]
102macro_rules! run_simulation {
103 ($engine:ident) => {
104 $engine.run().unwrap();
105 };
106 ($engine:ident, $expect:expr) => {
107 match $engine.run() {
108 Ok(()) => panic!("Expected an error!"),
109 Err(e) => assert_eq!(&format!("{e}"), $expect),
110 }
111 };
112}
113
114/// Spawn a sub-component that is stored in an `RefCell<Option<>>`
115///
116/// This removes the sub-component from the Option and then spawns the `run()`
117/// function.
118#[macro_export]
119macro_rules! spawn_subcomponent {
120 ($($spawner:ident).+ ; $($block:ident).+) => {
121 let sub_block = $($block).+.borrow_mut().take().unwrap();
122 $($spawner).+.spawn(async move { sub_block.run().await } );
123 };
124}