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>>(orArc<Mutex<T>>) into a flatReifiedGraphof 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
Rcgraph but easy on a flat node+edge form.
§Design choices
- Node identity comes from
Rc::as_ptr(orArc::as_ptr) cast tousize. No traits or wrappers required on yourT. - 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(useArc<Inner>insideTif cloning is expensive). - Reconstruction in
reflect_graphpreserves sharing exactly: eachNodeIdbecomes oneRcand 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.
- Reified
Graph - 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
NodeIdfrom anRc<RefCell<T>>using pointer identity. - reflect_
graph - Reconstruct an
Rc<RefCell<T>>graph from aReifiedGraph. - reify_
graph - Reify an
Rc<RefCell<T>>graph into aReifiedGraph.