@@ -34,44 +34,48 @@ pub const CHILD_FIELD: u16 = u16::MAX;
3434#[ derive( Debug ) ]
3535pub struct AstCursor < ' a > {
3636 ast : & ' a Ast ,
37- /// A stack of parents, along with iterators for their children
38- parents : Vec < ( & ' a Node , ChildrenIter < ' a > ) > ,
39- node : & ' a Node ,
37+ /// A stack of parents, along with iterators for their children.
38+ parents : Vec < ( Id , ChildrenIter < ' a > ) > ,
39+ node_id : Id ,
4040}
4141
4242impl < ' a > AstCursor < ' a > {
4343 pub fn new ( ast : & ' a Ast ) -> Self {
44- // TODO: handle non-zero root
45- let node = ast. get_node ( ast. root ) . unwrap ( ) ;
4644 Self {
4745 ast,
4846 parents : vec ! [ ] ,
49- node ,
47+ node_id : ast . root ,
5048 }
5149 }
5250
51+ /// The Id of the node currently under the cursor.
52+ pub fn node_id ( & self ) -> Id {
53+ self . node_id
54+ }
55+
5356 fn goto_next_sibling_opt ( & mut self ) -> Option < ( ) > {
54- self . node = self . parents . last_mut ( ) ?. 1 . next ( ) ?;
57+ self . node_id = self . parents . last_mut ( ) ?. 1 . next ( ) ?;
5558 Some ( ( ) )
5659 }
5760
5861 fn goto_first_child_opt ( & mut self ) -> Option < ( ) > {
59- let parent = self . node ;
60- let mut children = ChildrenIter :: new ( self . ast , parent) ;
62+ let parent_id = self . node_id ;
63+ let parent = self . ast . get_node ( parent_id) ?;
64+ let mut children = ChildrenIter :: new ( parent) ;
6165 let first_child = children. next ( ) ?;
62- self . node = first_child;
63- self . parents . push ( ( parent , children) ) ;
66+ self . node_id = first_child;
67+ self . parents . push ( ( parent_id , children) ) ;
6468 Some ( ( ) )
6569 }
6670
6771 fn goto_parent_opt ( & mut self ) -> Option < ( ) > {
68- self . node = self . parents . pop ( ) ?. 0 ;
72+ self . node_id = self . parents . pop ( ) ?. 0 ;
6973 Some ( ( ) )
7074 }
7175}
7276impl < ' a > Cursor < ' a , Ast , Node , FieldId > for AstCursor < ' a > {
7377 fn node ( & self ) -> & ' a Node {
74- self . node
78+ & self . ast . nodes [ self . node_id ]
7579 }
7680
7781 fn field_id ( & self ) -> Option < FieldId > {
@@ -101,36 +105,30 @@ impl<'a> Cursor<'a, Ast, Node, FieldId> for AstCursor<'a> {
101105 }
102106}
103107
104- /// An iterator over all the child nodes of a node.
108+ /// An iterator over the child Ids of a node.
105109#[ derive( Debug ) ]
106110struct ChildrenIter < ' a > {
107- ast : & ' a Ast ,
108111 current_field : Option < FieldId > ,
109112 fields : std:: collections:: btree_map:: Iter < ' a , FieldId , Vec < Id > > ,
110113 field_children : Option < std:: slice:: Iter < ' a , Id > > ,
111114}
112115
113116impl < ' a > ChildrenIter < ' a > {
114- fn new ( ast : & ' a Ast , node : & ' a Node ) -> Self {
117+ fn new ( node : & ' a Node ) -> Self {
115118 Self {
116- ast,
117119 current_field : None ,
118120 fields : node. fields . iter ( ) ,
119121 field_children : None ,
120122 }
121123 }
122124
123- fn get_node ( & self , id : Id ) -> & ' a Node {
124- self . ast . get_node ( id) . unwrap ( )
125- }
126-
127125 fn current_field ( & self ) -> Option < FieldId > {
128126 self . current_field
129127 }
130128}
131129
132- impl < ' a > Iterator for ChildrenIter < ' a > {
133- type Item = & ' a Node ;
130+ impl Iterator for ChildrenIter < ' _ > {
131+ type Item = Id ;
134132
135133 fn next ( & mut self ) -> Option < Self :: Item > {
136134 match self . field_children . as_mut ( ) {
@@ -151,7 +149,7 @@ impl<'a> Iterator for ChildrenIter<'a> {
151149 self . next ( )
152150 }
153151 } ,
154- Some ( child_id) => Some ( self . get_node ( * child_id) ) ,
152+ Some ( child_id) => Some ( * child_id) ,
155153 } ,
156154 }
157155 }
@@ -236,7 +234,6 @@ impl Ast {
236234 ) -> Id {
237235 let id = self . nodes . len ( ) ;
238236 self . nodes . push ( Node {
239- id,
240237 kind,
241238 kind_name : self . schema . node_kind_for_id ( kind) . unwrap ( ) ,
242239 fields,
@@ -265,7 +262,6 @@ impl Ast {
265262 } ) ;
266263 let id = self . nodes . len ( ) ;
267264 self . nodes . push ( Node {
268- id,
269265 kind : kind_id,
270266 kind_name : kind,
271267 is_named : true ,
@@ -345,7 +341,6 @@ impl Ast {
345341/// A node in our AST
346342#[ derive( PartialEq , Eq , Debug , Clone , Serialize ) ]
347343pub struct Node {
348- id : Id ,
349344 kind : KindId ,
350345 kind_name : & ' static str ,
351346 pub ( crate ) fields : BTreeMap < FieldId , Vec < Id > > ,
@@ -361,10 +356,6 @@ pub struct Node {
361356}
362357
363358impl Node {
364- pub fn id ( & self ) -> Id {
365- self . id
366- }
367-
368359 pub fn kind ( & self ) -> & ' static str {
369360 self . kind_name
370361 }
@@ -600,39 +591,41 @@ fn apply_rules_inner(
600591 }
601592 }
602593
603- // Collect fields before recursing (avoids borrowing ast immutably during mutation)
604- let field_entries: Vec < ( FieldId , Vec < Id > ) > = ast. nodes [ id]
605- . fields
606- . iter ( )
607- . map ( |( & fid, children) | ( fid, children. clone ( ) ) )
608- . collect ( ) ;
609-
610- // recursively descend into all the fields
594+ // Take the parent's fields by ownership: the recursion will rewrite
595+ // each child Id, and we'll write the (possibly mutated) field map back
596+ // when we're done. Avoids cloning the whole BTreeMap and its child
597+ // Vecs on entry. Each child Vec is only re-allocated if a rewrite
598+ // actually changes its contents.
599+ //
611600 // Child traversal does not increment rewrite depth and starts fresh
612601 // (no rule is skipped on child subtrees).
613- let mut changed = false ;
614- let mut new_fields = BTreeMap :: new ( ) ;
615- for ( field_id, children) in field_entries {
616- let mut new_children = Vec :: new ( ) ;
617- for child_id in children {
602+ let mut fields = std:: mem:: take ( & mut ast. nodes [ id] . fields ) ;
603+ for children in fields. values_mut ( ) {
604+ let mut new_children: Option < Vec < Id > > = None ;
605+ for ( i, & child_id) in children. iter ( ) . enumerate ( ) {
618606 let result = apply_rules_inner ( index, ast, child_id, fresh, rewrite_depth, None ) ?;
619- if result. len ( ) != 1 || result[ 0 ] != child_id {
620- changed = true ;
607+ let unchanged = result. len ( ) == 1 && result[ 0 ] == child_id;
608+ match ( & mut new_children, unchanged) {
609+ ( None , true ) => { } // unchanged so far, no allocation needed
610+ ( None , false ) => {
611+ // First divergence — copy already-processed Ids and
612+ // start collecting the rewritten sequence.
613+ let mut new = Vec :: with_capacity ( children. len ( ) ) ;
614+ new. extend_from_slice ( & children[ ..i] ) ;
615+ new. extend ( result) ;
616+ new_children = Some ( new) ;
617+ }
618+ ( Some ( new) , _) => {
619+ new. extend ( result) ;
620+ }
621621 }
622- new_children. extend ( result) ;
623622 }
624- new_fields. insert ( field_id, new_children) ;
625- }
626-
627- if !changed {
628- return Ok ( vec ! [ id] ) ;
623+ if let Some ( new) = new_children {
624+ * children = new;
625+ }
629626 }
630-
631- let mut node = ast. nodes [ id] . clone ( ) ;
632- node. fields = new_fields;
633- node. id = ast. nodes . len ( ) ;
634- ast. nodes . push ( node) ;
635- Ok ( vec ! [ ast. nodes. len( ) - 1 ] )
627+ ast. nodes [ id] . fields = fields;
628+ Ok ( vec ! [ id] )
636629}
637630
638631/// One phase of a desugaring pass: a named bundle of rules that runs to
0 commit comments