pest/iterators/
flat_pairs.rs

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
10use alloc::rc::Rc;
11use alloc::vec::Vec;
12use core::fmt;
13
14use super::line_index::LineIndex;
15use super::pair::{self, Pair};
16use super::queueable_token::QueueableToken;
17use super::tokens::{self, Tokens};
18use crate::RuleType;
19
20/// An iterator over [`Pair`]s. It is created by [`Pairs::flatten`].
21///
22/// [`Pair`]: struct.Pair.html
23/// [`Pairs::flatten`]: struct.Pairs.html#method.flatten
24pub struct FlatPairs<'i, R> {
25    /// # Safety
26    ///
27    /// All `QueueableToken`s' `input_pos` must be valid character boundary indices into `input`.
28    queue: Rc<Vec<QueueableToken<'i, R>>>,
29    input: &'i str,
30    start: usize,
31    end: usize,
32    line_index: Rc<LineIndex>,
33}
34
35/// # Safety
36///
37/// All `QueueableToken`s' `input_pos` must be valid character boundary indices into `input`.
38pub unsafe fn new<'i, R: RuleType>(
39    queue: Rc<Vec<QueueableToken<'i, R>>>,
40    input: &'i str,
41    start: usize,
42    end: usize,
43) -> FlatPairs<'i, R> {
44    FlatPairs {
45        queue,
46        input,
47        line_index: Rc::new(LineIndex::new(input)),
48        start,
49        end,
50    }
51}
52
53impl<'i, R: RuleType> FlatPairs<'i, R> {
54    /// Returns the `Tokens` for these pairs.
55    ///
56    /// # Examples
57    ///
58    /// ```
59    /// # use std::rc::Rc;
60    /// # use pest;
61    /// # #[allow(non_camel_case_types)]
62    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
63    /// enum Rule {
64    ///     a
65    /// }
66    ///
67    /// let input = "";
68    /// let pairs = pest::state(input, |state| {
69    ///     // generating Token pair with Rule::a ...
70    /// #     state.rule(Rule::a, |s| Ok(s))
71    /// }).unwrap();
72    /// let tokens: Vec<_> = pairs.flatten().tokens().collect();
73    ///
74    /// assert_eq!(tokens.len(), 2);
75    /// ```
76    #[inline]
77    pub fn tokens(self) -> Tokens<'i, R> {
78        tokens::new(self.queue, self.input, self.start, self.end)
79    }
80
81    fn next_start(&mut self) {
82        self.start += 1;
83
84        while self.start < self.end && !self.is_start(self.start) {
85            self.start += 1;
86        }
87    }
88
89    fn next_start_from_end(&mut self) {
90        self.end -= 1;
91
92        while self.end >= self.start && !self.is_start(self.end) {
93            self.end -= 1;
94        }
95    }
96
97    fn is_start(&self, index: usize) -> bool {
98        match self.queue[index] {
99            QueueableToken::Start { .. } => true,
100            QueueableToken::End { .. } => false,
101        }
102    }
103}
104
105impl<'i, R: RuleType> ExactSizeIterator for FlatPairs<'i, R> {
106    fn len(&self) -> usize {
107        // Tokens len is exactly twice as flatten pairs len
108        (self.end - self.start) >> 1
109    }
110}
111
112impl<'i, R: RuleType> Iterator for FlatPairs<'i, R> {
113    type Item = Pair<'i, R>;
114
115    fn next(&mut self) -> Option<Self::Item> {
116        if self.start >= self.end {
117            return None;
118        }
119
120        let pair = unsafe {
121            pair::new(
122                Rc::clone(&self.queue),
123                self.input,
124                Rc::clone(&self.line_index),
125                self.start,
126            )
127        };
128        self.next_start();
129
130        Some(pair)
131    }
132
133    fn size_hint(&self) -> (usize, Option<usize>) {
134        let len = <Self as ExactSizeIterator>::len(self);
135        (len, Some(len))
136    }
137}
138
139impl<'i, R: RuleType> DoubleEndedIterator for FlatPairs<'i, R> {
140    fn next_back(&mut self) -> Option<Self::Item> {
141        if self.end <= self.start {
142            return None;
143        }
144
145        self.next_start_from_end();
146
147        let pair = unsafe {
148            pair::new(
149                Rc::clone(&self.queue),
150                self.input,
151                Rc::clone(&self.line_index),
152                self.end,
153            )
154        };
155
156        Some(pair)
157    }
158}
159
160impl<'i, R: RuleType> fmt::Debug for FlatPairs<'i, R> {
161    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162        f.debug_struct("FlatPairs")
163            .field("pairs", &self.clone().collect::<Vec<_>>())
164            .finish()
165    }
166}
167
168impl<'i, R: Clone> Clone for FlatPairs<'i, R> {
169    fn clone(&self) -> FlatPairs<'i, R> {
170        FlatPairs {
171            queue: Rc::clone(&self.queue),
172            input: self.input,
173            line_index: Rc::clone(&self.line_index),
174            start: self.start,
175            end: self.end,
176        }
177    }
178}
179
180#[cfg(test)]
181mod tests {
182    use super::super::super::macros::tests::*;
183    use super::super::super::Parser;
184    use alloc::vec;
185    use alloc::vec::Vec;
186
187    #[test]
188    fn iter_for_flat_pairs() {
189        let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();
190
191        assert_eq!(
192            pairs.flatten().map(|p| p.as_rule()).collect::<Vec<Rule>>(),
193            vec![Rule::a, Rule::b, Rule::c]
194        );
195    }
196
197    #[test]
198    fn double_ended_iter_for_flat_pairs() {
199        let pairs = AbcParser::parse(Rule::a, "abcde").unwrap();
200        assert_eq!(
201            pairs
202                .flatten()
203                .rev()
204                .map(|p| p.as_rule())
205                .collect::<Vec<Rule>>(),
206            vec![Rule::c, Rule::b, Rule::a]
207        );
208    }
209
210    #[test]
211    fn test_line_col() {
212        let mut pairs = AbcParser::parse(Rule::a, "abcNe\nabcde").unwrap().flatten();
213
214        let pair = pairs.next().unwrap();
215        assert_eq!(pair.as_str(), "abc");
216        assert_eq!(pair.line_col(), (1, 1));
217        assert_eq!(pair.line_col(), pair.as_span().start_pos().line_col());
218
219        let pair = pairs.next().unwrap();
220        assert_eq!(pair.as_str(), "b");
221        assert_eq!(pair.line_col(), (1, 2));
222        assert_eq!(pair.line_col(), pair.as_span().start_pos().line_col());
223
224        let pair = pairs.next().unwrap();
225        assert_eq!(pair.as_str(), "e");
226        assert_eq!(pair.line_col(), (1, 5));
227        assert_eq!(pair.line_col(), pair.as_span().start_pos().line_col());
228    }
229
230    #[test]
231    fn exact_size_iter_for_pairs() {
232        let pairs = AbcParser::parse(Rule::a, "abc\nefgh").unwrap().flatten();
233        assert_eq!(pairs.len(), pairs.count());
234
235        let pairs = AbcParser::parse(Rule::a, "我很漂亮efgh").unwrap().flatten();
236        assert_eq!(pairs.len(), pairs.count());
237
238        let pairs = AbcParser::parse(Rule::a, "abc\nefgh").unwrap().flatten();
239        let pairs = pairs.rev();
240        assert_eq!(pairs.len(), pairs.count());
241
242        let mut pairs = AbcParser::parse(Rule::a, "abc\nefgh").unwrap().flatten();
243        let pairs_len = pairs.len();
244        let _ = pairs.next().unwrap();
245        assert_eq!(pairs.count() + 1, pairs_len);
246    }
247}