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//! # Developer Guide
16//!
17//! The Developer Guide provides a document that goes through the GWR engine
18//! and related libraries in a more directed approach than the API guide can.
19//! See the `gwr-developer-guide/` folder.
20//!
21//! # Examples
22//!
23//! Make sure you look at the **examples/** folder which includes
24//! worked/documented examples. The current examples are:
25//!  - [examples/flaky-component]: a worked example of a simple two-port
26//!    component.
27//!  - [examples/flaky-with-delay]: a worked example of a simple two-port
28//!    component that has some subcomponents.
29//!  - [examples/scrambler]: a worked example of a component that registers a a
30//!    vector of subcomponents.
31//!  - [examples/sim-pipe]: simulate a flow-controlled pipeline.
32//!  - [examples/sim-ring]: simulate a device comprising a ring of nodes.
33//!  - [examples/sim-fabric]: simulate a device comprising a rectangular fabric.
34//!
35//! [components]: ../gwr_components/index.html
36//! [examples/flaky-component]: ../flaky_component/index.html
37//! [examples/flaky-with-delay]: ../flaky_with_delay/index.html
38//! [examples/scrambler]: ../scrambler/index.html
39//! [examples/sim-pipe]: ../sim_pipe/index.html
40//! [examples/sim-ring]: ../sim_ring/index.html
41//! [examples/sim-fabric]: ../sim_fabric/index.html
42
43//! # Simple Application
44//!
45//! A very simple application would look like:
46//!
47//! ```rust
48//! use gwr_components::sink::Sink;
49//! use gwr_components::source::Source;
50//! use gwr_components::{connect_port, option_box_repeat};
51//! use gwr_engine::engine::Engine;
52//! use gwr_engine::run_simulation;
53//!
54//! let mut engine = Engine::default();
55//! let mut source = Source::new_and_register(&engine, engine.top(), "source", option_box_repeat!(0x123 ; 10))
56//!     .expect("should be able to create and register `Source`");
57//! let sink = Sink::new_and_register(&engine, engine.top(), "sink")
58//!     .expect("should be able to create and register `Sink`");
59//! connect_port!(source, tx => sink, rx)
60//!     .expect("should be able to connect `Source` to `Sink`");
61//! run_simulation!(engine);
62//! assert_eq!(sink.num_sunk(), 10);
63//! ```
64
65//! Simulations can be run as purely event driven (where one event triggers one
66//! or more others) or the use of clocks can be introduced to model time. The
67//! combination of both is the most common.
68//!
69//! The [engine](crate::engine::Engine) manages the
70//! [clocks](crate::time::clock). A simple example of a component that uses the
71//! clock is the
72//! [rate limiter](../gwr_components/flow_controls/rate_limiter/index.html)
73//! which models the amount of time it takes for objects to pass through it.
74
75pub mod engine;
76pub mod events;
77pub mod executor;
78pub mod port;
79pub mod test_helpers;
80pub mod time;
81pub mod traits;
82pub mod types;
83
84#[macro_export]
85/// Spawn all component run() functions and then run the simulation.
86macro_rules! run_simulation {
87    ($engine:ident) => {
88        $engine.run().unwrap();
89    };
90    ($engine:ident, $expect:expr) => {
91        match $engine.run() {
92            Ok(()) => panic!("Expected an error!"),
93            Err(e) => assert_eq!(format!("{e}").as_str(), $expect),
94        }
95    };
96}
97
98#[macro_export]
99/// Spawn a sub-component that is stored in an `RefCell<Option<>>`
100///
101/// This removes the sub-component from the Option and then spawns the `run()`
102/// function.
103macro_rules! spawn_subcomponent {
104    ($($spawner:ident).+ ; $($block:ident).+) => {
105        let sub_block = $($block).+.borrow_mut().take().unwrap();
106        $($spawner).+.spawn(async move { sub_block.run().await } );
107    };
108}