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
//! Conflagrate is a framework for building applications from control flow graphs, instead of
//! the other way around.
//!
//! Conflagrate is designed to bring modularity, maintainability, and extensibility to control flow
//! logic.  Where object oriented design, functional programming, dependency injection, and similar
//! tools help developers build and reuse functionality, conflagrate helps developers to encapsulate
//! that functionality in modular, testable building blocks that can be arranged and rearranged to
//! construct a complete application.  Importantly, this application's control flow can be easily
//! updated to change the order of operations, conditions of branch execution, or even to add
//! entirely new subsystems without needing to refactor existing components or control flow.
//!
//! The control flow graph is defined with the [`graph`] macro, which converts your graph as
//! defined with the [DOT language](https://graphviz.org) into an executable structure.  Each
//! node in the graph is annotated with a [`nodetype`] that associates a block of code with the
//! node. Finally, sometimes a node needs more to do its job than just the output of the previous
//! node in the graph.  Conflagrate provides a simple dependency injection system to provide
//! external resources and data.  Define a dependency provider function with the [`dependency`]
//! macro and add a reference to the dependency to the [`nodetype`] function signature.
//!
//! # Examples
//!
//! A simple program to record console inputs on a loop and echo them all back on exit:
//! ```no_run
//! # use tokio::sync::Mutex;
//! # use conflagrate::{dependency, graph, nodetype};
//! #
//! #[dependency]
//! async fn memory() -> Mutex<Vec<String>> {
//!     Mutex::new(Vec::<String>::new())
//! }
//!
//! #[nodetype]
//! pub fn GetInput() -> String {
//!     let mut input = String::new();
//!     println!("Type any input ('exit' to exit):");
//!     std::io::stdin().read_line(&mut input).unwrap();
//!     input.truncate(input.len() - 1);
//!     input
//! }
//!
//! #[nodetype]
//! async fn Record(input: String, memory: &Mutex<Vec<String>>) -> (String, ()) {
//!     memory.lock().await.push(input.clone());
//!     (input, ())
//! }
//!
//! #[nodetype]
//! pub async fn EchoAndExit(memory: &Mutex<Vec<String>>) {
//!     println!("You entered:");
//!     let inputs = memory.lock().await;
//!     for input in inputs.iter() {
//!         println!("{}", input);
//!     }
//! }
//!
//! graph! {
//!     digraph MemoryEcho {
//!         node[shape=box];
//!
//!         get_input[label="Get Input", type=GetInput, start=true];
//!         echo_and_exit[label="Echo Recorded\nInput and Exit", type=EchoAndExit];
//!         record[label="Record and Loop", type=Record, branch=matcher];
//!
//!         get_input -> record;
//!         record -> echo_and_exit [label=exit, value=exit];
//!         record -> get_input;
//!     }
//! }
//!
//! fn main() {
//!     MemoryEcho::run(());
//! }
//! ```

mod branchtracker;
mod dependencies;

pub use conflagrate_macros::{dependency, graph, nodetype};
#[doc(hidden)]
pub use branchtracker::BranchTracker;
#[doc(hidden)]
pub use dependencies::DependencyCache;

#[doc(hidden)]
#[async_trait::async_trait]
pub trait NodeType {
    type Args: Clone;
    type ReturnType;
    async fn run(args: Self::Args, deps: &DependencyCache) -> Self::ReturnType;
}