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-ring]: simulate a device comprising a ring of nodes.
43//!  - [examples/sim-fabric]: simulate a device comprising a rectangular fabric.
44//!
45//! [components]: ../gwr_components/index.html
46//! [examples/flaky-component]: ../flaky_component/index.html
47//! [examples/flaky-with-delay]: ../flaky_with_delay/index.html
48//! [examples/scrambler]: ../scrambler/index.html
49//! [examples/sim-pipe]: ../sim_pipe/index.html
50//! [examples/sim-ring]: ../sim_ring/index.html
51//! [examples/sim-fabric]: ../sim_fabric/index.html
52
53//! # Simple Application
54//!
55//! A very simple application would look like:
56//!
57//! ```rust
58//! use gwr_components::sink::Sink;
59//! use gwr_components::source::Source;
60//! use gwr_components::{connect_port, option_box_repeat};
61//! use gwr_engine::engine::Engine;
62//! use gwr_engine::run_simulation;
63//!
64//! let mut engine = Engine::default();
65//! let clock = engine.default_clock();
66//! let mut source = Source::new_and_register(&engine, engine.top(), "source", option_box_repeat!(0x123 ; 10))
67//!     .expect("should be able to create and register `Source`");
68//! let sink = Sink::new_and_register(&engine, &clock, engine.top(), "sink")
69//!     .expect("should be able to create and register `Sink`");
70//! connect_port!(source, tx => sink, rx)
71//!     .expect("should be able to connect `Source` to `Sink`");
72//! run_simulation!(engine);
73//! assert_eq!(sink.num_sunk(), 10);
74//! ```
75
76//! Simulations can be run as purely event driven (where one event triggers one
77//! or more others) or the use of clocks can be introduced to model time. The
78//! combination of both is the most common.
79//!
80//! The [engine](crate::engine::Engine) manages the
81//! [clocks](crate::time::clock). A simple example of a component that uses the
82//! clock is the
83//! [rate limiter](../gwr_components/flow_controls/rate_limiter/index.html)
84//! which models the amount of time it takes for objects to pass through it.
85
86pub mod engine;
87pub mod events;
88pub mod executor;
89#[cfg(feature = "global_allocator")]
90mod global_allocator;
91pub mod port;
92pub mod test_helpers;
93pub mod time;
94pub mod traits;
95pub mod types;
96
97#[macro_export]
98/// Spawn all component run() functions and then run the simulation.
99macro_rules! run_simulation {
100    ($engine:ident) => {
101        $engine.run().unwrap();
102    };
103    ($engine:ident, $expect:expr) => {
104        match $engine.run() {
105            Ok(()) => panic!("Expected an error!"),
106            Err(e) => assert_eq!(&format!("{e}"), $expect),
107        }
108    };
109}
110
111#[macro_export]
112/// Spawn a sub-component that is stored in an `RefCell<Option<>>`
113///
114/// This removes the sub-component from the Option and then spawns the `run()`
115/// function.
116macro_rules! spawn_subcomponent {
117    ($($spawner:ident).+ ; $($block:ident).+) => {
118        let sub_block = $($block).+.borrow_mut().take().unwrap();
119        $($spawner).+.spawn(async move { sub_block.run().await } );
120    };
121}