macro_rules! delimiter {
({}) => {
::proc_macro2::Delimiter::Brace
};
([]) => {
::proc_macro2::Delimiter::Bracket
};
(()) => {
::proc_macro2::Delimiter::Parenthesis
};
(<>) => {
::proc_macro2::Delimiter::None
};
(none) => {
::proc_macro2::Delimiter::None
};
}
pub(crate) mod angle;
pub(crate) mod consts;
pub(crate) mod consts_ctx;
pub(crate) mod empty_generics;
pub(crate) mod helpers;
pub(crate) mod where_process;
pub(crate) use angle::*;
pub(crate) use consts::*;
pub(crate) use consts_ctx::*;
pub(crate) use empty_generics::*;
pub(crate) use helpers::*;
pub(crate) use where_process::*;
mod blanket;
pub(crate) use blanket::expand_blanket;
use proc_macro2::{Group, Ident, TokenStream, TokenTree};
use quote::quote;
use syn::ItemTrait;
use crate::util::Cursor;
use crate::util::{compile_err, compile_error_str};
pub(crate) fn expand_tokens(
cursor: &mut Cursor, trait_def: &ItemTrait, trait_full_path: &TokenStream,
) -> Result<Vec<TokenTree>, TokenStream> {
let mut result = vec![];
while !cursor.at_end() {
if cursor.is_punct('#')
&& let Some(TokenTree::Ident(name)) = cursor.peek_at(1)
{
result.extend(expand_directive(
name,
cursor,
trait_def,
trait_full_path,
)?);
continue;
}
let Some(tt) = cursor.peek() else {
break;
};
if let TokenTree::Group(g) = tt
&& g.delimiter() == delimiter![[]]
&& !cursor.prev_bracket_passthrough()
{
let inner = expand_tokens(
&mut Cursor::new(&g.stream().into_iter().collect::<Vec<_>>()),
trait_def,
trait_full_path,
)?;
let new_group = Group::new(g.delimiter(), inner.into_iter().collect());
result.push(new_group.into());
cursor.bump();
} else {
result.push(tt.clone());
cursor.bump();
}
}
Ok(result)
}
fn expand_directive(
name: &Ident, cursor: &mut Cursor, trait_def: &ItemTrait,
trait_full_path: &TokenStream,
) -> Result<Vec<TokenTree>, TokenStream> {
if let Some(TokenTree::Group(args)) = cursor.peek_at(2) {
match args.delimiter() {
delimiter![{}] => {
cursor.bump(); cursor.bump(); cursor.bump(); expand_single(name, args, trait_def).map(|tt| vec![tt])
}
_ => {
let body_tt = cursor.peek_at(3);
let Some(TokenTree::Group(body)) = body_tt else {
return Err(compile_err!(
"`#{}` 后期望 `(args)` + `{{body}}` 或直接 `{{body}}`",
name
));
};
if body.delimiter() != delimiter![{}] {
return Err(compile_err!(
"`#{}` 后期望 `(args)` + `{{body}}` 或直接 `{{body}}`",
name
));
}
cursor.bump(); cursor.bump(); cursor.bump(); cursor.bump(); match name.to_string().as_str() {
"fill" => expand_fill(args, body, trait_def).map(|tt| vec![tt]),
"delegate" => {
expand_delegate(args, body, trait_def).map(|tt| vec![tt])
}
"blanket" => {
expand_blanket(args, body, trait_def, trait_full_path)
}
_ => {
let inner = quote! {
#name ! { #args #body #trait_def }
};
Ok(vec![Group::new(delimiter![{}], inner).into()])
}
}
}
}
} else {
Err(compile_err!(
"`#{}` 后期望括号参数 `(args)` 或代码块 `{{body}}`",
name
))
}
}
fn expand_single(
method_name: &Ident, body: &Group, trait_def: &ItemTrait,
) -> Result<TokenTree, TokenStream> {
let item = get_trait_item(trait_def, method_name)?;
Ok(Group::new(delimiter![{}], build_from_item(item, &body.stream())).into())
}
fn expand_many(
args_group: &Group, trait_def: &ItemTrait,
build: impl Fn(&Ident, &syn::TraitItem) -> Result<TokenStream, TokenStream>,
) -> Result<TokenTree, TokenStream> {
let method_names = parse_names_from_tokens(
&args_group.stream().into_iter().collect::<Vec<_>>(),
trait_def,
)?;
let mut methods = TokenStream::new();
for name in &method_names {
let item = get_trait_item(trait_def, name)?;
methods.extend(build(name, item)?);
}
Ok(Group::new(delimiter![{}], methods).into())
}
fn expand_fill(
args_group: &Group, body: &Group, trait_def: &ItemTrait,
) -> Result<TokenTree, TokenStream> {
let body_stream = body.stream();
expand_many(args_group, trait_def, |_name, item| {
Ok(build_from_item(item, &body_stream))
})
}
fn expand_delegate(
args_group: &Group, target: &Group, trait_def: &ItemTrait,
) -> Result<TokenTree, TokenStream> {
let target_stream = target.stream();
expand_many(args_group, trait_def, |name, item| {
let syn::TraitItem::Fn(f) = item else {
return Err(compile_err!(
"batch-impl: #delegate 只能用于方法,trait `{}` 中的 `{}` 不是方法",
trait_def.ident,
name
));
};
let sig = f.sig.clone();
let call_args = collect_call_args(&sig).map_err(|pat| {
compile_err!(
"batch-impl: #delegate 方法 `{}::{}` 的参数 `{}` 无法委托转发:\
仅支持 `self` 与纯标识符模式",
trait_def.ident,
name,
pat
)
})?;
let body = quote! { (#target_stream) . #name ( #(#call_args),* ) };
Ok(build_from_item(item, &body))
})
}