1// Copyright 2021 The AccessKit Authors. All rights reserved.
2// Licensed under the Apache License, Version 2.0 (found in
3// the LICENSE-APACHE file) or the MIT license (found in
4// the LICENSE-MIT file), at your option.
5
6// Derived from Chromium's accessibility abstraction.
7// Copyright 2018 The Chromium Authors. All rights reserved.
8// Use of this source code is governed by a BSD-style license that can be
9// found in the LICENSE.chromium file.
10
11use std::iter::FusedIterator;
12
13use accesskit::NodeId;
14
15use crate::{filters::FilterResult, node::Node, tree::State as TreeState};
16
17/// An iterator that yields following siblings of a node.
18///
19/// This struct is created by the [`following_siblings`](Node::following_siblings) method on [`Node`].
20pub struct FollowingSiblings<'a> {
21 back_position: usize,
22 done: bool,
23 front_position: usize,
24 parent: Option<Node<'a>>,
25}
26
27impl<'a> FollowingSiblings<'a> {
28 pub(crate) fn new(node: Node<'a>) -> Self {
29 let parent_and_index: Option<(Node<'_>, usize)> = node.parent_and_index();
30 let (back_position: usize, front_position: usize, done: bool) =
31 if let Some((ref parent: &Node<'_>, index: usize)) = parent_and_index {
32 let back_position: usize = parent.data().children().len() - 1;
33 let front_position: usize = index + 1;
34 (
35 back_position,
36 front_position,
37 front_position > back_position,
38 )
39 } else {
40 (0, 0, true)
41 };
42 Self {
43 back_position,
44 done,
45 front_position,
46 parent: parent_and_index.map(|(parent: Node<'_>, _)| parent),
47 }
48 }
49}
50
51impl<'a> Iterator for FollowingSiblings<'a> {
52 type Item = NodeId;
53
54 fn next(&mut self) -> Option<Self::Item> {
55 if self.done {
56 None
57 } else {
58 self.done = self.front_position == self.back_position;
59 let child = self
60 .parent
61 .as_ref()?
62 .data()
63 .children()
64 .get(self.front_position)?;
65 self.front_position += 1;
66 Some(*child)
67 }
68 }
69
70 fn size_hint(&self) -> (usize, Option<usize>) {
71 let len = match self.done {
72 true => 0,
73 _ => self.back_position + 1 - self.front_position,
74 };
75 (len, Some(len))
76 }
77}
78
79impl<'a> DoubleEndedIterator for FollowingSiblings<'a> {
80 fn next_back(&mut self) -> Option<Self::Item> {
81 if self.done {
82 None
83 } else {
84 self.done = self.back_position == self.front_position;
85 let child: &NodeId = self
86 .parent
87 .as_ref()?
88 .data()
89 .children()
90 .get(self.back_position)?;
91 self.back_position -= 1;
92 Some(*child)
93 }
94 }
95}
96
97impl<'a> ExactSizeIterator for FollowingSiblings<'a> {}
98
99impl<'a> FusedIterator for FollowingSiblings<'a> {}
100
101/// An iterator that yields preceding siblings of a node.
102///
103/// This struct is created by the [`preceding_siblings`](Node::preceding_siblings) method on [`Node`].
104pub struct PrecedingSiblings<'a> {
105 back_position: usize,
106 done: bool,
107 front_position: usize,
108 parent: Option<Node<'a>>,
109}
110
111impl<'a> PrecedingSiblings<'a> {
112 pub(crate) fn new(node: Node<'a>) -> Self {
113 let parent_and_index: Option<(Node<'_>, usize)> = node.parent_and_index();
114 let (back_position: usize, front_position: usize, done: bool) = if let Some((_, index: usize)) = parent_and_index {
115 let front_position: usize = index.saturating_sub(1);
116 (0, front_position, index == 0)
117 } else {
118 (0, 0, true)
119 };
120 Self {
121 back_position,
122 done,
123 front_position,
124 parent: parent_and_index.map(|(parent: Node<'_>, _)| parent),
125 }
126 }
127}
128
129impl<'a> Iterator for PrecedingSiblings<'a> {
130 type Item = NodeId;
131
132 fn next(&mut self) -> Option<Self::Item> {
133 if self.done {
134 None
135 } else {
136 self.done = self.front_position == self.back_position;
137 let child = self
138 .parent
139 .as_ref()?
140 .data()
141 .children()
142 .get(self.front_position)?;
143 if !self.done {
144 self.front_position -= 1;
145 }
146 Some(*child)
147 }
148 }
149
150 fn size_hint(&self) -> (usize, Option<usize>) {
151 let len = match self.done {
152 true => 0,
153 _ => self.front_position + 1 - self.back_position,
154 };
155 (len, Some(len))
156 }
157}
158
159impl<'a> DoubleEndedIterator for PrecedingSiblings<'a> {
160 fn next_back(&mut self) -> Option<Self::Item> {
161 if self.done {
162 None
163 } else {
164 self.done = self.back_position == self.front_position;
165 let child: &NodeId = self
166 .parent
167 .as_ref()?
168 .data()
169 .children()
170 .get(self.back_position)?;
171 self.back_position += 1;
172 Some(*child)
173 }
174 }
175}
176
177impl<'a> ExactSizeIterator for PrecedingSiblings<'a> {}
178
179impl<'a> FusedIterator for PrecedingSiblings<'a> {}
180
181fn next_filtered_sibling<'a>(
182 node: Option<Node<'a>>,
183 filter: &impl Fn(&Node) -> FilterResult,
184) -> Option<Node<'a>> {
185 let mut next = node;
186 let mut consider_children = false;
187 while let Some(current) = next {
188 if let Some(Some(child)) = consider_children.then(|| current.children().next()) {
189 let result = filter(&child);
190 next = Some(child);
191 if result == FilterResult::Include {
192 return next;
193 }
194 } else if let Some(sibling) = current.following_siblings().next() {
195 let result = filter(&sibling);
196 next = Some(sibling);
197 if result == FilterResult::Include {
198 return next;
199 }
200 if result == FilterResult::ExcludeNode {
201 consider_children = true;
202 }
203 } else {
204 let parent = current.parent();
205 next = parent;
206 if let Some(parent) = parent {
207 if filter(&parent) != FilterResult::ExcludeNode {
208 return None;
209 }
210 consider_children = false;
211 } else {
212 return None;
213 }
214 }
215 }
216 None
217}
218
219fn previous_filtered_sibling<'a>(
220 node: Option<Node<'a>>,
221 filter: &impl Fn(&Node) -> FilterResult,
222) -> Option<Node<'a>> {
223 let mut previous = node;
224 let mut consider_children = false;
225 while let Some(current) = previous {
226 if let Some(Some(child)) = consider_children.then(|| current.children().next_back()) {
227 let result = filter(&child);
228 previous = Some(child);
229 if result == FilterResult::Include {
230 return previous;
231 }
232 } else if let Some(sibling) = current.preceding_siblings().next() {
233 let result = filter(&sibling);
234 previous = Some(sibling);
235 if result == FilterResult::Include {
236 return previous;
237 }
238 if result == FilterResult::ExcludeNode {
239 consider_children = true;
240 }
241 } else {
242 let parent = current.parent();
243 previous = parent;
244 if let Some(parent) = parent {
245 if filter(&parent) != FilterResult::ExcludeNode {
246 return None;
247 }
248 consider_children = false;
249 } else {
250 return None;
251 }
252 }
253 }
254 None
255}
256
257/// An iterator that yields following siblings of a node according to the
258/// specified filter.
259///
260/// This struct is created by the [`following_filtered_siblings`](Node::following_filtered_siblings) method on [`Node`].
261pub struct FollowingFilteredSiblings<'a, Filter: Fn(&Node) -> FilterResult> {
262 filter: Filter,
263 back: Option<Node<'a>>,
264 done: bool,
265 front: Option<Node<'a>>,
266}
267
268impl<'a, Filter: Fn(&Node) -> FilterResult> FollowingFilteredSiblings<'a, Filter> {
269 pub(crate) fn new(node: Node<'a>, filter: Filter) -> Self {
270 let front: Option> = next_filtered_sibling(node:Some(node), &filter);
271 let back: Option> = nodeOption>
272 .parent()
273 .and_then(|parent: Node<'_>| parent.last_filtered_child(&filter));
274 Self {
275 filter,
276 back,
277 done: back.is_none() || front.is_none(),
278 front,
279 }
280 }
281}
282
283impl<'a, Filter: Fn(&Node) -> FilterResult> Iterator for FollowingFilteredSiblings<'a, Filter> {
284 type Item = Node<'a>;
285
286 fn next(&mut self) -> Option<Self::Item> {
287 if self.done {
288 None
289 } else {
290 self.done = self.front.as_ref().unwrap().id() == self.back.as_ref().unwrap().id();
291 let current: Option> = self.front;
292 self.front = next_filtered_sibling(self.front, &self.filter);
293 current
294 }
295 }
296}
297
298impl<'a, Filter: Fn(&Node) -> FilterResult> DoubleEndedIterator
299 for FollowingFilteredSiblings<'a, Filter>
300{
301 fn next_back(&mut self) -> Option<Self::Item> {
302 if self.done {
303 None
304 } else {
305 self.done = self.back.as_ref().unwrap().id() == self.front.as_ref().unwrap().id();
306 let current: Option> = self.back;
307 self.back = previous_filtered_sibling(self.back, &self.filter);
308 current
309 }
310 }
311}
312
313impl<'a, Filter: Fn(&Node) -> FilterResult> FusedIterator
314 for FollowingFilteredSiblings<'a, Filter>
315{
316}
317
318/// An iterator that yields preceding siblings of a node according to the
319/// specified filter.
320///
321/// This struct is created by the [`preceding_filtered_siblings`](Node::preceding_filtered_siblings) method on [`Node`].
322pub struct PrecedingFilteredSiblings<'a, Filter: Fn(&Node) -> FilterResult> {
323 filter: Filter,
324 back: Option<Node<'a>>,
325 done: bool,
326 front: Option<Node<'a>>,
327}
328
329impl<'a, Filter: Fn(&Node) -> FilterResult> PrecedingFilteredSiblings<'a, Filter> {
330 pub(crate) fn new(node: Node<'a>, filter: Filter) -> Self {
331 let front: Option> = previous_filtered_sibling(node:Some(node), &filter);
332 let back: Option> = nodeOption>
333 .parent()
334 .and_then(|parent: Node<'_>| parent.first_filtered_child(&filter));
335 Self {
336 filter,
337 back,
338 done: back.is_none() || front.is_none(),
339 front,
340 }
341 }
342}
343
344impl<'a, Filter: Fn(&Node) -> FilterResult> Iterator for PrecedingFilteredSiblings<'a, Filter> {
345 type Item = Node<'a>;
346
347 fn next(&mut self) -> Option<Self::Item> {
348 if self.done {
349 None
350 } else {
351 self.done = self.front.as_ref().unwrap().id() == self.back.as_ref().unwrap().id();
352 let current: Option> = self.front;
353 self.front = previous_filtered_sibling(self.front, &self.filter);
354 current
355 }
356 }
357}
358
359impl<'a, Filter: Fn(&Node) -> FilterResult> DoubleEndedIterator
360 for PrecedingFilteredSiblings<'a, Filter>
361{
362 fn next_back(&mut self) -> Option<Self::Item> {
363 if self.done {
364 None
365 } else {
366 self.done = self.back.as_ref().unwrap().id() == self.front.as_ref().unwrap().id();
367 let current: Option> = self.back;
368 self.back = next_filtered_sibling(self.back, &self.filter);
369 current
370 }
371 }
372}
373
374impl<'a, Filter: Fn(&Node) -> FilterResult> FusedIterator
375 for PrecedingFilteredSiblings<'a, Filter>
376{
377}
378
379/// An iterator that yields children of a node according to the specified
380/// filter.
381///
382/// This struct is created by the [`filtered_children`](Node::filtered_children) method on [`Node`].
383pub struct FilteredChildren<'a, Filter: Fn(&Node) -> FilterResult> {
384 filter: Filter,
385 back: Option<Node<'a>>,
386 done: bool,
387 front: Option<Node<'a>>,
388}
389
390impl<'a, Filter: Fn(&Node) -> FilterResult> FilteredChildren<'a, Filter> {
391 pub(crate) fn new(node: Node<'a>, filter: Filter) -> Self {
392 let front: Option> = node.first_filtered_child(&filter);
393 let back: Option> = node.last_filtered_child(&filter);
394 Self {
395 filter,
396 back,
397 done: back.is_none() || front.is_none(),
398 front,
399 }
400 }
401}
402
403impl<'a, Filter: Fn(&Node) -> FilterResult> Iterator for FilteredChildren<'a, Filter> {
404 type Item = Node<'a>;
405
406 fn next(&mut self) -> Option<Self::Item> {
407 if self.done {
408 None
409 } else {
410 self.done = self.front.as_ref().unwrap().id() == self.back.as_ref().unwrap().id();
411 let current: Option> = self.front;
412 self.front = next_filtered_sibling(self.front, &self.filter);
413 current
414 }
415 }
416}
417
418impl<'a, Filter: Fn(&Node) -> FilterResult> DoubleEndedIterator for FilteredChildren<'a, Filter> {
419 fn next_back(&mut self) -> Option<Self::Item> {
420 if self.done {
421 None
422 } else {
423 self.done = self.back.as_ref().unwrap().id() == self.front.as_ref().unwrap().id();
424 let current: Option> = self.back;
425 self.back = previous_filtered_sibling(self.back, &self.filter);
426 current
427 }
428 }
429}
430
431impl<'a, Filter: Fn(&Node) -> FilterResult> FusedIterator for FilteredChildren<'a, Filter> {}
432
433pub(crate) enum LabelledBy<'a, Filter: Fn(&Node) -> FilterResult> {
434 FromDescendants(FilteredChildren<'a, Filter>),
435 Explicit {
436 ids: std::slice::Iter<'a, NodeId>,
437 tree_state: &'a TreeState,
438 },
439}
440
441impl<'a, Filter: Fn(&Node) -> FilterResult> Iterator for LabelledBy<'a, Filter> {
442 type Item = Node<'a>;
443
444 fn next(&mut self) -> Option<Self::Item> {
445 match self {
446 Self::FromDescendants(iter: &mut FilteredChildren<'_, …>) => iter.next(),
447 Self::Explicit { ids: &mut Iter<'_, NodeId>, tree_state: &mut &State } => {
448 ids.next().map(|id: &NodeId| tree_state.node_by_id(*id).unwrap())
449 }
450 }
451 }
452
453 fn size_hint(&self) -> (usize, Option<usize>) {
454 match self {
455 Self::FromDescendants(iter: &FilteredChildren<'_, Filter>) => iter.size_hint(),
456 Self::Explicit { ids: &Iter<'_, NodeId>, .. } => ids.size_hint(),
457 }
458 }
459}
460
461impl<'a, Filter: Fn(&Node) -> FilterResult> DoubleEndedIterator for LabelledBy<'a, Filter> {
462 fn next_back(&mut self) -> Option<Self::Item> {
463 match self {
464 Self::FromDescendants(iter: &mut FilteredChildren<'_, …>) => iter.next_back(),
465 Self::Explicit { ids: &mut Iter<'_, NodeId>, tree_state: &mut &State } => idsOption<&NodeId>
466 .next_back()
467 .map(|id: &NodeId| tree_state.node_by_id(*id).unwrap()),
468 }
469 }
470}
471
472impl<'a, Filter: Fn(&Node) -> FilterResult> FusedIterator for LabelledBy<'a, Filter> {}
473
474#[cfg(test)]
475mod tests {
476 use crate::tests::*;
477 use accesskit::NodeId;
478
479 #[test]
480 fn following_siblings() {
481 let tree = test_tree();
482 assert!(tree.state().root().following_siblings().next().is_none());
483 assert_eq!(0, tree.state().root().following_siblings().len());
484 assert_eq!(
485 [
486 PARAGRAPH_1_IGNORED_ID,
487 PARAGRAPH_2_ID,
488 PARAGRAPH_3_IGNORED_ID
489 ],
490 tree.state()
491 .node_by_id(PARAGRAPH_0_ID)
492 .unwrap()
493 .following_siblings()
494 .map(|node| node.id())
495 .collect::<Vec<NodeId>>()[..]
496 );
497 assert_eq!(
498 3,
499 tree.state()
500 .node_by_id(PARAGRAPH_0_ID)
501 .unwrap()
502 .following_siblings()
503 .len()
504 );
505 assert!(tree
506 .state()
507 .node_by_id(PARAGRAPH_3_IGNORED_ID)
508 .unwrap()
509 .following_siblings()
510 .next()
511 .is_none());
512 assert_eq!(
513 0,
514 tree.state()
515 .node_by_id(PARAGRAPH_3_IGNORED_ID)
516 .unwrap()
517 .following_siblings()
518 .len()
519 );
520 }
521
522 #[test]
523 fn following_siblings_reversed() {
524 let tree = test_tree();
525 assert!(tree
526 .state()
527 .root()
528 .following_siblings()
529 .next_back()
530 .is_none());
531 assert_eq!(
532 [
533 PARAGRAPH_3_IGNORED_ID,
534 PARAGRAPH_2_ID,
535 PARAGRAPH_1_IGNORED_ID
536 ],
537 tree.state()
538 .node_by_id(PARAGRAPH_0_ID)
539 .unwrap()
540 .following_siblings()
541 .rev()
542 .map(|node| node.id())
543 .collect::<Vec<NodeId>>()[..]
544 );
545 assert!(tree
546 .state()
547 .node_by_id(PARAGRAPH_3_IGNORED_ID)
548 .unwrap()
549 .following_siblings()
550 .next_back()
551 .is_none());
552 }
553
554 #[test]
555 fn preceding_siblings() {
556 let tree = test_tree();
557 assert!(tree.state().root().preceding_siblings().next().is_none());
558 assert_eq!(0, tree.state().root().preceding_siblings().len());
559 assert_eq!(
560 [PARAGRAPH_2_ID, PARAGRAPH_1_IGNORED_ID, PARAGRAPH_0_ID],
561 tree.state()
562 .node_by_id(PARAGRAPH_3_IGNORED_ID)
563 .unwrap()
564 .preceding_siblings()
565 .map(|node| node.id())
566 .collect::<Vec<NodeId>>()[..]
567 );
568 assert_eq!(
569 3,
570 tree.state()
571 .node_by_id(PARAGRAPH_3_IGNORED_ID)
572 .unwrap()
573 .preceding_siblings()
574 .len()
575 );
576 assert!(tree
577 .state()
578 .node_by_id(PARAGRAPH_0_ID)
579 .unwrap()
580 .preceding_siblings()
581 .next()
582 .is_none());
583 assert_eq!(
584 0,
585 tree.state()
586 .node_by_id(PARAGRAPH_0_ID)
587 .unwrap()
588 .preceding_siblings()
589 .len()
590 );
591 }
592
593 #[test]
594 fn preceding_siblings_reversed() {
595 let tree = test_tree();
596 assert!(tree
597 .state()
598 .root()
599 .preceding_siblings()
600 .next_back()
601 .is_none());
602 assert_eq!(
603 [PARAGRAPH_0_ID, PARAGRAPH_1_IGNORED_ID, PARAGRAPH_2_ID],
604 tree.state()
605 .node_by_id(PARAGRAPH_3_IGNORED_ID)
606 .unwrap()
607 .preceding_siblings()
608 .rev()
609 .map(|node| node.id())
610 .collect::<Vec<NodeId>>()[..]
611 );
612 assert!(tree
613 .state()
614 .node_by_id(PARAGRAPH_0_ID)
615 .unwrap()
616 .preceding_siblings()
617 .next_back()
618 .is_none());
619 }
620
621 #[test]
622 fn following_filtered_siblings() {
623 let tree = test_tree();
624 assert!(tree
625 .state()
626 .root()
627 .following_filtered_siblings(test_tree_filter)
628 .next()
629 .is_none());
630 assert_eq!(
631 [
632 STATIC_TEXT_1_0_ID,
633 PARAGRAPH_2_ID,
634 STATIC_TEXT_3_1_0_ID,
635 BUTTON_3_2_ID
636 ],
637 tree.state()
638 .node_by_id(PARAGRAPH_0_ID)
639 .unwrap()
640 .following_filtered_siblings(test_tree_filter)
641 .map(|node| node.id())
642 .collect::<Vec<NodeId>>()[..]
643 );
644 assert!(tree
645 .state()
646 .node_by_id(PARAGRAPH_3_IGNORED_ID)
647 .unwrap()
648 .following_filtered_siblings(test_tree_filter)
649 .next()
650 .is_none());
651 }
652
653 #[test]
654 fn following_filtered_siblings_reversed() {
655 let tree = test_tree();
656 assert!(tree
657 .state()
658 .root()
659 .following_filtered_siblings(test_tree_filter)
660 .next_back()
661 .is_none());
662 assert_eq!(
663 [
664 BUTTON_3_2_ID,
665 STATIC_TEXT_3_1_0_ID,
666 PARAGRAPH_2_ID,
667 STATIC_TEXT_1_0_ID
668 ],
669 tree.state()
670 .node_by_id(PARAGRAPH_0_ID)
671 .unwrap()
672 .following_filtered_siblings(test_tree_filter)
673 .rev()
674 .map(|node| node.id())
675 .collect::<Vec<NodeId>>()[..]
676 );
677 assert!(tree
678 .state()
679 .node_by_id(PARAGRAPH_3_IGNORED_ID)
680 .unwrap()
681 .following_filtered_siblings(test_tree_filter)
682 .next_back()
683 .is_none());
684 }
685
686 #[test]
687 fn preceding_filtered_siblings() {
688 let tree = test_tree();
689 assert!(tree
690 .state()
691 .root()
692 .preceding_filtered_siblings(test_tree_filter)
693 .next()
694 .is_none());
695 assert_eq!(
696 [PARAGRAPH_2_ID, STATIC_TEXT_1_0_ID, PARAGRAPH_0_ID],
697 tree.state()
698 .node_by_id(PARAGRAPH_3_IGNORED_ID)
699 .unwrap()
700 .preceding_filtered_siblings(test_tree_filter)
701 .map(|node| node.id())
702 .collect::<Vec<NodeId>>()[..]
703 );
704 assert!(tree
705 .state()
706 .node_by_id(PARAGRAPH_0_ID)
707 .unwrap()
708 .preceding_filtered_siblings(test_tree_filter)
709 .next()
710 .is_none());
711 }
712
713 #[test]
714 fn preceding_filtered_siblings_reversed() {
715 let tree = test_tree();
716 assert!(tree
717 .state()
718 .root()
719 .preceding_filtered_siblings(test_tree_filter)
720 .next_back()
721 .is_none());
722 assert_eq!(
723 [PARAGRAPH_0_ID, STATIC_TEXT_1_0_ID, PARAGRAPH_2_ID],
724 tree.state()
725 .node_by_id(PARAGRAPH_3_IGNORED_ID)
726 .unwrap()
727 .preceding_filtered_siblings(test_tree_filter)
728 .rev()
729 .map(|node| node.id())
730 .collect::<Vec<NodeId>>()[..]
731 );
732 assert!(tree
733 .state()
734 .node_by_id(PARAGRAPH_0_ID)
735 .unwrap()
736 .preceding_filtered_siblings(test_tree_filter)
737 .next_back()
738 .is_none());
739 }
740
741 #[test]
742 fn filtered_children() {
743 let tree = test_tree();
744 assert_eq!(
745 [
746 PARAGRAPH_0_ID,
747 STATIC_TEXT_1_0_ID,
748 PARAGRAPH_2_ID,
749 STATIC_TEXT_3_1_0_ID,
750 BUTTON_3_2_ID
751 ],
752 tree.state()
753 .root()
754 .filtered_children(test_tree_filter)
755 .map(|node| node.id())
756 .collect::<Vec<NodeId>>()[..]
757 );
758 assert!(tree
759 .state()
760 .node_by_id(PARAGRAPH_0_ID)
761 .unwrap()
762 .filtered_children(test_tree_filter)
763 .next()
764 .is_none());
765 assert!(tree
766 .state()
767 .node_by_id(STATIC_TEXT_0_0_IGNORED_ID)
768 .unwrap()
769 .filtered_children(test_tree_filter)
770 .next()
771 .is_none());
772 }
773
774 #[test]
775 fn filtered_children_reversed() {
776 let tree = test_tree();
777 assert_eq!(
778 [
779 BUTTON_3_2_ID,
780 STATIC_TEXT_3_1_0_ID,
781 PARAGRAPH_2_ID,
782 STATIC_TEXT_1_0_ID,
783 PARAGRAPH_0_ID
784 ],
785 tree.state()
786 .root()
787 .filtered_children(test_tree_filter)
788 .rev()
789 .map(|node| node.id())
790 .collect::<Vec<NodeId>>()[..]
791 );
792 assert!(tree
793 .state()
794 .node_by_id(PARAGRAPH_0_ID)
795 .unwrap()
796 .filtered_children(test_tree_filter)
797 .next_back()
798 .is_none());
799 assert!(tree
800 .state()
801 .node_by_id(STATIC_TEXT_0_0_IGNORED_ID)
802 .unwrap()
803 .filtered_children(test_tree_filter)
804 .next_back()
805 .is_none());
806 }
807}
808