1#[cfg(feature = "proc_macro2")]
4use proc_macro2::{TokenStream, TokenTree};
5
6#[cfg(not(feature = "proc_macro2"))]
7use proc_macro::{TokenStream, TokenTree};
8
9use crate::EndOfStream;
10use crate::Parser;
11
12#[derive(Clone)]
14#[cfg_attr(feature = "proc_macro2", derive(Debug))]
15struct TokenIterBase {
16 iter: <TokenStream as IntoIterator>::IntoIter,
18 counter: usize,
20
21 #[cfg(feature = "extra_asserts")]
22 committed: bool,
25}
26
27impl TokenIterBase {
28 fn new(
29 iter: impl IntoIterator<IntoIter = <TokenStream as IntoIterator>::IntoIter>,
30 start_at: usize,
31 ) -> Self {
32 Self {
33 iter: iter.into_iter(),
34 counter: start_at,
35 #[cfg(feature = "extra_asserts")]
36 committed: false,
37 }
38 }
39}
40
41#[derive(Clone)]
51#[cfg_attr(feature = "proc_macro2", derive(Debug))]
52pub struct TokenIter {
53 base: TokenIterBase,
54}
55
56impl TokenIter {
57 pub fn new(
59 stream: impl IntoIterator<IntoIter = <TokenStream as IntoIterator>::IntoIter>,
60 ) -> Self {
61 TokenIter {
62 base: TokenIterBase::new(stream, 0),
63 }
64 }
65}
66
67impl TokenIter {
68 #[must_use]
70 pub const fn counter(&self) -> usize {
71 self.base.counter
72 }
73
74 pub(crate) fn add(&mut self, add: usize) {
76 self.base.counter += add;
77 }
78
79 pub(crate) fn parse_group<T>(
84 &mut self,
85 stream: impl IntoIterator<IntoIter = <TokenStream as IntoIterator>::IntoIter>,
86 ) -> crate::Result<T>
87 where
88 T: crate::Parser,
89 {
90 #[cfg(feature = "extra_asserts")]
91 assert!(!self.base.committed);
92 let mut tokens = TokenIter {
93 base: TokenIterBase::new(stream, self.counter()),
94 };
95 let parsed = T::parser(&mut tokens)?;
96 EndOfStream::parser(&mut tokens)?;
98 self.base.counter = tokens.counter();
99 #[cfg(feature = "extra_asserts")]
100 {
101 self.base.committed = true;
102 };
103 Ok(parsed)
104 }
105}
106
107impl Iterator for TokenIter {
109 type Item = TokenTree;
110
111 fn next(&mut self) -> Option<Self::Item> {
112 let item = self.base.iter.next()?;
113 self.base.counter += 1;
114 #[cfg(feature = "extra_asserts")]
115 {
116 self.base.committed = false;
117 };
118 Some(item)
119 }
120}
121
122pub trait IntoTokenIter: Sized {
124 fn into_token_iter(self) -> TokenIter;
126}
127
128impl IntoTokenIter for <TokenStream as IntoIterator>::IntoIter {
129 fn into_token_iter(self) -> TokenIter {
130 TokenIter {
131 base: TokenIterBase::new(self, 0),
132 }
133 }
134}
135
136pub trait ToTokenIter: Sized {
138 fn to_token_iter(self) -> TokenIter;
140}
141
142impl ToTokenIter for TokenStream {
143 fn to_token_iter(self) -> TokenIter {
144 TokenIter::new(self)
145 }
146}