pub fn transform<N, F>(
src: &Arena<N>,
root: Id<N>,
dst: &mut Arena<N>,
f: F,
) -> Option<Id<N>>Expand description
Rebuilds the tree rooted at root from src into dst, passing every node
through f, and returns the handle of the new root.
This is the rewrite (fold) operation: a copy of the subtree is built in the
destination arena, and f gets a chance to replace each node as it is rebuilt.
Nodes are processed post-order — every child is rebuilt and allocated into
dst before its parent — so when f receives a node, that node’s child handles
have already been remapped to point at their new selves in dst. With f set
to the identity (|node| node), the result is a faithful deep copy: same shape,
same span on every node.
The traversal is the iterative walk, so an arbitrarily deep tree is rebuilt
without recursing on the call stack. It assumes a tree — each node reachable
from root exactly once; a shared sub-node would be copied once per path to it.
§Returns
The handle of the rebuilt root in dst, or None if root names no live node
in src, or if dst runs out of capacity while allocating. Either way dst
is left holding whatever was allocated before the stop, and never panics.
§Examples
Deep-copy a tree, doubling every literal on the way:
use ast_lang::{transform, walk, Arena, Flow, Id, Node, Span, Visitor};
#[derive(Clone)]
enum Expr {
Lit(i64, Span),
Add(Id<Expr>, Id<Expr>, Span),
}
impl Node for Expr {
fn span(&self) -> Span {
match self {
Expr::Lit(_, s) | Expr::Add(_, _, s) => *s,
}
}
fn each_child(&self, f: &mut dyn FnMut(Id<Self>)) {
if let Expr::Add(a, b, _) = self {
f(*a);
f(*b);
}
}
fn map_children(&self, f: &mut dyn FnMut(Id<Self>) -> Id<Self>) -> Self {
match self {
Expr::Lit(v, s) => Expr::Lit(*v, *s),
Expr::Add(a, b, s) => Expr::Add(f(*a), f(*b), *s),
}
}
}
let mut src = Arena::new();
let one = src.alloc(Expr::Lit(1, Span::new(0, 1)));
let two = src.alloc(Expr::Lit(2, Span::new(4, 5)));
let add = src.alloc(Expr::Add(one, two, Span::new(0, 5)));
let mut dst = Arena::new();
let new_root = transform(&src, add, &mut dst, |node| match node {
Expr::Lit(v, s) => Expr::Lit(v * 2, s),
other => other,
})
.expect("root is live");
// The rebuilt tree sums to 2*(1) + 2*(2) = 6.
struct Sum(i64);
impl Visitor<Expr> for Sum {
fn enter(&mut self, _: &Arena<Expr>, _: Id<Expr>, node: &Expr) -> Flow {
if let Expr::Lit(v, _) = node {
self.0 += *v;
}
Flow::Continue
}
}
let mut sum = Sum(0);
walk(&dst, new_root, &mut sum);
assert_eq!(sum.0, 6);