#[cfg(feature = "proc_macro2")]
use proc_macro2::{TokenStream, TokenTree};
#[cfg(not(feature = "proc_macro2"))]
use proc_macro::{TokenStream, TokenTree};
use crate::EndOfStream;
use crate::Parser;
#[derive(Clone)]
#[cfg_attr(feature = "proc_macro2", derive(Debug))]
struct TokenIterBase {
iter: <TokenStream as IntoIterator>::IntoIter,
counter: usize,
#[cfg(feature = "extra_asserts")]
committed: bool,
}
impl TokenIterBase {
fn new(
iter: impl IntoIterator<IntoIter = <TokenStream as IntoIterator>::IntoIter>,
start_at: usize,
) -> Self {
Self {
iter: iter.into_iter(),
counter: start_at,
#[cfg(feature = "extra_asserts")]
committed: false,
}
}
}
#[derive(Clone)]
#[cfg_attr(feature = "proc_macro2", derive(Debug))]
pub struct TokenIter {
base: TokenIterBase,
}
impl TokenIter {
pub fn new(
stream: impl IntoIterator<IntoIter = <TokenStream as IntoIterator>::IntoIter>,
) -> Self {
TokenIter {
base: TokenIterBase::new(stream, 0),
}
}
}
impl TokenIter {
#[must_use]
pub const fn counter(&self) -> usize {
self.base.counter
}
pub(crate) fn add(&mut self, add: usize) {
self.base.counter += add;
}
pub(crate) fn parse_group<T>(
&mut self,
stream: impl IntoIterator<IntoIter = <TokenStream as IntoIterator>::IntoIter>,
) -> crate::Result<T>
where
T: crate::Parser,
{
#[cfg(feature = "extra_asserts")]
assert!(!self.base.committed);
let mut tokens = TokenIter {
base: TokenIterBase::new(stream, self.counter()),
};
let parsed = T::parser(&mut tokens)?;
EndOfStream::parser(&mut tokens)?;
self.base.counter = tokens.counter();
#[cfg(feature = "extra_asserts")]
{
self.base.committed = true;
};
Ok(parsed)
}
}
impl Iterator for TokenIter {
type Item = TokenTree;
fn next(&mut self) -> Option<Self::Item> {
let item = self.base.iter.next()?;
self.base.counter += 1;
#[cfg(feature = "extra_asserts")]
{
self.base.committed = false;
};
Some(item)
}
}
pub trait IntoTokenIter: Sized {
fn into_token_iter(self) -> TokenIter;
}
impl IntoTokenIter for <TokenStream as IntoIterator>::IntoIter {
fn into_token_iter(self) -> TokenIter {
TokenIter {
base: TokenIterBase::new(self, 0),
}
}
}
pub trait ToTokenIter: Sized {
fn to_token_iter(self) -> TokenIter;
}
impl ToTokenIter for TokenStream {
fn to_token_iter(self) -> TokenIter {
TokenIter::new(self)
}
}