use crate::util::log::debug;
use proc_macro2::{TokenStream, TokenTree};
use quote::ToTokens;
use std::marker::PhantomData;
use syn::parse::{Parse, ParseStream};
pub struct Terminated<T, Term>
where
T: Parse,
Term: Parse,
{
value: T,
terminator_type: PhantomData<Term>,
}
impl<T, Term> Terminated<T, Term>
where
T: Parse,
Term: Parse,
{
pub(crate) fn into_value(self) -> T {
self.value
}
}
impl<T, Term> Parse for Terminated<T, Term>
where
T: Parse,
Term: Parse,
{
fn parse(input: ParseStream) -> syn::Result<Self> {
let mut tokens = TokenStream::new();
while !input.is_empty() {
debug!(
"Parsing Terminated<{}, {}>: {:?}...",
std::any::type_name::<T>(),
std::any::type_name::<Term>(),
input
);
let fork = input.fork();
let is_terminator = fork.parse::<Term>().is_ok();
if is_terminator {
break;
}
let tt = input.parse::<TokenTree>()?;
tokens.extend(tt.into_token_stream());
}
debug!(
"Collecting tokens for Terminated<{}, {}> is successful: {:?}",
std::any::type_name::<T>(),
std::any::type_name::<Term>(),
tokens
);
debug!("Parsing {}: {:?}...", std::any::type_name::<T>(), tokens);
let value = syn::parse2::<T>(tokens)?;
debug!("Parsing {} is successful.", std::any::type_name::<T>());
Ok(Terminated {
value,
terminator_type: PhantomData,
})
}
}