1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
#[cfg_attr(doc, aquamarine::aquamarine)]
/// # Intro to Moongraph πŸŒ™πŸ“ˆ
///
/// `moongraph` is a library for defining, scheduling and running directed acyclic graphs
/// with shared resources.
///
/// ## DAG
/// A "DAG" is a directed, acyclic graph.
/// Within the `moongraph` library, graph nodes are Rust functions and graph edges are the
/// function's input parameters and output parameters. For example, in the following diagram
/// we represent nodes as circles and edges as rectangles:
///
/// ```mermaid
/// flowchart LR
///     A[Input Types] --> B((Rust Function)) --> C[Output Types]
/// ```
///
/// In this way our graphs are "directed" because the output of one function becomes the
/// input of another function, which leads to a required ordering when executing the graph.
///
/// ```mermaid
/// flowchart LR
///     A[Input Types] --> B((Function A)) --> C[Output Types] -- Become Input Types --> D((Function B))
/// ```
///
/// "Acyclic" means that the graph cannot contain cycles between nodes.
/// What this means in `moongraph` is that the result of one function **cannot** be the input to another
/// function whose result is required input of the first function. For example the following graph would
/// fail to schedule:
///
/// ```mermaid
/// flowchart LR
///     A[A Input Types / B Output Types] --> B((Function A)) --> C[A Output Types] --> D((Function B))
///     D --> A
/// ```
///
/// Obviously this graph cannot be scheduled because it's not possible to determine which function to run
/// first!
/// Attempting to run or schedule a graph with cycles will produce an error.
///
/// ### The benefit of a DAG
/// Once a DAG has been defined, it does not change.
/// For this reason we can create a schedule that runs all nodes in the DAG in an optimal way, running as many nodes as possible in parallel, safely accessing shared resources **without locks** and in a synchronous context.
/// This makes using DAGs an alternative to async runtimes and an alternative to message passing systems.
/// DAGs as a main loop are often found in games, simulations and other contexts where reliable, predictable performance is a top concern.
///
/// So if you're still interested, let's learn about creating DAGs with `moongraph`.
///
/// ## Nodes and Edges
/// Graph nodes are Rust functions.
/// There are two requirements for a Rust function to be used as a graph node.
/// 1. The input parameters must implement [`Edges`](crate::Edges) `+ Any + Send + Sync`.
/// 2. The output must implement [`NodeResults`](crate::NodeResults) `+ Any + Send + Sync`.
///
/// [`Edges`](crate::Edges) is a trait that tells `moongraph` how to construct your node's input
/// from its internal resources (we'll explain more about that when we get talking about the `Graph` type). For now we just need to know about the three ways to access an input parameter:
/// 1. By reference
/// 2. By mutable reference
/// 3. By **move**
///
/// The first two should be familiar from Rust in general and the last is somewhat novel. That is - an input parameter to a node function can be borrowed from the graph, borrowed mutably from the graph, or **moved** out of the graph into the function. To represent each type of access we have three wrappers:
/// 1. [`View`](crate::View) - allows a node function to borrow from the graph.
/// 2. [`ViewMut`](crate::ViewMut) - allows a node function to borrow mutably from the graph.
/// 3. [`Move`](crate::Move) - allows a node function to move a type from the graph into itself.
///
/// With these we can construct our input parameters by wrapping them in a tuple.
/// Here we define a node function that uses all three and possibly returns an error:
///
/// ```rust
/// use moongraph::{View, ViewMut, Move, GraphError};
///
/// fn node_b((s, mut u, f): (View<&'static str>, ViewMut<usize>, Move<f32>)) -> Result<(), GraphError> {
///     *u += f.floor() as usize;
///     println!("s={s}, u={u}, f={f}");
///     Ok(())
/// }
/// ```
///
/// And here we'll define another node that creates `node_b`'s `f32` as a result:
///
/// ```rust
/// # use moongraph::GraphError;
/// fn node_a(_:()) -> Result<(f32,), GraphError> {
///     Ok((42.0,))
/// }
/// ```
///
/// Notice how even though `node_a` doesn't use any input we still have to pass `()`.
/// Also notice how the result is a tuple even though there's only one element `(f32,)`.
/// These are both warts due to constraints in Rust's type system.
/// That's the worst of it though, and it's easy enough to live with.
///
/// ## Graph
/// The top level type you'll interact with is called [`Graph`](crate::Graph).
/// Now that we have our nodes we can start constructing our graph.
/// A [`Graph`](crate::Graph) is made up of two main concepts - [`Execution`](crate::Execution) and [`TypeMap`](crate::TypeMap).
///
/// [`Execution`](crate::Execution) is a collection of node functions and a schedule that determines their running order.
///
/// [`TypeMap`](crate::TypeMap) is a collection of resources (edge types).
///
/// For the most part we won't have to interact with either of these.
/// Instead we'll be adding functions and resources to the graph using `Graph`'s API, which will
/// do this interaction for us, but it's good to understand the concepts.
///
/// So - let's construct a graph using our previously created nodes.
/// For this we'll use the [`graph!`](crate::graph) macro, but you can use the API directly if you like.
///
/// ```rust
/// use moongraph::{View, ViewMut, Move, GraphError, Graph, graph};
///
/// fn node_b((s, mut u, f): (View<&'static str>, ViewMut<usize>, Move<f32>)) -> Result<(), GraphError> {
///     *u += f.floor() as usize;
///     println!("s={s}, u={u}, f={f}");
///     Ok(())
/// }
///
/// fn node_a(_:()) -> Result<(f32,), GraphError> {
///     Ok((42.0,))
/// }
///
/// let mut graph = graph!(node_b, node_a)
///     .with_resource("a big blue crystal") // add the &'static str resource
///     .with_resource(0usize); // add the usize resource
/// // we don't have to add the f32 resource because it comes as the result of node_a
/// ```
///
/// ### Resources
/// Input parameters don't always have to come from the results of functions, in fact they
/// more often come from a set of resources that live inside the graph.
/// Notice how we added the `&'static str` and `usize` resources to the graph explicitly using [`Graph::with_resource`](crate::Graph::with_resource).
/// So to recap - edge types are also known as resources and can come from the results of node functions or can be inserted into the graph manually before executing it.
///
/// ### Execution
/// After the graph is built it can be executed.
/// The order of execution of node functions is determined by the edge types of the functions themselves.
/// For example, since `node_b` takes as input the results of `node_a`, `node_b` must run _after_ `node_a`.
/// [`Graph`](crate::Graph) is smart enough to figure out these types of orderings by itself.
/// It can also determine which node functions access resources _mutably_, and therefore which node functions can be run in parallel.
/// But there are certain scenarios where type information is not enough to determine ordering.
/// For example if we were building a game we might need the physics step to run before rendering, but the types may not describe this and so we would have to state that ordering explicitly.
/// Luckily we can do that using [`graph!`](crate::graph) and the `>` and `<` operators:
/// ```rust
/// use moongraph::{Graph, GraphError, graph};
///
/// fn physics_step(_:()) -> Result<(), GraphError> {
///     println!("physics step goes here");
///     Ok(())
/// }
///
/// fn render(_:()) -> Result<(), GraphError> {
///     println!("rendering goes here");
///     Ok(())
/// }
///
/// let graph = graph!(physics_step < render);
/// ```
/// Alternatively we can use the [`Graph`](crate::Graph) and [`Node`](crate::Node) APIs to do the same thing:
/// ```rust
/// # use moongraph::{IsGraphNode, Graph, GraphError, graph};
/// #
/// # fn physics_step(_:()) -> Result<(), GraphError> {
/// #     println!("physics step goes here");
/// #     Ok(())
/// # }
/// #
/// # fn render(_:()) -> Result<(), GraphError> {
/// #     println!("rendering goes here");
/// #     Ok(())
/// # }
/// #
/// let graph = Graph::default()
///    .with_node(
///        physics_step
///            .into_node()
///            .with_name("physics_step")
///            .run_before("render")
///    )
///    .with_node(render.into_node().with_name("render"));
/// ```
/// You can see that the [`graph!`](crate::graph) macro is doing a lot of heavy lifting.
///
/// Now that we have our graph, we can run it:
/// ```rust
/// # use moongraph::{IsGraphNode, Graph, GraphError, graph};
/// #
/// # fn physics_step(_:()) -> Result<(), GraphError> {
/// #     println!("physics step goes here");
/// #     Ok(())
/// # }
/// #
/// # fn render(_:()) -> Result<(), GraphError> {
/// #     println!("rendering goes here");
/// #     Ok(())
/// # }
/// #
/// let mut graph = graph!(physics_step < render);
/// graph.run().unwrap();
/// ```
///
/// ## Full example
/// Here's another example where we'll implement a number of physics steps followed by an unrelated banking step.
/// After constructing the graph, we'll run the graph and also print out the schedule.
/// ```rust
/// use moongraph::*;
///
/// #[derive(Default)]
/// pub struct Position(f32, f32);
///
/// #[derive(Default)]
/// pub struct Velocity(f32, f32);
///
/// #[derive(Default)]
/// pub struct Acceleration(f32, f32);
///
/// #[derive(Default)]
/// pub struct BankAccount {
///     interest_rate: f32,
///     balance: f32,
/// }
///
/// pub fn add_acceleration((mut v, a): (ViewMut<Velocity>, View<Acceleration>)) -> Result<(), GraphError> {
///     v.0 += a.0;
///     v.1 += a.1;
///     Ok(())
/// }
///
/// pub fn add_velocity((mut p, v): (ViewMut<Position>, View<Velocity>)) -> Result<(), GraphError> {
///     p.0 += v.0;
///     p.1 += v.1;
///     Ok(())
/// }
///
/// pub fn compound_interest(mut acct: ViewMut<BankAccount>) -> Result<(), GraphError> {
///     let increment = acct.interest_rate * acct.balance;
///     acct.balance += increment;
///     Ok(())
/// }
///
/// let mut graph = graph!(
///     add_acceleration,
///     add_velocity,
///     compound_interest
/// )
/// .with_resource(Position(0.0, 0.0))
/// .with_resource(Velocity(0.0, 0.0))
/// .with_resource(Acceleration(1.0, 1.0))
/// .with_resource(BankAccount {
///     interest_rate: 0.02,
///     balance: 1337.0,
/// });
///
/// graph.run().unwrap();
/// let schedule = graph.get_schedule();
/// assert_eq!(
///     vec![
///         vec!["add_velocity", "compound_interest"],
///         vec!["add_acceleration"]
///     ],
///     schedule,
/// );
///
/// graph.run().unwrap();
/// let position = graph.get_resource::<Position>().unwrap().unwrap();
/// assert_eq!((1.0, 1.0), (position.0, position.1));
/// ```
///
/// Notice how the returned schedule shows that `add_velocity` and `compound_interest` can run together in parallel. We call this a "batch". It's possible to run all nodes in a batch at the same time because none of their borrows conflict and there are no explicit ordering constraints between them.
///
///
///
/// ## Conclusion
/// Hopefully by this point you have a better idea what `moongraph` is about and how to use it.
/// For more info please look at the module and type level documentation.
/// If you have any questions please reach out at [the moongraph GitHub repository](https://github.com/schell/moongraph).
///
/// Happy hacking! β˜•β˜•β˜•
pub mod tutorial {}