dot-parser 0.6.1

This library provides a parser for the DOT/Graphviz graph description language, as well as useful functions to transform those graphs.
Documentation
// The goal of this example is to illustrate the difference between ast::Graph
// and canonical::Graph. In practice, unless you need to work with ast::Graph,
// for a very good reason, canonical::Graph will make your life easier.

use dot_parser::ast;
use dot_parser::canonical;

static DOT_STR: &str = "graph {
    A [label=A][color=grey]
    B [label=B][color=grey]
    C [label=C]
    D [label=D]

    A -- B -- subgraph { C D }
}";

fn main() {
    let ast_graph = ast::Graph::try_from(DOT_STR).unwrap();
    let canonical_graph = canonical::Graph::from(ast_graph.clone());

    // Working with ast_graph is painful, because the structure follows closely
    // the syntax: for instance, the `ast::Graph` structure has a `stmts` field,
    // which contains a `NodeStmt` (for A) which contains an `AttrList` field, which
    // contains two `AList`s, each containing a single attribute, because the two attributes were given in separate
    // lists (`[label=A][color=grey]` instead of `[label=A; color=grey]`).
    //
    // Printing all attributes is painful:
    
    println!("Showing all attributes using ast::Graph:");
    for stmt in ast_graph.stmts {
        if let ast::Stmt::NodeStmt(n) = stmt {
            if let Some(attr_list) = n.attr {
                for alist in attr_list {
                    for (attr, val) in alist {
                        println!("({}, {})", attr, val);
                    }
                }
            }
        }
    }

    // Fortunatelly, we can work with a canonical graph, which converts the
    // ast::Graph into something that follows more closely our intuition:
    println!("\nShowing all attributes using canonical::Graph:");
    for node in canonical_graph.nodes.set.values() {
        for (attr, val) in &node.attr {
            println!("({}, {})", attr, val);
        }
    }
    

    // Similarly, the grammar allows to chain edges, and to have subgraphs in
    // chains:
    // (`A -- B -- subgraph { C D }`). 
    //
    // This is equivalent to writing explicitly the three following edges: 
    // ```
    // A -- B
    // B -- C
    // B -- D
    // ```
    //
    // While working with the graph, it would be easier to deal with the list of
    // explicit edges, instead of working the chained edges.
    // Suppose we want to print all the edges, doing it with ast::Graph is so
    // painful that I don't even want to do it here: we first need to split each
    // step of the EdgeStmt into separate edges, then look at the source and the
    // destination, and check whether they are a subgraph or not, and if it is, get
    // all the nodes from the subgraph (for both the source and the destination)
    // and create an edge for each of them... this is super annoying in
    // practice (in particular, think about nested subgraphs, and dealing with
    // edges within subgraphs themselves).

    // Fortunatelly, canonical::Graph deals with this complexity:
    println!("\nShowing all edges using canonical::Graph:");
    for edge in canonical_graph.edges.set {
        println!("{} -- {}", edge.from, edge.to);
    }
}