batch-impl 0.5.7

A proc-macro library for batch generating trait impls with a powerful DSL
Documentation
//! 预处理层:指令展开、裸 where 改写、尖括号组配对。

// ============================================================
// 分隔符拼写宏
// ============================================================

/// 分隔符拼写宏:统一 `Delimiter::*` 字面量为源码分隔符拼写
/// (调用统一用 `[]`)——`delimiter![{}]` / `delimiter![[]]` /
/// `delimiter![()]` 与源码一一对应。
///
/// proc-macro2 的 `Delimiter` 无"尖括号"变体,`<>` 必须借用 `Delimiter::None`
/// 承载——而 `None` 本身也是真实"透明组"的拼写。为避免两义,宏用两种拼写
/// 区分:
/// - `delimiter![<>]`:**尖括号组**载体(`angle_collect` 配对产物);
/// - `delimiter![none]`:**真实透明组**(宏变量 `$var:ty` 展开产物,
///   内容即 DSL token,需扁平化)。
///
/// 二者展开值相同(`Delimiter::None`),不可在同一条 `match` 中作两个臂
/// (会报 unreachable pattern);实际用法分布在互斥的上下文,无冲突。
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 preprocess_helpers;
pub(crate) mod where_process;

pub(crate) use angle::*;
pub(crate) use preprocess_helpers::*;
pub(crate) use where_process::*;

use proc_macro2::{Group, Ident, TokenStream, TokenTree};
use quote::quote;
use syn::ItemTrait;

use crate::diagnostic::compile_error_str;
use crate::scan::Cursor;

// ============================================================
// 指令预处理
// ============================================================

/// 指令预处理入口:扫描 token 流,展开 `#` 指令。
///
/// 仅 `#[batch_impl]` / `#[batch_impl_only]` 支持(需要 trait 定义读取方法签名)。
/// `batch_trait!` 不调用此函数(无 trait 定义可用)。
///
/// ## 指令语法
///
/// | 指令 | 语法 | 效果 |
/// |------|------|------|
/// | 单 item | `#name{body}` | `{fn method(签名) { body }}` 或 `{const NAME: Type = body;}` 或 `{type Name = body;}` |
/// | 填充 | `#fill(args){body}` | `{fn m1(sig){body} fn m2(sig){body} ...}` |
/// | 委托 | `#delegate(args){target}` | `{fn m1(sig){(target).m1(args)} ...}` |
///
/// `#name{body}` 中 `name` 可以是 trait 中的任意 item 名(方法、常量、类型),
/// `build_from_item` 根据 item 类型自动选择输出格式。
///
/// `args` 中出现 `#all` 表示 trait 的所有 item(fn + const + type),
/// `#all_methods` 仅 Fn 方法,`#all_constants` 仅 const,`#all_types` 仅 type。
///
/// ## 递归规则
///
/// 只递归展开 `[...]`(Bracket)Group 内容;`(...)` 和 `{...}` 不递归,
/// 避免误入指令的参数或 body。
pub(crate) fn expand_tokens(
    cursor: &mut Cursor, trait_def: &ItemTrait,
) -> 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)
        {
            // 每个指令展开为恰好一个 token(一个 `{...}` 组),直接入列
            result.push(expand_directive(name, cursor, trait_def)?);
            continue;
        }
        // 当前 token 一定存在(循环条件保证了非 at_end)
        let Some(tt) = cursor.peek() else {
            // 逻辑上不可达;防御性 break 以兜底
            break;
        };
        // 只递归展开 [...] 内容(`(...)` 和 `{...}` 不递归);
        // `ident![...]` 宏调用体与 `#[...]` 属性是透传的(内容任意 Rust,
        // 不得展开其中的指令——与 angle_collect 的 Bracket 守卫对齐)
        if let TokenTree::Group(g) = tt
            && g.delimiter() == delimiter![[]]
            && !cursor.prev_is_punct('!')
            && !cursor.prev_is_punct('#')
        {
            let inner = expand_tokens(
                &mut Cursor::new(&g.stream().into_iter().collect::<Vec<_>>()),
                trait_def,
            )?;
            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)
}

/// 分派指令:根据 `#` 后的名称和括号结构分派到对应的展开函数。
/// 每个指令展开为恰好一个 `{...}` 组 token。
fn expand_directive(
    name: &Ident, cursor: &mut Cursor, trait_def: &ItemTrait,
) -> Result<TokenTree, TokenStream> {
    if let Some(TokenTree::Group(args)) = cursor.peek_at(2) {
        match args.delimiter() {
            delimiter![{}] => {
                // `#name{body}` — item 名紧跟 `{body}`(fn / const / type 通用)
                cursor.bump(); // #
                cursor.bump(); // method_name
                cursor.bump(); // {body}
                expand_single(name, args, trait_def)
            }
            _ => {
                // `#cmd(args){body}` — 名称 + 括号参数 + {body}
                let body_tt = cursor.peek_at(3);
                let Some(TokenTree::Group(body)) = body_tt else {
                    return Err(compile_error_str(&format!(
                        "`#{}` 后期望 `(args)` + `{{body}}` 或直接 `{{body}}`",
                        name
                    )));
                };
                if body.delimiter() != delimiter![{}] {
                    return Err(compile_error_str(&format!(
                        "`#{}` 后期望 `(args)` + `{{body}}` 或直接 `{{body}}`",
                        name
                    )));
                }
                cursor.bump(); // #
                cursor.bump(); // name
                cursor.bump(); // (args)
                cursor.bump(); // {body}
                match name.to_string().as_str() {
                    "fill" => expand_fill(args, body, trait_def),
                    "delegate" => expand_delegate(args, body, trait_def),
                    // 开放扩展:`#name(args){body}` → `{ name!{(args){body} trait_def} }`
                    // 一个函数式宏调用,位于 impl body(附着用法)或顶层(独立用法)。
                    // 与 `#fill`/`#delegate` 同源:把"读 trait → 生成 fn 定义"的实现
                    // 交给用户的同名宏——它解析 args / body / trait 并生成 impl 项。
                    _ => {
                        let inner = quote! {
                            #name ! { #args #body #trait_def }
                        };
                        Ok(Group::new(delimiter![{}], inner).into())
                    }
                }
            }
        }
    } else {
        Err(compile_error_str(&format!(
            "`#{}` 后期望括号参数 `(args)` 或代码块 `{{body}}`",
            name
        )))
    }
}

/// `#name{body}` → `{fn method(签名) { body }}` 或 `{const NAME: Type = body;}` 或 `{type Name = body;}`
///
/// 根据 `name` 在 trait 定义中查找对应的 item,由 `build_from_item` 按 item 类型自动输出。
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())
}

/// 多 item 指令展开的公共骨架:解析方法名列表 → 逐 item 构造实现 → 打包为 `{...}` 组。
/// `build` 按 item 构造实现体(可报错,如 `#delegate` 的非 fn 项/解构参数)。
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())
}

/// `#fill(args){body}` → `{fn m1(sig){body} fn m2(sig){body} ...}`
///
/// `args` 为逗号分隔的 item 名列表,或 `#all`(表示所有 item)。
/// 支持 fn、const、type 三种 item 类型。
/// 为每个 item 从 trait 定义读取签名/类型,body 作为实现体。
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))
    })
}

/// `#delegate(args){target}` → `{fn m1(sig){(target).m1(params)} ...}`
///
/// 为每个方法生成委托调用:跳过 `self` 参数,将其余参数原样转发。
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_error_str(&format!(
                "batch-impl: #delegate 只能用于方法,trait `{}` 中的 `{}` 不是方法",
                trait_def.ident, name
            )));
        };
        let sig = f.sig.clone();
        let call_args = collect_call_args(&sig).map_err(|pat| {
            compile_error_str(&format!(
                "batch-impl: #delegate 方法 `{}::{}` 的参数 `{}` 无法委托转发:\
                 仅支持 `self` 与纯标识符模式",
                trait_def.ident, name, pat
            ))
        })?;
        let body = quote! { (#target_stream) . #name ( #(#call_args),* ) };
        Ok(build_from_item(item, &body))
    })
}