// pest. The Elegant Parser // Copyright (c) 2018 Dragoș Tiselice // // Licensed under the Apache License, Version 2.0 // or the MIT // license , at your // option. All files in the project carrying such notice may not be copied, // modified, or distributed except according to those terms. use alloc::rc::Rc; use alloc::vec::Vec; use core::fmt; use super::line_index::LineIndex; use super::pair::{self, Pair}; use super::queueable_token::QueueableToken; use super::tokens::{self, Tokens}; use crate::RuleType; /// An iterator over [`Pair`]s. It is created by [`Pairs::flatten`]. /// /// [`Pair`]: struct.Pair.html /// [`Pairs::flatten`]: struct.Pairs.html#method.flatten pub struct FlatPairs<'i, R> { /// # Safety /// /// All `QueueableToken`s' `input_pos` must be valid character boundary indices into `input`. queue: Rc>>, input: &'i str, start: usize, end: usize, line_index: Rc, } /// # Safety /// /// All `QueueableToken`s' `input_pos` must be valid character boundary indices into `input`. pub unsafe fn new<'i, R: RuleType>( queue: Rc>>, input: &'i str, start: usize, end: usize, ) -> FlatPairs<'i, R> { FlatPairs { queue, input, line_index: Rc::new(LineIndex::new(input)), start, end, } } impl<'i, R: RuleType> FlatPairs<'i, R> { /// Returns the `Tokens` for these pairs. /// /// # Examples /// /// ``` /// # use std::rc::Rc; /// # use pest; /// # #[allow(non_camel_case_types)] /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] /// enum Rule { /// a /// } /// /// let input = ""; /// let pairs = pest::state(input, |state| { /// // generating Token pair with Rule::a ... /// # state.rule(Rule::a, |s| Ok(s)) /// }).unwrap(); /// let tokens: Vec<_> = pairs.flatten().tokens().collect(); /// /// assert_eq!(tokens.len(), 2); /// ``` #[inline] pub fn tokens(self) -> Tokens<'i, R> { tokens::new(self.queue, self.input, self.start, self.end) } fn next_start(&mut self) { self.start += 1; while self.start < self.end && !self.is_start(self.start) { self.start += 1; } } fn next_start_from_end(&mut self) { self.end -= 1; while self.end >= self.start && !self.is_start(self.end) { self.end -= 1; } } fn is_start(&self, index: usize) -> bool { match self.queue[index] { QueueableToken::Start { .. } => true, QueueableToken::End { .. } => false, } } } impl<'i, R: RuleType> ExactSizeIterator for FlatPairs<'i, R> { fn len(&self) -> usize { // Tokens len is exactly twice as flatten pairs len (self.end - self.start) >> 1 } } impl<'i, R: RuleType> Iterator for FlatPairs<'i, R> { type Item = Pair<'i, R>; fn next(&mut self) -> Option { if self.start >= self.end { return None; } let pair = unsafe { pair::new( Rc::clone(&self.queue), self.input, Rc::clone(&self.line_index), self.start, ) }; self.next_start(); Some(pair) } fn size_hint(&self) -> (usize, Option) { let len = ::len(self); (len, Some(len)) } } impl<'i, R: RuleType> DoubleEndedIterator for FlatPairs<'i, R> { fn next_back(&mut self) -> Option { if self.end <= self.start { return None; } self.next_start_from_end(); let pair = unsafe { pair::new( Rc::clone(&self.queue), self.input, Rc::clone(&self.line_index), self.end, ) }; Some(pair) } } impl<'i, R: RuleType> fmt::Debug for FlatPairs<'i, R> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("FlatPairs") .field("pairs", &self.clone().collect::>()) .finish() } } impl<'i, R: Clone> Clone for FlatPairs<'i, R> { fn clone(&self) -> FlatPairs<'i, R> { FlatPairs { queue: Rc::clone(&self.queue), input: self.input, line_index: Rc::clone(&self.line_index), start: self.start, end: self.end, } } } #[cfg(test)] mod tests { use super::super::super::macros::tests::*; use super::super::super::Parser; use alloc::vec; use alloc::vec::Vec; #[test] fn iter_for_flat_pairs() { let pairs = AbcParser::parse(Rule::a, "abcde").unwrap(); assert_eq!( pairs.flatten().map(|p| p.as_rule()).collect::>(), vec![Rule::a, Rule::b, Rule::c] ); } #[test] fn double_ended_iter_for_flat_pairs() { let pairs = AbcParser::parse(Rule::a, "abcde").unwrap(); assert_eq!( pairs .flatten() .rev() .map(|p| p.as_rule()) .collect::>(), vec![Rule::c, Rule::b, Rule::a] ); } #[test] fn test_line_col() { let mut pairs = AbcParser::parse(Rule::a, "abcNe\nabcde").unwrap().flatten(); let pair = pairs.next().unwrap(); assert_eq!(pair.as_str(), "abc"); assert_eq!(pair.line_col(), (1, 1)); assert_eq!(pair.line_col(), pair.as_span().start_pos().line_col()); let pair = pairs.next().unwrap(); assert_eq!(pair.as_str(), "b"); assert_eq!(pair.line_col(), (1, 2)); assert_eq!(pair.line_col(), pair.as_span().start_pos().line_col()); let pair = pairs.next().unwrap(); assert_eq!(pair.as_str(), "e"); assert_eq!(pair.line_col(), (1, 5)); assert_eq!(pair.line_col(), pair.as_span().start_pos().line_col()); } #[test] fn exact_size_iter_for_pairs() { let pairs = AbcParser::parse(Rule::a, "abc\nefgh").unwrap().flatten(); assert_eq!(pairs.len(), pairs.count()); let pairs = AbcParser::parse(Rule::a, "我很漂亮efgh").unwrap().flatten(); assert_eq!(pairs.len(), pairs.count()); let pairs = AbcParser::parse(Rule::a, "abc\nefgh").unwrap().flatten(); let pairs = pairs.rev(); assert_eq!(pairs.len(), pairs.count()); let mut pairs = AbcParser::parse(Rule::a, "abc\nefgh").unwrap().flatten(); let pairs_len = pairs.len(); let _ = pairs.next().unwrap(); assert_eq!(pairs.count() + 1, pairs_len); } }