1 // pest. The Elegant Parser
2 // Copyright (c) 2018 Dragoș Tiselice
3 //
4 // Licensed under the Apache License, Version 2.0
5 // <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
6 // license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7 // option. All files in the project carrying such notice may not be copied,
8 // modified, or distributed except according to those terms.
9 
10 use alloc::format;
11 use alloc::rc::Rc;
12 use alloc::string::String;
13 use alloc::vec::Vec;
14 use core::fmt;
15 use core::hash::{Hash, Hasher};
16 use core::iter::Filter;
17 use core::ptr;
18 use core::str;
19 
20 #[cfg(feature = "pretty-print")]
21 use serde::ser::SerializeStruct;
22 
23 use super::flat_pairs::{self, FlatPairs};
24 use super::line_index::LineIndex;
25 use super::pair::{self, Pair};
26 use super::queueable_token::QueueableToken;
27 use super::tokens::{self, Tokens};
28 use crate::RuleType;
29 
30 /// An iterator over [`Pair`]s. It is created by [`pest::state`] and [`Pair::into_inner`].
31 ///
32 /// [`Pair`]: struct.Pair.html
33 /// [`pest::state`]: ../fn.state.html
34 /// [`Pair::into_inner`]: struct.Pair.html#method.into_inner
35 #[derive(Clone)]
36 pub struct Pairs<'i, R> {
37     queue: Rc<Vec<QueueableToken<'i, R>>>,
38     input: &'i str,
39     start: usize,
40     end: usize,
41     pairs_count: usize,
42     line_index: Rc<LineIndex>,
43 }
44 
new<'i, R: RuleType>( queue: Rc<Vec<QueueableToken<'i, R>>>, input: &'i str, line_index: Option<Rc<LineIndex>>, start: usize, end: usize, ) -> Pairs<'i, R>45 pub fn new<'i, R: RuleType>(
46     queue: Rc<Vec<QueueableToken<'i, R>>>,
47     input: &'i str,
48     line_index: Option<Rc<LineIndex>>,
49     start: usize,
50     end: usize,
51 ) -> Pairs<'i, R> {
52     let line_index = match line_index {
53         Some(line_index) => line_index,
54         None => Rc::new(LineIndex::new(input)),
55     };
56 
57     let mut pairs_count = 0;
58     let mut cursor = start;
59     while cursor < end {
60         cursor = match queue[cursor] {
61             QueueableToken::Start {
62                 end_token_index, ..
63             } => end_token_index,
64             _ => unreachable!(),
65         } + 1;
66         pairs_count += 1;
67     }
68 
69     Pairs {
70         queue,
71         input,
72         start,
73         end,
74         pairs_count,
75         line_index,
76     }
77 }
78 
79 impl<'i, R: RuleType> Pairs<'i, R> {
80     /// Captures a slice from the `&str` defined by the starting position of the first token `Pair`
81     /// and the ending position of the last token `Pair` of the `Pairs`. This also captures
82     /// the input between those two token `Pair`s.
83     ///
84     /// # Examples
85     ///
86     /// ```
87     /// # use std::rc::Rc;
88     /// # use pest;
89     /// # #[allow(non_camel_case_types)]
90     /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
91     /// enum Rule {
92     ///     a,
93     ///     b
94     /// }
95     ///
96     /// let input = "a b";
97     /// let pairs = pest::state(input, |state| {
98     ///     // generating Token pairs with Rule::a and Rule::b ...
99     /// #     state.rule(Rule::a, |s| s.match_string("a")).and_then(|s| s.skip(1))
100     /// #         .and_then(|s| s.rule(Rule::b, |s| s.match_string("b")))
101     /// }).unwrap();
102     ///
103     /// assert_eq!(pairs.as_str(), "a b");
104     /// ```
105     #[inline]
as_str(&self) -> &'i str106     pub fn as_str(&self) -> &'i str {
107         if self.start < self.end {
108             let start = self.pos(self.start);
109             let end = self.pos(self.end - 1);
110             // Generated positions always come from Positions and are UTF-8 borders.
111             &self.input[start..end]
112         } else {
113             ""
114         }
115     }
116 
117     /// Returns the input string of `Pairs`.
118     ///
119     /// This function returns the input string of `Pairs` as a `&str`. This is the source string
120     /// from which `Pairs` was created. The returned `&str` can be used to examine the contents of
121     /// `Pairs` or to perform further processing on the string.
122     ///
123     /// # Examples
124     ///
125     /// ```
126     /// # use std::rc::Rc;
127     /// # use pest;
128     /// # #[allow(non_camel_case_types)]
129     /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
130     /// enum Rule {
131     ///     a,
132     ///     b
133     /// }
134     ///
135     /// // Example: Get input string from Pairs
136     ///
137     /// let input = "a b";
138     /// let pairs = pest::state(input, |state| {
139     ///     // generating Token pairs with Rule::a and Rule::b ...
140     /// #     state.rule(Rule::a, |s| s.match_string("a")).and_then(|s| s.skip(1))
141     /// #         .and_then(|s| s.rule(Rule::b, |s| s.match_string("b")))
142     /// }).unwrap();
143     ///
144     /// assert_eq!(pairs.as_str(), "a b");
145     /// assert_eq!(input, pairs.get_input());
146     /// ```
get_input(&self) -> &'i str147     pub fn get_input(&self) -> &'i str {
148         self.input
149     }
150 
151     /// Captures inner token `Pair`s and concatenates resulting `&str`s. This does not capture
152     /// the input between token `Pair`s.
153     ///
154     /// # Examples
155     ///
156     /// ```
157     /// # use std::rc::Rc;
158     /// # use pest;
159     /// # #[allow(non_camel_case_types)]
160     /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
161     /// enum Rule {
162     ///     a,
163     ///     b
164     /// }
165     ///
166     /// let input = "a b";
167     /// let pairs = pest::state(input, |state| {
168     ///     // generating Token pairs with Rule::a and Rule::b ...
169     /// #     state.rule(Rule::a, |s| s.match_string("a")).and_then(|s| s.skip(1))
170     /// #         .and_then(|s| s.rule(Rule::b, |s| s.match_string("b")))
171     /// }).unwrap();
172     ///
173     /// assert_eq!(pairs.concat(), "ab");
174     /// ```
175     #[inline]
concat(&self) -> String176     pub fn concat(&self) -> String {
177         self.clone()
178             .fold(String::new(), |string, pair| string + pair.as_str())
179     }
180 
181     /// Flattens the `Pairs`.
182     ///
183     /// # Examples
184     ///
185     /// ```
186     /// # use std::rc::Rc;
187     /// # use pest;
188     /// # #[allow(non_camel_case_types)]
189     /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
190     /// enum Rule {
191     ///     a,
192     ///     b
193     /// }
194     ///
195     /// let input = "";
196     /// let pairs = pest::state(input, |state| {
197     ///     // generating nested Token pair with Rule::b inside Rule::a
198     /// #     state.rule(Rule::a, |state| {
199     /// #         state.rule(Rule::b, |s| Ok(s))
200     /// #     })
201     /// }).unwrap();
202     /// let tokens: Vec<_> = pairs.flatten().tokens().collect();
203     ///
204     /// assert_eq!(tokens.len(), 4);
205     /// ```
206     #[inline]
flatten(self) -> FlatPairs<'i, R>207     pub fn flatten(self) -> FlatPairs<'i, R> {
208         unsafe { flat_pairs::new(self.queue, self.input, self.start, self.end) }
209     }
210 
211     /// Finds the first pair that has its node or branch tagged with the provided
212     /// label. Searches in the flattened [`Pairs`] iterator.
213     ///
214     /// # Examples
215     ///
216     /// Try to recognize the branch between add and mul
217     /// ```
218     /// use pest::{state, ParseResult, ParserState};
219     /// #[allow(non_camel_case_types)]
220     /// #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
221     /// enum Rule {
222     ///     number, // 0..9
223     ///     add,    // num + num
224     ///     mul,    // num * num
225     /// }
226     /// fn mark_branch(
227     ///     state: Box<ParserState<'_, Rule>>,
228     /// ) -> ParseResult<Box<ParserState<'_, Rule>>> {
229     ///     expr(state, Rule::mul, "*")
230     ///         .and_then(|state| state.tag_node("mul"))
231     ///         .or_else(|state| expr(state, Rule::add, "+"))
232     ///         .and_then(|state| state.tag_node("add"))
233     /// }
234     /// fn expr<'a>(
235     ///     state: Box<ParserState<'a, Rule>>,
236     ///     r: Rule,
237     ///     o: &'static str,
238     /// ) -> ParseResult<Box<ParserState<'a, Rule>>> {
239     ///     state.rule(r, |state| {
240     ///         state.sequence(|state| {
241     ///             number(state)
242     ///                 .and_then(|state| state.tag_node("lhs"))
243     ///                 .and_then(|state| state.match_string(o))
244     ///                 .and_then(number)
245     ///                 .and_then(|state| state.tag_node("rhs"))
246     ///         })
247     ///     })
248     /// }
249     /// fn number(state: Box<ParserState<'_, Rule>>) -> ParseResult<Box<ParserState<'_, Rule>>> {
250     ///     state.rule(Rule::number, |state| state.match_range('0'..'9'))
251     /// }
252     /// let input = "1+2";
253     /// let pairs = state(input, mark_branch).unwrap();
254     /// assert_eq!(pairs.find_first_tagged("add").unwrap().as_rule(), Rule::add);
255     /// assert_eq!(pairs.find_first_tagged("mul"), None);
256     /// ```
257     #[inline]
find_first_tagged(&self, tag: &'i str) -> Option<Pair<'i, R>>258     pub fn find_first_tagged(&self, tag: &'i str) -> Option<Pair<'i, R>> {
259         self.clone().find_tagged(tag).next()
260     }
261 
262     /// Returns the iterator over pairs that have their node or branch tagged
263     /// with the provided label. The iterator is built from a flattened [`Pairs`] iterator.
264     ///
265     /// # Examples
266     ///
267     /// Try to recognize the node between left and right hand side
268     /// ```
269     /// use pest::{state, ParseResult, ParserState};
270     /// #[allow(non_camel_case_types)]
271     /// #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
272     /// enum Rule {
273     ///     number, // 0..9
274     ///     add,    // num + num
275     ///     mul,    // num * num
276     /// }
277     /// fn mark_branch(
278     ///     state: Box<ParserState<'_, Rule>>,
279     /// ) -> ParseResult<Box<ParserState<'_, Rule>>> {
280     ///     expr(state, Rule::mul, "*")
281     ///         .and_then(|state| state.tag_node("mul"))
282     ///         .or_else(|state| expr(state, Rule::add, "+"))
283     ///         .and_then(|state| state.tag_node("add"))
284     /// }
285     /// fn expr<'a>(
286     ///     state: Box<ParserState<'a, Rule>>,
287     ///     r: Rule,
288     ///     o: &'static str,
289     /// ) -> ParseResult<Box<ParserState<'a, Rule>>> {
290     ///     state.rule(r, |state| {
291     ///         state.sequence(|state| {
292     ///             number(state)
293     ///                 .and_then(|state| state.tag_node("lhs"))
294     ///                 .and_then(|state| state.match_string(o))
295     ///                 .and_then(number)
296     ///                 .and_then(|state| state.tag_node("rhs"))
297     ///         })
298     ///     })
299     /// }
300     /// fn number(state: Box<ParserState<'_, Rule>>) -> ParseResult<Box<ParserState<'_, Rule>>> {
301     ///     state.rule(Rule::number, |state| state.match_range('0'..'9'))
302     /// }
303     ///
304     /// let input = "1+2";
305     /// let pairs = state(input, mark_branch).unwrap();
306     /// let mut left_numbers = pairs.find_tagged("lhs");
307     /// assert_eq!(left_numbers.next().unwrap().as_str(), "1");
308     /// assert_eq!(left_numbers.next(), None);
309     /// ```
310     #[inline]
find_tagged( self, tag: &'i str, ) -> Filter<FlatPairs<'i, R>, impl FnMut(&Pair<'i, R>) -> bool + '_>311     pub fn find_tagged(
312         self,
313         tag: &'i str,
314     ) -> Filter<FlatPairs<'i, R>, impl FnMut(&Pair<'i, R>) -> bool + '_> {
315         self.flatten()
316             .filter(move |pair: &Pair<'i, R>| matches!(pair.as_node_tag(), Some(nt) if nt == tag))
317     }
318 
319     /// Returns the `Tokens` for the `Pairs`.
320     ///
321     /// # Examples
322     ///
323     /// ```
324     /// # use std::rc::Rc;
325     /// # use pest;
326     /// # #[allow(non_camel_case_types)]
327     /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
328     /// enum Rule {
329     ///     a
330     /// }
331     ///
332     /// let input = "";
333     /// let pairs = pest::state(input, |state| {
334     ///     // generating Token pair with Rule::a ...
335     /// #     state.rule(Rule::a, |s| Ok(s))
336     /// }).unwrap();
337     /// let tokens: Vec<_> = pairs.tokens().collect();
338     ///
339     /// assert_eq!(tokens.len(), 2);
340     /// ```
341     #[inline]
tokens(self) -> Tokens<'i, R>342     pub fn tokens(self) -> Tokens<'i, R> {
343         tokens::new(self.queue, self.input, self.start, self.end)
344     }
345 
346     /// Peek at the first inner `Pair` without changing the position of this iterator.
347     #[inline]
peek(&self) -> Option<Pair<'i, R>>348     pub fn peek(&self) -> Option<Pair<'i, R>> {
349         if self.start < self.end {
350             Some(unsafe {
351                 pair::new(
352                     Rc::clone(&self.queue),
353                     self.input,
354                     Rc::clone(&self.line_index),
355                     self.start,
356                 )
357             })
358         } else {
359             None
360         }
361     }
362 
363     /// Generates a string that stores the lexical information of `self` in
364     /// a pretty-printed JSON format.
365     #[cfg(feature = "pretty-print")]
to_json(&self) -> String366     pub fn to_json(&self) -> String {
367         ::serde_json::to_string_pretty(self).expect("Failed to pretty-print Pairs to json.")
368     }
369 
pair(&self) -> usize370     fn pair(&self) -> usize {
371         match self.queue[self.start] {
372             QueueableToken::Start {
373                 end_token_index, ..
374             } => end_token_index,
375             _ => unreachable!(),
376         }
377     }
378 
pair_from_end(&self) -> usize379     fn pair_from_end(&self) -> usize {
380         match self.queue[self.end - 1] {
381             QueueableToken::End {
382                 start_token_index, ..
383             } => start_token_index,
384             _ => unreachable!(),
385         }
386     }
387 
pos(&self, index: usize) -> usize388     fn pos(&self, index: usize) -> usize {
389         match self.queue[index] {
390             QueueableToken::Start { input_pos, .. } | QueueableToken::End { input_pos, .. } => {
391                 input_pos
392             }
393         }
394     }
395 }
396 
397 impl<'i, R: RuleType> ExactSizeIterator for Pairs<'i, R> {
398     #[inline]
len(&self) -> usize399     fn len(&self) -> usize {
400         self.pairs_count
401     }
402 }
403 
404 impl<'i, R: RuleType> Iterator for Pairs<'i, R> {
405     type Item = Pair<'i, R>;
406 
next(&mut self) -> Option<Self::Item>407     fn next(&mut self) -> Option<Self::Item> {
408         let pair = self.peek()?;
409 
410         self.start = self.pair() + 1;
411         self.pairs_count -= 1;
412         Some(pair)
413     }
414 
size_hint(&self) -> (usize, Option<usize>)415     fn size_hint(&self) -> (usize, Option<usize>) {
416         let len = <Self as ExactSizeIterator>::len(self);
417         (len, Some(len))
418     }
419 }
420 
421 impl<'i, R: RuleType> DoubleEndedIterator for Pairs<'i, R> {
next_back(&mut self) -> Option<Self::Item>422     fn next_back(&mut self) -> Option<Self::Item> {
423         if self.end <= self.start {
424             return None;
425         }
426 
427         self.end = self.pair_from_end();
428         self.pairs_count -= 1;
429 
430         let pair = unsafe {
431             pair::new(
432                 Rc::clone(&self.queue),
433                 self.input,
434                 Rc::clone(&self.line_index),
435                 self.end,
436             )
437         };
438 
439         Some(pair)
440     }
441 }
442 
443 impl<'i, R: RuleType> fmt::Debug for Pairs<'i, R> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result444     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
445         f.debug_list().entries(self.clone()).finish()
446     }
447 }
448 
449 impl<'i, R: RuleType> fmt::Display for Pairs<'i, R> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result450     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
451         write!(
452             f,
453             "[{}]",
454             self.clone()
455                 .map(|pair| format!("{}", pair))
456                 .collect::<Vec<_>>()
457                 .join(", ")
458         )
459     }
460 }
461 
462 impl<'i, R: PartialEq> PartialEq for Pairs<'i, R> {
eq(&self, other: &Pairs<'i, R>) -> bool463     fn eq(&self, other: &Pairs<'i, R>) -> bool {
464         Rc::ptr_eq(&self.queue, &other.queue)
465             && ptr::eq(self.input, other.input)
466             && self.start == other.start
467             && self.end == other.end
468     }
469 }
470 
471 impl<'i, R: Eq> Eq for Pairs<'i, R> {}
472 
473 impl<'i, R: Hash> Hash for Pairs<'i, R> {
hash<H: Hasher>(&self, state: &mut H)474     fn hash<H: Hasher>(&self, state: &mut H) {
475         (&*self.queue as *const Vec<QueueableToken<'i, R>>).hash(state);
476         (self.input as *const str).hash(state);
477         self.start.hash(state);
478         self.end.hash(state);
479     }
480 }
481 
482 #[cfg(feature = "pretty-print")]
483 impl<'i, R: RuleType> ::serde::Serialize for Pairs<'i, R> {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: ::serde::Serializer,484     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
485     where
486         S: ::serde::Serializer,
487     {
488         let start = self.pos(self.start);
489         let end = self.pos(self.end - 1);
490         let pairs = self.clone().collect::<Vec<_>>();
491 
492         let mut ser = serializer.serialize_struct("Pairs", 2)?;
493         ser.serialize_field("pos", &(start, end))?;
494         ser.serialize_field("pairs", &pairs)?;
495         ser.end()
496     }
497 }
498 
499 #[cfg(test)]
500 mod tests {
501     use super::super::super::macros::tests::*;
502     use super::super::super::Parser;
503     use alloc::borrow::ToOwned;
504     use alloc::boxed::Box;
505     use alloc::format;
506     use alloc::vec;
507     use alloc::vec::Vec;
508 
509     #[test]
510     #[cfg(feature = "pretty-print")]
test_pretty_print()511     fn test_pretty_print() {
512         let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();
513 
514         let expected = r#"{
515   "pos": [
516     0,
517     5
518   ],
519   "pairs": [
520     {
521       "pos": [
522         0,
523         3
524       ],
525       "rule": "a",
526       "inner": {
527         "pos": [
528           1,
529           2
530         ],
531         "pairs": [
532           {
533             "pos": [
534               1,
535               2
536             ],
537             "rule": "b",
538             "inner": "b"
539           }
540         ]
541       }
542     },
543     {
544       "pos": [
545         4,
546         5
547       ],
548       "rule": "c",
549       "inner": "e"
550     }
551   ]
552 }"#;
553 
554         assert_eq!(expected, pairs.to_json());
555     }
556 
557     #[test]
as_str()558     fn as_str() {
559         let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();
560 
561         assert_eq!(pairs.as_str(), "abcde");
562     }
563 
564     #[test]
get_input_of_pairs()565     fn get_input_of_pairs() {
566         let input = "abcde";
567         let pairs = AbcParser::parse(Rule::a, input).unwrap();
568 
569         assert_eq!(pairs.get_input(), input);
570     }
571 
572     #[test]
as_str_empty()573     fn as_str_empty() {
574         let mut pairs = AbcParser::parse(Rule::a, "abcde").unwrap();
575 
576         assert_eq!(pairs.nth(1).unwrap().into_inner().as_str(), "");
577     }
578 
579     #[test]
concat()580     fn concat() {
581         let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();
582 
583         assert_eq!(pairs.concat(), "abce");
584     }
585 
586     #[test]
pairs_debug()587     fn pairs_debug() {
588         let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();
589 
590         #[rustfmt::skip]
591         assert_eq!(
592             format!("{:?}", pairs),
593             "[\
594                 Pair { rule: a, span: Span { str: \"abc\", start: 0, end: 3 }, inner: [\
595                     Pair { rule: b, span: Span { str: \"b\", start: 1, end: 2 }, inner: [] }\
596                 ] }, \
597                 Pair { rule: c, span: Span { str: \"e\", start: 4, end: 5 }, inner: [] }\
598             ]"
599             .to_owned()
600         );
601     }
602 
603     #[test]
pairs_display()604     fn pairs_display() {
605         let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();
606 
607         assert_eq!(
608             format!("{}", pairs),
609             "[a(0, 3, [b(1, 2)]), c(4, 5)]".to_owned()
610         );
611     }
612 
613     #[test]
iter_for_pairs()614     fn iter_for_pairs() {
615         let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();
616         assert_eq!(
617             pairs.map(|p| p.as_rule()).collect::<Vec<Rule>>(),
618             vec![Rule::a, Rule::c]
619         );
620     }
621 
622     #[test]
double_ended_iter_for_pairs()623     fn double_ended_iter_for_pairs() {
624         let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();
625         assert_eq!(
626             pairs.rev().map(|p| p.as_rule()).collect::<Vec<Rule>>(),
627             vec![Rule::c, Rule::a]
628         );
629     }
630 
631     #[test]
test_line_col()632     fn test_line_col() {
633         let mut pairs = AbcParser::parse(Rule::a, "abc\nefgh").unwrap();
634         let pair = pairs.next().unwrap();
635         assert_eq!(pair.as_str(), "abc");
636         assert_eq!(pair.line_col(), (1, 1));
637 
638         let pair = pairs.next().unwrap();
639         assert_eq!(pair.as_str(), "e");
640         assert_eq!(pair.line_col(), (2, 1));
641 
642         let pair = pairs.next().unwrap();
643         assert_eq!(pair.as_str(), "fgh");
644         assert_eq!(pair.line_col(), (2, 2));
645     }
646 
647     #[test]
test_rev_iter_line_col()648     fn test_rev_iter_line_col() {
649         let mut pairs = AbcParser::parse(Rule::a, "abc\nefgh").unwrap().rev();
650         let pair = pairs.next().unwrap();
651         assert_eq!(pair.as_str(), "fgh");
652         assert_eq!(pair.line_col(), (2, 2));
653 
654         let pair = pairs.next().unwrap();
655         assert_eq!(pair.as_str(), "e");
656         assert_eq!(pair.line_col(), (2, 1));
657 
658         let pair = pairs.next().unwrap();
659         assert_eq!(pair.as_str(), "abc");
660         assert_eq!(pair.line_col(), (1, 1));
661     }
662 
663     #[test]
664     // false positive: pest uses `..` as a complete range (historically)
665     #[allow(clippy::almost_complete_range)]
test_tag_node_branch()666     fn test_tag_node_branch() {
667         use crate::{state, ParseResult, ParserState};
668         #[allow(non_camel_case_types)]
669         #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
670         enum Rule {
671             number, // 0..9
672             add,    // num + num
673             mul,    // num * num
674         }
675         fn mark_branch(
676             state: Box<ParserState<'_, Rule>>,
677         ) -> ParseResult<Box<ParserState<'_, Rule>>> {
678             expr(state, Rule::mul, "*")
679                 .and_then(|state| state.tag_node("mul"))
680                 .or_else(|state| expr(state, Rule::add, "+"))
681                 .and_then(|state| state.tag_node("add"))
682         }
683         fn expr<'a>(
684             state: Box<ParserState<'a, Rule>>,
685             r: Rule,
686             o: &'static str,
687         ) -> ParseResult<Box<ParserState<'a, Rule>>> {
688             state.rule(r, |state| {
689                 state.sequence(|state| {
690                     number(state)
691                         .and_then(|state| state.tag_node("lhs"))
692                         .and_then(|state| state.match_string(o))
693                         .and_then(number)
694                         .and_then(|state| state.tag_node("rhs"))
695                 })
696             })
697         }
698         fn number(state: Box<ParserState<'_, Rule>>) -> ParseResult<Box<ParserState<'_, Rule>>> {
699             state.rule(Rule::number, |state| state.match_range('0'..'9'))
700         }
701         let input = "1+2";
702         let pairs = state(input, mark_branch).unwrap();
703         assert_eq!(pairs.find_first_tagged("add").unwrap().as_rule(), Rule::add);
704         assert_eq!(pairs.find_first_tagged("mul"), None);
705 
706         let mut left_numbers = pairs.clone().find_tagged("lhs");
707 
708         assert_eq!(left_numbers.next().unwrap().as_str(), "1");
709         assert_eq!(left_numbers.next(), None);
710         let mut right_numbers = pairs.find_tagged("rhs");
711 
712         assert_eq!(right_numbers.next().unwrap().as_str(), "2");
713         assert_eq!(right_numbers.next(), None);
714     }
715 
716     #[test]
exact_size_iter_for_pairs()717     fn exact_size_iter_for_pairs() {
718         let pairs = AbcParser::parse(Rule::a, "abc\nefgh").unwrap();
719         assert_eq!(pairs.len(), pairs.count());
720 
721         let pairs = AbcParser::parse(Rule::a, "abc\nefgh").unwrap().rev();
722         assert_eq!(pairs.len(), pairs.count());
723 
724         let mut pairs = AbcParser::parse(Rule::a, "abc\nefgh").unwrap();
725         let pairs_len = pairs.len();
726         let _ = pairs.next().unwrap();
727         assert_eq!(pairs.count() + 1, pairs_len);
728     }
729 }
730