@@ -42,6 +42,7 @@ impl State {
42
42
mut changes : Option < & mut InternalChanges > ,
43
43
) {
44
44
let mut unreachable = HashSet :: new ( ) ;
45
+ let mut seen_child_ids = HashSet :: new ( ) ;
45
46
46
47
if let Some ( tree) = update. tree {
47
48
if tree. root != self . data . root {
@@ -74,14 +75,11 @@ impl State {
74
75
for ( node_id, node_data) in update. nodes {
75
76
unreachable. remove ( & node_id) ;
76
77
77
- let mut seen_child_ids = HashSet :: with_capacity ( node_data. children ( ) . len ( ) ) ;
78
78
for ( child_index, child_id) in node_data. children ( ) . iter ( ) . enumerate ( ) {
79
79
if seen_child_ids. contains ( child_id) {
80
- panic ! (
81
- "Node {:?} of TreeUpdate includes duplicate child {:?};" ,
82
- node_id, child_id
83
- ) ;
80
+ panic ! ( "TreeUpdate includes duplicate child {:?}" , child_id) ;
84
81
}
82
+ seen_child_ids. insert ( * child_id) ;
85
83
unreachable. remove ( child_id) ;
86
84
let parent_and_index = ParentAndIndex ( node_id, child_index) ;
87
85
if let Some ( child_state) = self . nodes . get_mut ( child_id) {
@@ -102,7 +100,6 @@ impl State {
102
100
} else {
103
101
pending_children. insert ( * child_id, parent_and_index) ;
104
102
}
105
- seen_child_ids. insert ( * child_id) ;
106
103
}
107
104
108
105
if let Some ( node_state) = self . nodes . get_mut ( & node_id) {
@@ -149,19 +146,22 @@ impl State {
149
146
fn traverse_unreachable (
150
147
nodes : & mut HashMap < NodeId , NodeState > ,
151
148
changes : & mut Option < & mut InternalChanges > ,
149
+ seen_child_ids : & HashSet < NodeId > ,
152
150
id : NodeId ,
153
151
) {
154
152
if let Some ( changes) = changes {
155
153
changes. removed_node_ids . insert ( id) ;
156
154
}
157
155
let node = nodes. remove ( & id) . unwrap ( ) ;
158
156
for child_id in node. data . children ( ) . iter ( ) {
159
- traverse_unreachable ( nodes, changes, * child_id) ;
157
+ if !seen_child_ids. contains ( child_id) {
158
+ traverse_unreachable ( nodes, changes, seen_child_ids, * child_id) ;
159
+ }
160
160
}
161
161
}
162
162
163
163
for id in unreachable {
164
- traverse_unreachable ( & mut self . nodes , & mut changes, id) ;
164
+ traverse_unreachable ( & mut self . nodes , & mut changes, & seen_child_ids , id) ;
165
165
}
166
166
}
167
167
@@ -373,7 +373,7 @@ impl<T> fmt::Display for ShortNodeList<'_, T> {
373
373
#[ cfg( test) ]
374
374
mod tests {
375
375
use accesskit:: { Node , NodeId , Role , Tree , TreeUpdate } ;
376
- use alloc:: vec;
376
+ use alloc:: { vec, vec :: Vec } ;
377
377
378
378
#[ test]
379
379
fn init_tree_with_root_node ( ) {
@@ -765,4 +765,99 @@ mod tests {
765
765
let mut handler = Handler { } ;
766
766
tree. update_and_process_changes ( update, & mut handler) ;
767
767
}
768
+
769
+ #[ test]
770
+ fn move_node ( ) {
771
+ struct Handler {
772
+ got_updated_root : bool ,
773
+ got_updated_child : bool ,
774
+ got_removed_container : bool ,
775
+ }
776
+
777
+ fn unexpected_change ( ) {
778
+ panic ! ( "expected only updated root and removed container" ) ;
779
+ }
780
+
781
+ impl super :: ChangeHandler for Handler {
782
+ fn node_added ( & mut self , _node : & crate :: Node ) {
783
+ unexpected_change ( ) ;
784
+ }
785
+ fn node_updated ( & mut self , old_node : & crate :: Node , new_node : & crate :: Node ) {
786
+ if new_node. id ( ) == NodeId ( 0 )
787
+ && old_node. child_ids ( ) . collect :: < Vec < NodeId > > ( ) == vec ! [ NodeId ( 1 ) ]
788
+ && new_node. child_ids ( ) . collect :: < Vec < NodeId > > ( ) == vec ! [ NodeId ( 2 ) ]
789
+ {
790
+ self . got_updated_root = true ;
791
+ return ;
792
+ }
793
+ if new_node. id ( ) == NodeId ( 2 )
794
+ && old_node. parent_id ( ) == Some ( NodeId ( 1 ) )
795
+ && new_node. parent_id ( ) == Some ( NodeId ( 0 ) )
796
+ {
797
+ self . got_updated_child = true ;
798
+ return ;
799
+ }
800
+ unexpected_change ( ) ;
801
+ }
802
+ fn focus_moved (
803
+ & mut self ,
804
+ _old_node : Option < & crate :: Node > ,
805
+ _new_node : Option < & crate :: Node > ,
806
+ ) {
807
+ unexpected_change ( ) ;
808
+ }
809
+ fn node_removed ( & mut self , node : & crate :: Node ) {
810
+ if node. id ( ) == NodeId ( 1 ) {
811
+ self . got_removed_container = true ;
812
+ return ;
813
+ }
814
+ unexpected_change ( ) ;
815
+ }
816
+ }
817
+
818
+ let mut root = Node :: new ( Role :: Window ) ;
819
+ root. set_children ( [ NodeId ( 1 ) ] ) ;
820
+ let mut container = Node :: new ( Role :: GenericContainer ) ;
821
+ container. set_children ( [ NodeId ( 2 ) ] ) ;
822
+ let update = TreeUpdate {
823
+ nodes : vec ! [
824
+ ( NodeId ( 0 ) , root. clone( ) ) ,
825
+ ( NodeId ( 1 ) , container) ,
826
+ ( NodeId ( 2 ) , Node :: new( Role :: Button ) ) ,
827
+ ] ,
828
+ tree : Some ( Tree :: new ( NodeId ( 0 ) ) ) ,
829
+ focus : NodeId ( 0 ) ,
830
+ } ;
831
+ let mut tree = crate :: Tree :: new ( update, false ) ;
832
+ root. set_children ( [ NodeId ( 2 ) ] ) ;
833
+ let mut handler = Handler {
834
+ got_updated_root : false ,
835
+ got_updated_child : false ,
836
+ got_removed_container : false ,
837
+ } ;
838
+ tree. update_and_process_changes (
839
+ TreeUpdate {
840
+ nodes : vec ! [ ( NodeId ( 0 ) , root) ] ,
841
+ tree : None ,
842
+ focus : NodeId ( 0 ) ,
843
+ } ,
844
+ & mut handler,
845
+ ) ;
846
+ assert ! ( handler. got_updated_root) ;
847
+ assert ! ( handler. got_updated_child) ;
848
+ assert ! ( handler. got_removed_container) ;
849
+ assert_eq ! (
850
+ tree. state( )
851
+ . node_by_id( NodeId ( 0 ) )
852
+ . unwrap( )
853
+ . child_ids( )
854
+ . collect:: <Vec <NodeId >>( ) ,
855
+ vec![ NodeId ( 2 ) ]
856
+ ) ;
857
+ assert ! ( tree. state( ) . node_by_id( NodeId ( 1 ) ) . is_none( ) ) ;
858
+ assert_eq ! (
859
+ tree. state( ) . node_by_id( NodeId ( 2 ) ) . unwrap( ) . parent_id( ) ,
860
+ Some ( NodeId ( 0 ) )
861
+ ) ;
862
+ }
768
863
}
0 commit comments