Skip to main content

Crate reify_graph

Crate reify_graph 

Source
Expand description

Convert Rc<RefCell<T>> and Arc<Mutex<T>> pointer graphs into a flat, inspectable, serializable form, and back.

Pointer-shaped data (trees with shared subtrees, DAGs, cyclic graphs) is awkward to serialize, log, or transform: walking it naively either duplicates shared nodes or loops forever on cycles. This crate gives you a small, non-invasive API to:

  • Reify: turn a pointer graph rooted at an Rc<RefCell<T>> (or Arc<Mutex<T>>) into a flat ReifiedGraph of nodes and edges, keyed by pointer identity, detecting cycles and preserving sharing.
  • Reflect: rebuild the original pointer graph from a ReifiedGraph, restoring the same sharing topology (one allocation per node id, even when many edges point to it).

With the default serde feature enabled, ReifiedGraph is Serialize + Deserialize, which gives you JSON / postcard / etc. serialization of arbitrary cyclic data essentially for free.

§When to use it

  • You want to dump or log a graph for debugging (an AST with shared sub-expressions, a circuit netlist, a scene graph).
  • You want to send pointer-shaped state across a process boundary.
  • You want to apply a structural transform (renumbering, GC, deduping) that’s awkward on the live Rc graph but easy on a flat node+edge form.

§Design choices

  • Node identity comes from Rc::as_ptr (or Arc::as_ptr) cast to usize. No traits or wrappers required on your T.
  • Children are extracted by a closure you supply, so the library never guesses at the structure of your type.
  • Node data is cloned into the ReifiedGraph (use Arc<Inner> inside T if cloning is expensive).
  • Reconstruction in reflect_graph preserves sharing exactly: each NodeId becomes one Rc and is re-pointed everywhere it was referenced.

See the docs/phase2-graph-reification.md design note, and the serialize_graph example for an end-to-end serde_json round trip.

§Examples

Round-trip a small Rc<RefCell<_>> tree through the flat form:

use reify_graph::{reify_graph, reflect_graph};
use std::cell::RefCell;
use std::rc::Rc;

#[derive(Clone, Debug)]
struct Node {
    value: i32,
    children: Vec<Rc<RefCell<Node>>>,
}

let leaf = Rc::new(RefCell::new(Node { value: 1, children: vec![] }));
let root = Rc::new(RefCell::new(Node {
    value: 0,
    children: vec![leaf.clone()],
}));

// Flatten: 2 nodes, 1 edge
let graph = reify_graph(root.clone(), |n| n.children.clone());
assert_eq!(graph.nodes.len(), 2);
assert_eq!(graph.edges.len(), 1);

// Rebuild, restoring the original sharing
let reconstructed = reflect_graph(graph, |n, kids| n.children = kids);
assert_eq!(reconstructed.borrow().value, 0);
assert_eq!(reconstructed.borrow().children[0].borrow().value, 1);

For Arc<Mutex<T>> graphs (the same pattern, thread-safe), see the arc module’s reify_graph_arc and reflect_graph_arc.

Modules§

arc
Arc-pointer graph reification, parallel to the Rc<RefCell<T>> API.

Structs§

NodeId
A stable node identifier derived from pointer identity.
ReifiedGraph
An adjacency-list representation of a pointer graph.

Functions§

collect_nodes
Collect all reachable nodes from root, detecting shared pointers.
node_id_of
Extract a NodeId from an Rc<RefCell<T>> using pointer identity.
reflect_graph
Reconstruct an Rc<RefCell<T>> graph from a ReifiedGraph.
reify_graph
Reify an Rc<RefCell<T>> graph into a ReifiedGraph.