use proc_macro2::{Group, TokenStream, TokenTree};
use quote::{ToTokens, quote};
use crate::util::compile_error_str;
pub(crate) fn return_type_refs_self(output: &syn::ReturnType) -> bool {
match output {
syn::ReturnType::Default => false,
syn::ReturnType::Type(_, ty) => ty
.to_token_stream()
.into_iter()
.any(|tt| matches!(tt, TokenTree::Ident(id) if id == "Self")),
}
}
pub(crate) fn has_at0(tokens: &[TokenTree]) -> bool {
let v: Vec<_> = tokens.to_vec();
v.iter().enumerate().any(|(i, tt)| match tt {
TokenTree::Punct(p) if p.as_char() == '@' => {
matches!(v.get(i + 1), Some(TokenTree::Literal(l)) if l.to_string() == "0")
}
TokenTree::Group(g) => has_at0(&g.stream().into_iter().collect::<Vec<_>>()),
_ => false,
})
}
pub(crate) fn trait_with_args(path: &TokenStream, param_names: &[TokenStream]) -> TokenStream {
if param_names.is_empty() {
quote!(#path)
} else {
let args_group = Group::new(delimiter![<>], quote!(#(#param_names),*));
quote!(#path #args_group)
}
}
pub(crate) fn resolve_target_predicates(
preds: &[TokenTree], trait_full_path: &TokenStream,
) -> Result<Vec<TokenTree>, TokenStream> {
let mut out = vec![];
let mut i = 0;
while i < preds.len() {
match &preds[i] {
TokenTree::Punct(p) if p.as_char() == '@' => match preds.get(i + 1) {
Some(TokenTree::Ident(id)) if id == "trait" => {
out.extend(trait_full_path.clone());
i += 2;
}
Some(TokenTree::Literal(lit)) if lit.to_string().parse::<usize>().is_ok() => {
out.push(preds[i].clone());
out.push(TokenTree::Literal(lit.clone()));
i += 2;
}
_ => {
return Err(compile_error_str(
"batch-impl: in #blanket wrapper where, `@` must be \
followed by a position digit (e.g. `@0`) or `@trait`",
preds[i].span(),
));
}
},
_ => {
out.push(preds[i].clone());
i += 1;
}
}
}
Ok(out)
}