use syn::parse::ParseStream;
use syn::{Ident, Path, Token, token};
pub(crate) fn peek_element_start(input: ParseStream) -> bool {
if !input.peek(Ident) {
return false;
}
let fork = input.fork();
let Ok(ident) = fork.parse::<Ident>() else {
return false;
};
if !ident_starts_upper(&ident) {
return false;
}
if fork.peek(Token![::]) {
let path_fork = input.fork();
if let Ok(path) = path_fork.parse::<Path>()
&& ends_in_variant_shape(&path)
{
return path_fork.peek(token::Brace);
}
return true;
}
fork.is_empty() || fork.peek(token::Paren) || fork.peek(token::Brace)
}
fn ends_in_variant_shape(path: &Path) -> bool {
if path.segments.len() < 2 {
return false;
}
let last = &path.segments[path.segments.len() - 1].ident;
let second_last = &path.segments[path.segments.len() - 2].ident;
ident_starts_upper(last) && ident_starts_upper(second_last)
}
pub(crate) fn ident_starts_upper(ident: &Ident) -> bool {
ident
.to_string()
.chars()
.next()
.is_some_and(|c| c.is_ascii_uppercase())
}
pub(crate) fn peek_escape(input: ParseStream) -> bool {
input.peek(Token![#]) && input.peek2(token::Brace)
}
pub(crate) fn peek_binding(input: ParseStream) -> bool {
if !input.peek(Ident) || !input.peek2(Token![=]) || input.peek2(Token![==]) {
return false;
}
let fork = input.fork();
let Ok(_ident) = fork.parse::<Ident>() else {
return false;
};
let Ok(_eq) = fork.parse::<Token![=]>() else {
return false;
};
peek_element_start(&fork)
}