graph!() { /* proc-macro */ }
Expand description

Defines the control flow graph of an application.

The graph! macro defines a control flow graph that can be run as a stand-alone application or called as a subgraph from within another graph. The syntax follows the standard DOT language excepting a few new, non-standard attributes that can be applied to nodes and edges that conflagrate uses to construct the executable application logic.

Node Attributes

  • type – The nodetype associated with the node the in graph, which is a block of executable code that takes as input the output from the previous node and provides as output the input to the next node. Multiple nodes in the graph can use the same nodetype to facillitate more code reuse.
  • start – Labels the node to start the graph from. Only one node may be labeled with the start attribute.
  • branch – Tells conflagrate how to handle a node that has more than one node trailing it in the graph. May take the following values:
    • parallel (default) – Conflagrate executes all trailing nodes simultaneously in parallel. The return value from the node is cloned and passed separately to each tail. If the branch attribute is omitted, this value is assumed.
    • matcher – Conflagrate executes only one trailing node determined by the output of the matcher node. This puts constraints on the required return type of the nodetype (see nodetype: Matcher).
    • resultmatcher – A variant of matcher that matches on a Result instead of a String (see nodetype: Result Matcher).

Edge Attributes

  • value – Used with nodes with the branch=matcher attribute (see above). The return value of the matcher node is compared against this (string) value. If it matches, this edge is followed to determine the next node to be executed in the graph.

Examples

Trivial Graph

A single-node graph that just prints the text Hello, world!.

#[nodetype]
pub fn HelloWorld() {
    println!("Hello, world!");
}

graph!{
    digraph {
        start[type=HelloWorld, start=true];
    }
}

fn main() {
    Graph::run(());
}

Simple Loop

A simple loop that asks the user if they wish to exit (type yes to exit).

#[nodetype]
pub fn AskExit() -> (String, ()) {
    let mut response = String::new();
    println!("Exit loop?");
    std::io::stdin().read_line(&mut response).unwrap();
    response.truncate(response.len() - 1);
    (response, ())
}

#[nodetype]
pub async fn DoNothing() {}

graph!{
    digraph Loop {
        ask_exit[type=AskExit, branch=matcher, start=true];
        end[type=DoNothing];

        ask_exit -> end [value=yes];
        ask_exit -> ask_exit;
    }
}

fn main() {
    Loop::run(())
}

This graph makes use of the matcher branching logic. The ask_exit node has two tails, one that goes to the end node with the value=yes attribute, and another that goes back to the ask_exit node with no attributes. The matching logic chooses which trailing node to execute next based on the first element in the tuple output from the AskExit nodetype function. The second element of the tuple is then passed as input to the chosen following node.

See Also

  • nodetype – Macro associating functions with nodes.
  • dependency – Macro associating a function providing a resource with the name of the function, providing that resource to nodetypes that reference them.