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.
  • 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 attributed is omitted, this value is assumed.
    • matcher – Conflagrate executes only one trailing node. The choice of node depends on the value returned by the nodetype function. Edges tagged with the value attribute (see below) are matched against the returned value, and a matching edge determines the following node. If no matches are found, the edge without a value attribute is used as the default.

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.