Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

mgraph! — Construction

The mgraph! macro constructs a graph from a declarative description of nodes and edges.

DSL Primitives

SymbolMeaning
N(id)New node with explicit local id
N_()New node with auto-assigned id
n(id)Reference to previously defined node
E()Edge constructor (for attaching values)
.val(v)Attach a value to a node or edge
.include(p)Add a part to a composite edge value (see Composite Values)
^Undirected edge
>>Directed edge (source → target)
<<Directed edge (target ← source)
&Attach explicit edge value before direction operator
,Separate independent fragments

Operator Precedence

The edge operators (^, >>, <<) are left-associative in Rust. This has an important consequence:

  • Flat chaining N(0) ^ N(1) ^ N(2) creates a star — all edges radiate from node 0
  • Grouping N(0) ^ (N(1) ^ N(2)) creates a path — 0 connects to 1, 1 connects to 2

This is because N(0) ^ N(1) returns node 0 (with an edge to 1 attached), so the next ^ N(2) adds another edge from 0.

Undirected Graphs

Path (grouping)

use grw::graph::{self, MGraph, edge};

// path: 0 — 1 — 2
let g: MGraph<(), edge::Undir<()>> = mgraph![
    N(0) ^ (N(1) ^ N(2))
].unwrap();

012

Triangle (back-reference)

// triangle: chain + n() closes the cycle
let g: MGraph<(), edge::Undir<()>> = mgraph![
    N(0) ^ (N(1) ^ (N(2) ^ n(0)))
].unwrap();

012

Star (flat chaining)

// star: flat chaining fans out from one node
let g: MGraph<(), edge::Undir<()>> = mgraph![
    N(0) ^ N(1)
         ^ N(2)
         ^ N(3)
         ^ N(4)
].unwrap();

01234

With Values

// node values
let g: MGraph<&str, edge::Undir<()>> = mgraph![
    N(0).val("alice") ^ (N(1).val("bob") ^ N(2).val("carol"))
].unwrap();

// edge values — & E().val(...) before direction operator
let g: MGraph<(), edge::Undir<f64>> = mgraph![
    N(0) & E().val(1.5) ^ (N(1) & E().val(2.0) ^ N(2))
].unwrap();

// both
let g: MGraph<&str, edge::Undir<u32>> = mgraph![
    N(0).val("a") & E().val(10) ^ N(1).val("b")
].unwrap();

Composite Edge Values

When the edge value is a composite (for example TypeSet<P>), E().include(p).include(q) builds one link holding both parts; naming one kind twice on a link is a typed build error. See Composite Values.

Anonymous Nodes

// ids assigned automatically
let g: MGraph<(), edge::Undir<()>> = mgraph![N_() ^ N_() ^ N_()].unwrap();

Directed Graphs

// path: 0 → 1 → 2
let g: MGraph<(), edge::Dir<()>> = mgraph![
    N(0) >> (N(1) >> N(2))
].unwrap();

012

// fan-out: flat chaining from one node
let g: MGraph<(), edge::Dir<()>> = mgraph![
    N(0) >> N(1)
         >> N(2)
         >> N(3)
].unwrap();

0123

// bidirectional: n() references existing nodes
let g: MGraph<(), edge::Dir<()>> = mgraph![
    N(0) >> N(1),
    n(1) >> n(0),
].unwrap();

01

// incoming edges with <<
let g: MGraph<(), edge::Dir<()>> = mgraph![
    N(0) << N(1),   // edge from 1 to 0
].unwrap();

Anydirected Graphs

Mix undirected and directed edges in one graph:

let g: MGraph<(), edge::Anydir<()>> = mgraph![
    N(0) ^ (N(1) >> N(2)),  // 0 — 1 → 2
    N(3) << n(2),            // 2 → 3
].unwrap();

0123^>><<

// all three edge types between one pair
let g: MGraph<(), edge::Anydir<()>> = mgraph![
    N(0) ^ N(1),         // undirected
    n(0) >> n(1),        // directed 0 → 1
    n(1) >> n(0),        // directed 1 → 0
].unwrap();

01>>^<<

Turbofish Syntax

When the type can’t be inferred, use the turbofish form:

let g = mgraph![<(), grw::graph::edge::Undir<()>>; N(0) ^ N(1)].unwrap();

Multiple Fragments

Use commas to separate disconnected components or back-references:

// two separate edges, then connect them
let g: MGraph<(), edge::Undir<()>> = mgraph![
    N(0) ^ N(1),
    N(2) ^ N(3),
    n(0) ^ n(2),
].unwrap();