mgraph! — Construction
The mgraph! macro constructs a graph from a declarative description of nodes and edges.
DSL Primitives
| Symbol | Meaning |
|---|---|
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();
Triangle (back-reference)
// triangle: chain + n() closes the cycle
let g: MGraph<(), edge::Undir<()>> = mgraph![
N(0) ^ (N(1) ^ (N(2) ^ n(0)))
].unwrap();
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();
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();
// fan-out: flat chaining from one node
let g: MGraph<(), edge::Dir<()>> = mgraph![
N(0) >> N(1)
>> N(2)
>> N(3)
].unwrap();
// bidirectional: n() references existing nodes
let g: MGraph<(), edge::Dir<()>> = mgraph![
N(0) >> N(1),
n(1) >> n(0),
].unwrap();
// 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();
// 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();
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();