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 | |
11 | use std::iter::FusedIterator; |
12 | |
13 | use accesskit::NodeId; |
14 | |
15 | use 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`]. |
20 | pub struct FollowingSiblings<'a> { |
21 | back_position: usize, |
22 | done: bool, |
23 | front_position: usize, |
24 | parent: Option<Node<'a>>, |
25 | } |
26 | |
27 | impl<'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 | |
51 | impl<'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 | |
79 | impl<'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 | |
97 | impl<'a> ExactSizeIterator for FollowingSiblings<'a> {} |
98 | |
99 | impl<'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`]. |
104 | pub struct PrecedingSiblings<'a> { |
105 | back_position: usize, |
106 | done: bool, |
107 | front_position: usize, |
108 | parent: Option<Node<'a>>, |
109 | } |
110 | |
111 | impl<'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 | |
129 | impl<'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 | |
159 | impl<'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 | |
177 | impl<'a> ExactSizeIterator for PrecedingSiblings<'a> {} |
178 | |
179 | impl<'a> FusedIterator for PrecedingSiblings<'a> {} |
180 | |
181 | fn 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 | |
219 | fn 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`]. |
261 | pub 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 | |
268 | impl<'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 | |
283 | impl<'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 | |
298 | impl<'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 | |
313 | impl<'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`]. |
322 | pub 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 | |
329 | impl<'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 | |
344 | impl<'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 | |
359 | impl<'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 | |
374 | impl<'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`]. |
383 | pub 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 | |
390 | impl<'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 | |
403 | impl<'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 | |
418 | impl<'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 | |
431 | impl<'a, Filter: Fn(&Node) -> FilterResult> FusedIterator for FilteredChildren<'a, Filter> {} |
432 | |
433 | pub(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 | |
441 | impl<'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 | |
461 | impl<'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 | |
472 | impl<'a, Filter: Fn(&Node) -> FilterResult> FusedIterator for LabelledBy<'a, Filter> {} |
473 | |
474 | #[cfg (test)] |
475 | mod 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 | |