proc_macro_tool/
parse_iter.rs1use crate::{stream, TokenTreeExt as _};
2use proc_macro::{Spacing::*, TokenStream, TokenTree};
3use std::{array, collections::VecDeque, iter::{self, FusedIterator}};
4
5pub trait ParseIterExt: IntoIterator<Item = TokenTree> + Sized {
7 fn parse_iter(self) -> ParseIter<Self::IntoIter> {
9 ParseIter { iter: self.into_iter(), buf: VecDeque::new() }
10 }
11}
12impl<I: IntoIterator<Item = TokenTree>> ParseIterExt for I { }
13
14#[derive(Debug, Clone)]
16pub struct ParseIter<I: Iterator<Item = TokenTree>> {
17 iter: I,
18 buf: VecDeque<TokenTree>,
19}
20
21impl<I: Iterator<Item = TokenTree>> ParseIter<I> {
22 pub fn peek(&mut self) -> Option<&TokenTree> {
23 self.peek_i(0)
24 }
25
26 pub fn next_if<F>(&mut self, f: F) -> Option<TokenTree>
27 where F: FnOnce(&TokenTree) -> bool,
28 {
29 let peek = self.peek()?;
30
31 if f(peek) {
32 self.next()
33 } else {
34 None
35 }
36 }
37
38 pub fn next_i_if<F>(&mut self, i: usize, f: F) -> Option<TokenTree>
39 where F: FnOnce(&TokenTree) -> bool,
40 {
41 let peek = self.peek_i(i)?;
42
43 if f(peek) {
44 self.nth(i)
45 } else {
46 None
47 }
48 }
49
50 #[track_caller]
53 pub fn next_tts<const N: usize>(&mut self) -> [TokenTree; N] {
54 array::from_fn(|_| self.next()
55 .expect("unexpected end of input"))
56 }
57
58 pub fn peek_i(&mut self, i: usize) -> Option<&TokenTree> {
59 for _ in self.buf.len()..=i {
60 self.buf.push_back(self.iter.next()?);
61 }
62 Some(&self.buf[i])
63 }
64
65 pub fn peek_is<F>(&mut self, f: F) -> bool
66 where F: FnOnce(&TokenTree) -> bool,
67 {
68 self.peek().is_some_and(f)
69 }
70
71 pub fn peek_i_is<F>(&mut self, i: usize, f: F) -> bool
72 where F: FnOnce(&TokenTree) -> bool,
73 {
74 self.peek_i(i).is_some_and(f)
75 }
76
77 pub fn peek_puncts(
79 &mut self,
80 puncts: impl AsRef<[u8]>,
81 ) -> Option<impl Iterator<Item = &TokenTree>> {
82 self.peek_i_puncts(0, puncts)
83 }
84
85 pub fn peek_i_puncts(
87 &mut self,
88 i: usize,
89 puncts: impl AsRef<[u8]>,
90 ) -> Option<impl Iterator<Item = &TokenTree>> {
91 let mut prev = None;
92
93 let puncts = puncts.as_ref();
94
95 for (j, ch) in puncts.iter().copied().map(char::from).enumerate() {
96 if let Some(prev) = prev {
97 if prev == Alone { return None }
98 }
99
100 let tt = self.peek_i(i + j)?;
101 let TokenTree::Punct(p) = tt else { return None };
102 if p.as_char() != ch { return None }
103
104 prev = Some(p.spacing());
105 }
106 Some(self.buf.iter().skip(i).take(puncts.len()))
107 }
108
109 pub fn next_puncts(
111 &mut self,
112 puncts: impl AsRef<[u8]>,
113 ) -> Option<impl Iterator<Item = TokenTree> + '_> {
114 let puncts = puncts.as_ref();
115 let _ = self.peek_puncts(puncts)?;
116
117 Some(self.buf.drain(..puncts.len()))
118 }
119
120 #[allow(clippy::missing_panics_doc)]
124 pub fn split_puncts(&mut self, puncts: impl AsRef<[u8]>) -> Option<TokenStream> {
125 let puncts = puncts.as_ref();
126 let mut i = 0;
127
128 loop {
129 if self.peek_i_puncts(i, puncts).is_some() {
130 let left = self.take(i).collect();
131 let _ = self.next_puncts(puncts).unwrap();
132 break Some(left);
133 }
134 self.peek_i(i)?;
135 i += 1;
136 }
137 }
138
139 pub fn split_puncts_all<'a>(
143 &'a mut self,
144 puncts: impl AsRef<[u8]> + 'a,
145 ) -> impl Iterator<Item = TokenStream> + 'a {
146 iter::from_fn(move || {
147 self.split_puncts(puncts.as_ref())
148 .or_else(|| self.peek().is_some().then(|| self.collect()))
149 })
150 }
151
152 pub fn next_attributes(&mut self) -> Vec<TokenStream> {
153 let mut attributes = vec![];
154
155 while self.peek_puncts("#").is_some()
156 &&self.peek_i_is(1, |tt| tt.is_delimiter_bracket())
157 {
158 attributes.push(self.next_tts::<2>().into_iter().collect());
159 }
160
161 attributes
162 }
163
164 pub fn next_outer_attributes(&mut self) -> Vec<TokenStream> {
165 let mut attributes = vec![];
166
167 while self.peek_puncts("#").is_some()
168 &&self.peek_i_is(1, |tt| tt.is_punch('!'))
169 &&self.peek_i_is(2, |tt| tt.is_delimiter_bracket())
170 {
171 attributes.push(stream(self.next_tts::<3>()));
172 }
173
174 attributes
175 }
176
177 #[allow(clippy::missing_panics_doc)]
178 pub fn next_vis(&mut self) -> Option<TokenStream> {
179 if self.peek_is(|tt| tt.is_keyword("pub")) {
180 if self.peek_i_is(1, |tt| tt.is_delimiter_paren()) {
181 return Some(stream(self.next_tts::<2>()));
182 }
183 return Some(self.next().unwrap().into());
184 }
185 None
186 }
187}
188impl<I: Iterator<Item = TokenTree>> Iterator for ParseIter<I> {
189 type Item = TokenTree;
190
191 fn next(&mut self) -> Option<Self::Item> {
192 self.buf.pop_front()
193 .or_else(|| self.iter.next())
194 }
195
196 fn count(self) -> usize
197 where Self: Sized,
198 {
199 self.buf.len() + self.iter.count()
200 }
201
202 fn fold<B, F>(self, init: B, f: F) -> B
203 where Self: Sized,
204 F: FnMut(B, Self::Item) -> B,
205 {
206 self.buf.into_iter().chain(self.iter).fold(init, f)
207 }
208
209 fn size_hint(&self) -> (usize, Option<usize>) {
210 let (lo, hi) = self.iter.size_hint();
211 let lo = lo.saturating_add(self.buf.len());
212 let hi = hi.and_then(|hi| hi.checked_add(self.buf.len()));
213 (lo, hi)
214 }
215}
216impl<I: DoubleEndedIterator<Item = TokenTree>> DoubleEndedIterator for ParseIter<I> {
217 fn next_back(&mut self) -> Option<Self::Item> {
218 self.iter.next_back()
219 .or_else(|| self.buf.pop_back())
220 }
221
222 fn rfold<B, F>(self, init: B, f: F) -> B
223 where Self: Sized,
224 F: FnMut(B, Self::Item) -> B,
225 {
226 self.buf.into_iter().chain(self.iter).rfold(init, f)
227 }
228}
229impl<I: ExactSizeIterator<Item = TokenTree>> ExactSizeIterator for ParseIter<I> { }
230impl<I: FusedIterator<Item = TokenTree>> FusedIterator for ParseIter<I> { }