Skip to main content

Crate batch_impl

Crate batch_impl 

Source
Expand description

§batch-impl

v0.6.1(2026-08-05)——@ 唯一宏元记号 + blanket 约束合并 + trait 感知常量(@trait/@all 系/@Cow/@0)。

为 Rust trait 批量生成 impl 块的过程宏库——一行 DSL,展开成 N 个 impl

use batch_impl::batch_impl;

// 一个 body,为 4 种类型各生成一个 impl
#[batch_impl(<T> Sortable<T> [Box, Rc]^Vec<T> where T: Ord  {
    fn is_sorted(&self) -> bool { self.windows(2).all(|w| w[0] <= w[1]) }
})]
trait Sortable<T> { fn is_sorted(&self) -> bool; }
// → impl<T> Sortable<T> for Box<Vec<T>> where T: Ord { ... }
// → impl<T> Sortable<T> for Rc<Vec<T>>  where T: Ord { ... }

// 一行生成 4 个带泛型的元组 impl
#[batch_impl(()^4)]
trait TupleTrait {}
// → impl<A>       TupleTrait for (A,) {}
// → impl<A, B>    TupleTrait for (A, B) {}
// → impl<A, B, C> TupleTrait for (A, B, C) {}
// → impl<A, B, C, D> TupleTrait for (A, B, C, D) {}

§为什么要用它

为多个类型实现同一 trait,手写意味着重复:签名抄 N 遍、body 复制 N 份、 泛型参数与关联类型各写各的、改一处漏三处。batch-impl 把 impl 的数量交给人脑 之外的描述:

  • 一处真相源:trait 定义只写一次(签名/泛型/bound/where 约束),DSL 只写 “哪些类型 × 什么实现”,其余由宏补齐——签名、泛型 bound、关联类型绑定、 甚至 trait 级 where 约束都从 trait 定义自动继承,与手写完全等价。
  • 一行矩阵[...] 列表、^/- 应用、()^N 元组生成,一条 DSL 描述 “类型矩阵”,宏对每个格子生成一个 impl。
  • 批量但不失手写质感{ body } 是普通 Rust 代码,# 指令自动抄签名, 生成的 impl 与手写逐 token 等价——rustc 能验证什么,它就能验证什么。

一个真实场景(见 examples/simplify.rs):12 个数值类型 + 4 个包装类型 + 4 个元组 + 若干杂项 = 29 个 impl,约 15 行 DSL,手写约 80 行。

§心智模型

你写的是一条“类型矩阵“的描述,batch-impl 对矩阵的每个格子生成 impl:

#[batch_impl( <impl-泛型> Trait名<trait-泛型> 目标类型矩阵 { body }? )]
记号含义直觉
^ / -应用:把左侧容器/修饰符作用到右侧类型同一个运算,仅结合性不同
[A, B]列表横向展开(笛卡尔积)
(A, B)元组排列(有序对)
#name指令:从 trait 定义自动抄 item 签名body 不用手写签名

^-同一运算(左侧是修饰符/容器,右侧是目标类型),区别只在结合方向:

  • ^ 右结合,链式产生嵌套:Box^Box^T = Box<Box<T>>HashMap^K^V = HashMap<K<V>>
  • - 左结合,链式累加参数:HashMap-K-V = HashMap<K, V>fn(A, B)-C = fn(A, B) -> C

所以选哪个只看你想要的分组形状:想套娃用 ^,想并列参数用 -

[A, B]^[X, Y] = 2×2 矩阵(4 个 impl);(T1, T2)^2 = 排列(4 个有序对)。

§快速开始

[dependencies]
batch-impl = "0.6.1"

需要 Rust 2024 edition 及以上。

use batch_impl::batch_impl;

// 1. 定义 trait,方法签名只写一次
trait Describe { fn describe(&self) -> String; }

// 2. 写一条 DSL:目标类型 + body(方法签名用 #name 自动从 trait 抄)
#[batch_impl(
    [usize, isize] #name{"number"},
    String #name{"string"}
)]
trait Tagged { fn name(&self) -> &str; }
// → impl Tagged for usize  { fn name(&self) -> &str { "number" } }
// → impl Tagged for isize  { fn name(&self) -> &str { "number" } }
// → impl Tagged for String { fn name(&self) -> &str { "string" } }

§特性一览

特性一句话教程章节
并列列表 [A, B]为多个类型同时实现,body 复用列表与 body
^ / - 运算符同一运算的右/左结合:嵌套与累加运算符
泛型自动化A<> 照抄、同名继承、trait where 子句继承泛型自动化
关联类型绑定Iter<Item=T>type Item = T;关联类型
指令系统 #name/#fill/#delegate签名自动抄、body 批量填、委托调用指令系统
覆盖式委托 #blanket包装矩阵一行生成委托 impl(任意包装 + :N、泛型 trait、assoc 投影、包装 where 谓词)指令系统
开放扩展不认识的 #name(args){body} 交给你的同名宏指令系统
@ 常量内置族 @uint/@scalar/@u8..u128 + @trait/@all 系/@Cow + batch_trait! 自定义(懒展开、链式引用)常量系统
宏元层统一 @# 只剩指令名,范围选择(@all 系)与位置引用(@0)归宏元层常量系统
where{...}约束容器统一(<> 只留名字),blanket 约束并列合并where 子句
元组生成()^3(T,)^N、笛卡尔积、范围元组生成
fn 类型 / unsafe / 指针 / 属性类型级修饰符全支持修饰符

§下一步

  • 完整教程docs/tutorial.md(渐进式从一行 impl 到高级矩阵组合)
  • 三个入口#[batch_impl](含 trait)/ #[batch_impl_only](只出 impl)/ batch_trait!(对已声明 trait 批量生成,支持多段)
  • 示例examples/quickstart.rs(特性 demo)、examples/simplify.rs (29 个 impl ≈ 15 行 DSL 的真实场景)
  • 开发者:内部架构见 docs/architecture.md,开发变更记录见 docs/dev-changelog.md

§许可证

MIT OR Apache-2.0

§batch-impl 教程

v0.6.1(2026-08-05)——@ 唯一宏元记号、@all 系范围选择、blanket 包装约束、<> 只留名字。

渐进式学习 DSL:从一行 impl 开始,到高级矩阵组合。示例均为可编译代码, 每一步的产物都是普通 Rust——宏生成的 impl 与手写逐 token 等价。

§1. 从一行 impl 开始

#[batch_impl(...)] 标注在 trait 定义上,参数里的每个 spec 生成一个 impl:

#[batch_impl(usize, isize, f32, f64)]
trait Numeric {}
// → impl Numeric for usize {}
// → impl Numeric for isize {}
// → impl Numeric for f32 {}
// → impl Numeric for f64 {}

spec 的骨架:

<impl-泛型> Trait名<trait-泛型> 目标类型 { body }?
部分示例何时需要
<impl-泛型><T>, <T: Clone>, <const N: usize>impl 块需要泛型参数时
Trait名<trait-泛型>MyTrait<T>, MyTrait<Vec<T>>trait 定义有泛型参数时
目标类型usize, Vec<T>, &str必需
{ body }{ fn m(&self) -> usize { 0 } }需要自定义实现体时

多个 spec 用 , 分隔:#[batch_impl(usize, isize)]

§2. 列表与 body

§并列列表 [A, B]

一个 body 为所有目标类型复用:

#[batch_impl([usize, isize, f32] {
    fn tag(&self) -> &'static str { "number" }
})]
trait Tagged { fn tag(&self) -> &'static str; }
// → impl Tagged for usize { fn tag(&self) -> &'static str { "number" } }
// → impl Tagged for isize { ... }
// → impl Tagged for f32   { ... }

§独立/共享 body 合并

列表项可有独立 body,与共享 body 合并:

#[batch_impl(
    [usize { fn name() -> &'static str { "usize" } },
     isize { fn name() -> &'static str { "isize" } }]
    { fn zero() -> Self { 0 } }
)]
trait Zero {
    fn zero() -> Self;
    fn name() -> &'static str;
}
// → impl Zero for usize { fn zero() -> Self { 0 } fn name() -> &'static str { "usize" } }
// → impl Zero for isize { fn zero() -> Self { 0 } fn name() -> &'static str { "isize" } }

§3. 运算符 ^-

^-同一运算:左侧是修饰符/容器,右侧是目标类型。区别只在结合性: ^ 右结合(嵌套),- 左结合(累加参数)。

优先级从低到高:; < , < - < ^() 分组在所有运算符之上。

写法展开
Box^TBox<T>
Box^<X,Y>Box<X, Y>(多参容器)
Box^Box^TBox<Box<T>>(右结合嵌套)
HashMap<K>^VHashMap<K, V>(预填泛型追加)
&^Box^T&Box<T>(修饰符链式应用)
Vec-u32Vec<u32>
HashMap-u32-StringHashMap<u32, String>(左结合累加)
fn^(A,B)-Cfn(A,B)->C
[Box, Vec]^TBox<T>, Vec<T>
Box^[T1, T2]Box<T1>, Box<T2>
[Box, Vec]^[T1, T2]笛卡尔积共 4 项
[HashMap<K>, Vec<K>]^VHashMap<K, V>, Vec<K, V>

注意Box^Vec-u32 是错误写法(会被解释为 Box<Vec, u32>),应写为 Box^Vec^u32

操作数严格性^/-/, 两侧必须有操作数——A^^A-A,AA,,B 均报 compile_error!;仅尾随逗号A, / [A, B,])允许,();/[] 等 括号是真实 token 不算空操作数。; 作为 batch_trait! 段落边界保持宽松。

§4. 泛型声明

#[batch_impl(<T> Vec<T>)]
trait Collection {}
// → impl<T> Collection for Vec<T> {}

约束写法规范(0.6.1 起):<> 只写名字,约束统一放 where{...}——

#[batch_impl(<T> Named<T> Vec<T> where{T: Clone} { fn n(&self) -> usize { self.len() } })]
trait Named<T: Clone> { fn n(&self) -> usize; }

<T: Clone>(inline bound)仍兼容(未写约束时 trait 定义 bound 自动继承), 但约束容器统一为 where 后,多处约束的合并就是“并列谓词“(宏只做 token 拼接、零分析)——blanket 的 T: Trait 与包装谓词即因此天然合并。

§嵌套泛型合并

列表项各自声明 impl 泛型,自动合并到 impl 块:

#[batch_impl(<T> Describe<T> [Vec<T>, <U> HashMap<T, U>] {
    fn describe(&self) -> String { format!("len={}", self.len()) }
})]
trait Describe<T> { fn describe(&self) -> String; }
// → impl<T>    Describe<T> for Vec<T>
// → impl<T, U> Describe<T> for HashMap<T, U>

§const 泛型

#[batch_impl(<const N: usize> ConstGeneric<N> [i32; N] {
    fn len_const(&self) -> usize { N }
})]
trait ConstGeneric<const N: usize> { fn len_const(&self) -> usize; }
// → impl<const N: usize> ConstGeneric<N> for [i32; N] { ... }

§5. 泛型自动化(trait 定义是唯一真相源)

§A<> — trait 泛型照抄

空实参列表表示“实参与 bound 全部来自 trait 定义“:

#[batch_impl(Foo<> ())]
trait Foo<T: Clone> {}
// → impl<T: Clone> Foo<T> for ()

#[batch_impl] / #[batch_impl_only] 可用(需要 trait 定义); batch_trait! 无 trait 定义,A<> 原样透传。

§A<绑定们> — 同款照抄

纯关联类型绑定(A<Item=T>,无位置参数)同样照抄位置实参、绑定原样保留:

#[batch_impl(Foo<Item=T> ())]
trait Foo<T: Clone> { type Item; }
// → impl<T: Clone> Foo<T> for () { type Item = T; }

含位置参数的 A<T, Item=U> 是普通 DSL 语法(不展开)。

§未写 bound 的同名继承

impl 参数按“在 trait 实参中的位置“对应 trait 形参,同名且未写 bound 时继承:

#[batch_impl(<T> Foo<T> Vec<T> { fn get(&self) -> T { self[0].clone() } })]
trait Foo<T: Clone> { fn get(&self) -> T; }
// → impl<T: Clone> Foo<T> for Vec<T> { ... }

生命周期 bound(<'a, T> + trait Foo<'a, T: 'a>impl<'a, T: 'a>)、 'static、混合 bound(Clone + 'a)一并继承。

§trait 级 where 子句继承

trait Foo<T> where T: Clone 的谓词全形态继承

#[batch_impl(<T> Foo<T> ())]
trait Foo<T: Clone>
where
    T: Ord,
{
}
// → impl<T: Clone + Ord> Foo<T> for ()
  • 单一形参谓词T: Clone)合并进 bound(内联 + where 拼接),<T>A<> 两种写法同效;
  • 其余谓词原样透传到 impl 的 where 子句:T::Item: CloneVec<T>: ...、 生命周期谓词('a: 'b)等全部覆盖。
#[batch_impl(<T> Foo<T> ())]
trait Foo<T>
where
    T: IntoIterator,
    T::Item: Clone,
{
}
// → impl<T: IntoIterator> Foo<T> for () where T::Item: Clone

§改名 = 明确报错,绝不静默

实参 X 对应形参 T(有 bound)但名字不同、或继承的 bound/谓词引用 'a/U 等形参名而 impl 未声明同名——均报 compile_error! 引导 (请改名或手写 bound)。想用其他名字就手写 <X: ...>

已写 bound 的参数宏不干预(T: B 是否蕴含 T: Clone 由 rustc 验证, 如 trait B: A 的父 trait 关系)。

§6. 关联类型简洁写法

Name=value 语法在 trait 泛型参数中绑定关联类型:

#[batch_impl(<T> Iter<Item=T> Vec<T> {
    fn count(&self) -> usize { self.len() }
})]
trait Iter {
    type Item;
    fn count(&self) -> usize;
}
// → impl<T> Iter for Vec<T> { type Item = T; fn count(&self) -> usize { self.len() } }

支持多关联类型与泛型约束:

#[batch_impl(<T, U> Pair<First=T, Second=U> (T, U))]
trait Pair {
    type First;
    type Second;
}

#[batch_impl(<T: Clone> CloneIter<Item=T> Vec<T> {
    fn first(&self) -> T { self[0].clone() }
})]
trait CloneIter {
    type Item;
    fn first(&self) -> Self::Item;
}

§7. 指令系统

# 指令在预处理阶段展开,从 trait 定义自动读取 item 签名/类型,body 不用手写签名。

§#name{body} — 单 item 赋值(fn / const / type 自动选择输出格式)

#[batch_impl(usize #to_str{"usize"})]
trait ToString { fn to_str(&self) -> &str; }
// → impl ToString for usize { fn to_str(&self) -> &str { "usize" } }

#[batch_impl(usize #MAX_SIZE{1024})]
trait HasConst { const MAX_SIZE: usize; }
// → impl HasConst for usize { const MAX_SIZE: usize = 1024; }

#[batch_impl(usize #Item{u32})]
trait HasType { type Item; }
// → impl HasType for usize { type Item = u32; }

§#fill(methods){body} — 多方法同一 body

#[batch_impl(usize #fill(name, kind){"usize"})]
trait Describable { fn name(&self) -> &str; fn kind(&self) -> &str; }
// → 为 name 和 kind 各生成 { "usize" } body

特殊标记:@all(所有 item)、@all_methods(仅 fn)、@all_constants(仅 const)、@all_types(仅 type)。

按默认实现状态过滤(0.6.1 新增):trait item 分“有默认实现“(fn 带默认体 / const 带默认值 / type 带默认类型)与“无默认实现“(required,impl 必须提供)两种, @all_required* / @all_default* 分别选取:

标记选取范围
@all_required_methods仅无默认实现的方法(impl 必须提供)
@all_default_methods仅有默认实现的方法(impl 可省略)
@all_required / @all_default对应状态的全部 item(fn + const + type)
@all_required_constants / @all_default_constants对应状态的 const
@all_required_types / @all_default_types对应状态的 type(注意:trait 关联类型的默认值 type T = u8; 是 nightly 特性(associated_type_defaults,stable 上 E0658)——@all_default_types 仅 nightly 场景可用;@all_required_typestype T; 声明 stable 可用)

@all_required_methods 单独用 = “只实现必须的、默认方法保留 trait 默认实现”(比 @all + -name 逐个排除更精确);@all_default_methods 需与 required 侧或手写 组合(只填默认方法会缺 required 实现 → E0046)。required ∪ default = all。 三指令(#fill/#delegate/#blanket)与 - 排除(-@all_default_methods)通用。

// 必须的填 1,默认方法覆盖成 2
#[batch_impl(usize #fill(@all_required_methods){1} #fill(@all_default_methods){2})]
trait MixDefault {
    fn required(&self) -> u32;
    fn optional(&self) -> u32 { 100 } // 默认实现,被 @all_default_methods 覆盖
}
// 只实现必须的,默认方法保留 trait 默认
#[batch_impl(u64 #fill(@all_required_methods){3})]
trait KeepDefault {
    fn required(&self) -> u32;
    fn optional(&self) -> u32 { 7 }
}

§列表减法 -name

参数中 - 前缀表示排除项(保留列表减去排除列表,排除优先)。 用于“批量实现除了某个 item 之外的所有项“:

#[batch_impl(usize #fill(@all,-skip_me){0})]
trait HasDefault {
    fn keep_me(&self) -> u32;
    fn skip_me(&self) -> u32 { 999 } // 默认实现,被排除后保留
    const VALUE: u32;
}
// → impl HasDefault for usize {
//       fn keep_me(&self) -> u32 { 0 }
//       const VALUE: u32 = 0;
//       // skip_me 不生成,走 trait 默认实现
//   }

- 后可跟标识符(-foo)或 @all 系列标记(-@all_methods = 排除所有方法): #fill(@all,-@all_methods) = 仅 const + type 项。也适用于 #delegate#delegate(@all,-foo){target})。排除后为空、- 后缺目标会报 compile_error!- 只在指令参数域生效,与类型 DSL 的 - 连接运算符互不干扰。

§#delegate(methods){target} — 委托调用

把方法委托到 target 表达式上调用同名方法:

// Vec<u32> 用 #name 提供 body,Box<Vec<u32>> 委托过去
#[batch_impl(
    Vec<u32> #d_len{self.len()},
    Box^Vec^u32 #delegate(d_len){**self}
)]
trait MyLen { fn d_len(&self) -> usize; }
// → impl MyLen for Box<Vec<u32>> { fn d_len(&self) -> usize { (**self).d_len() } }

// blanket impl 模式:具体类型 + 引用委托
#[batch_impl(i32 #to_i32{*self}, <T: ToI32> &T #delegate(to_i32){**self})]
trait ToI32 { fn to_i32(&self) -> i32; }
// → impl<T: ToI32> ToI32 for &T { fn to_i32(&self) -> i32 { (**self).to_i32() } }

§指令与 DSL 组合

指令可与运算符、{body} 连续附着自由组合:

#[batch_impl(
    usize #name{"usize"} { fn kind(&self) -> &str { "number" } }
)]
trait Tagged { fn name(&self) -> &str; fn kind(&self) -> &str; }

#[batch_impl(<T: std::fmt::Display> Vec<T> #t10{self.len()})]
trait Len { fn t10(&self) -> usize; }

§扩展机制(开放指令系统)

不认识的 #name(args){body} 自动转换为一个 {...} 代码块,内容是函数式宏调用 name!{(args){body} trait ...}——把方法名列表、body 和整个 trait 定义一起交给 用户的同名宏,由它展开为需要的 fn 定义。这意味着指令系统是开放的,与 #fill / #delegate 完全同源:都是“读 trait → 生成 fn 定义“,只不过实现交给 用户(#fill 是库实现,开放指令是用户宏实现)。

#[batch_impl(usize #batch_preprocess_test(add,inc){*self+1})]
trait AddInc {
    fn add(&self) -> Self;
    fn inc(&self) -> Self;
}
// → trait AddInc { fn add(&self) -> Self; fn inc(&self) -> Self; }
// → impl AddInc for usize {
//       batch_preprocess_test!{(add,inc){*self+1} trait AddInc { fn add(&self) -> Self; fn inc(&self) -> Self; }}
//   }
//   → 宏展开为:fn add(&self) -> Self { *self + 1 } fn inc(&self) -> Self { *self + 1 }

说明:这是“用户自定义的 #fill“——每个类型可各挂一个 (usize #batch_preprocess_test(...){...}, isize #batch_preprocess_test(...){...}), trait 定义仍只来自 #[batch_impl] 输出的 trait,不会重复。

§#blanket(methods){包装列表} — 覆盖式委托

为包装类型批量生成委托 impl:{包装列表} 里的每个元素可以是任意类型 表达式& / &mut / Box / Rc / Arc / MyPtr / Box^Arc / Cow<'_>…),各生成一段完整委托 spec。先给内部类型实现 trait,再 blanket 覆盖包装:

#[batch_impl(u32 { fn name(&self) -> String { self.to_string() } })]
#[batch_impl(#blanket(@all){&, Box, Rc})]
trait Name {
    fn name(&self) -> String;
}
// → impl Name for u32 { ... }                       // 第一个 batch_impl
// → impl<T: Name> Name for &T    { fn name(&self) -> String { (**self).name() } }
// → impl<T: Name> Name for Box<T> { ... }           // blanket 各包装一段委托
// → impl<T: Name> Name for Rc<T>  { ... }

嵌套包装用 ^(目标类型 = 包装表达式 ^T,T 为 fresh 泛型), < 预填是追加语义(Box<Arc>^T = Box<Arc, T>,错误): Box^Arc:2Box<Arc<T>>Cow<'_>Cow<'_, T>

委托体解引用层数:默认 1(**self);嵌套须显式 :N* 数量 = N + 1,如 Box^Arc:2***self)。宏不猜包装内部的 Deref 层数——嵌套 包装忘标 :N 会退化为 rustc 方法不存在错误。

#[batch_impl(u32 { fn deep(&self) -> u32 { *self } })]
#[batch_impl(#blanket(deep){Box^Rc:2, Box^Box^Box:3})]
trait Deep {
    fn deep(&self) -> u32;
}

methods#delegate 相同(@all / @all_methods / 显式方法名列表)。

包装约束谓词:包装元素可尾随 where{...}(在 :N 之后),谓词并入 impl where 子句——解决 deref target ≠ T 的包装(如 Cow<'_, T> 的 deref target 是 T::Owned,blanket 默认委托到 T 需要额外约束)。谓词中 @0 指目标泛型(fresh T)、@trait 指本地 trait 名;@Cow 内置常量 即 Cow<'_> + 固有约束的打包:

#[batch_impl(#blanket(@all_methods){Cow<'_> where{@0: ToOwned + ?Sized, @0::Owned: @trait}})]
trait CowName { fn len(&self) -> usize; }
// → impl<T> CowName for Cow<'_, T>
//       where T: CowName, T: ToOwned + ?Sized, T::Owned: CowName
// 等价写法(内置常量):
#[batch_impl(#blanket(@all_methods){@Cow})]
trait CowName2 { fn len(&self) -> usize; }

泛型 trait 支持trait Foo<X: Clone>):trait 形参照抄为 impl 泛型 (impl<X: Clone, T: Foo<X>> Foo<X> for 包装<T> where ...),trait 级 where 谓词透传。

assoc type / const 委托@all 含 const/type 项时生成投影 type Item = <T as Foo<X>>::Item; / const N: Ty = <T as Foo<X>>::N;—— 带必需关联类型的 trait 也能 blanket 覆盖。

#[batch_impl(Foo<u32> u32 {
    type Item = u8;
    fn m(&self) -> u32 { *self }
})]
#[batch_impl(#blanket(@all){&, Box})]
trait Foo<X: Clone> {
    type Item;
    fn m(&self) -> X;
}
// → impl<X: Clone, T: Foo<X>> Foo<X> for Box<T> {
//     type Item = <T as Foo<X>>::Item;
//     fn m(&self) -> X { (**self).m() }
//   }

约束:*const/*mut(安全代码无法解引用裸指针委托)、self(无意义)、 空元素 / 非法 :N 均报错,请手写 #delegate。by-value receiver 方法 (fn consume(self))委托语义取决于包装的 Deref/move 能力,宏展开期无法 区分——维持全放行,由 rustc 兜底。

§8. where 子句

§where{...} 后缀

where{...} 后缀跟在目标类型之后,内是透传的 where 谓词;多个会合并:

#[batch_impl(<T: Clone> Sortable<T> Vec<T> where{ T: Ord } {
    fn sort(&self) -> Vec<T> { let mut v = self.clone(); v.sort(); v }
})]
trait Sortable<T> { fn sort(&self) -> Vec<T>; }
// → impl<T: Clone> Sortable<T> for Vec<T> where T: Ord { ... }

#[batch_impl(<A> <B> PairAB<A, B> (A, B) where{A: Clone} where{B: Clone} {
    fn pair(&self) -> (A, B) { (self.0.clone(), self.1.clone()) }
})]
trait PairAB<A, B> { fn pair(&self) -> (A, B); }

§裸写 where 谓词 {代码块}

也支持 Rust 风格裸写(三个接口通用),谓词后的 {...} 代码块必须存在; 谓词区边界为首个 {...} 代码块(ident!{...} 宏调用体与 <N = {5}> 尖括号内 代码块不计入),逗号谓词不会被 spec 切分:

#[batch_impl(<A> <B> PairAB<A, B> (A, B) where A: Clone, B: Clone {
    fn pair(&self) -> (A, B) { (self.0.clone(), self.1.clone()) }
})]
trait PairAB<A, B> { fn pair(&self) -> (A, B); }
// → impl<A, B> PairAB<A, B> for (A, B) where A: Clone, B: Clone { ... }

多个 where 段可依次书写(where A: Clone where B: Clone),与旧式多 where{...} 等价。

§9. fn 类型

#[batch_impl(fn^(i32, u32))]
trait FnSimple {}

// fn 类型追加返回类型
#[batch_impl(fn(i32, u32)-String)]
trait FnWithReturn {}

// fn 类型批量生成(笛卡尔积)
#[batch_impl(fn-(i32, u32)^2)]
trait FnTupleGen {}
// → impl FnTupleGen for fn(i32, i32) {}
// → impl FnTupleGen for fn(i32, u32) {}
// → impl FnTupleGen for fn(u32, i32) {}
// → impl FnTupleGen for fn(u32, u32) {}

unsafe fn(...) 类型:unsafe 紧跟 fn 时修饰 fn 类型本身,与 unsafe^T 的 unsafe impl 标记无关(unsafe^fn(...) 才是“unsafe impl,目标为 fn 类型“):

#[batch_impl(unsafe fn(i32, u32) -> u32)]
trait UnsafeFnType {}
// → impl UnsafeFnType for unsafe fn(i32, u32) -> u32 {}

#[batch_impl(unsafe fn^(i32, u32) - i64)]
trait UnsafeFnType2 {}
// → impl UnsafeFnType2 for unsafe fn(i32, u32) -> i64 {}

unsafe 歧义规则:裸 unsafe(后跟 ^/- 或单独出现)= unsafe impl 标记; unsafe fn... = unsafe fn 类型;unsafe 其他类型(并列、无运算符)= 报错 (几乎必是忘写 ^ 的笔误,应写 unsafe^T)。

§10. 修饰符大全

修饰符含义
&引用(&^T&T
&mut可变引用(&mut^T&mut T
*const裸指针(*const^T*const T
*mut可变裸指针(*mut^T*mut T
self恒等(self^TT
unsafeunsafe^T = unsafe impl 标记
#[attr]属性前缀(#[attr]^T → impl 前加属性)
[]空基座([]^T[T][]-T-N[T; N]
[T]切片([T]^N → 定长数组 [T; N]
#[batch_impl(unsafe^usize, isize)]
unsafe trait UnsafePartial {}
// unsafe trait 的所有 impl 自动 unsafe

#[batch_impl(*const^u32, *mut^i32)]
trait PtrMarker {}

#[batch_impl(*const^Box^u32)]
trait ConstPtrChain {}
// → impl ConstPtrChain for *const Box<u32> {}

#[batch_impl(#[allow(dead_code)]^usize, isize)]
trait AttrSimple {}

§数组/切片 builder

#[batch_impl([]^u8)]          // → impl ArrSlice for [u8] {}
trait ArrSlice {}

#[batch_impl([u8]^3)]         // → impl ArrLit for [u8; 3] {}
trait ArrLit {}

#[batch_impl(<const N: usize> [u8]^N)]  // → impl<const N: usize> ArrConst for [u8; N] {}
trait ArrConst {}

#[batch_impl([u8]^1..3)]      // → impl ArrRange for [u8; 1] {} 与 [u8; 2] {}
trait ArrRange {}

§复杂类型透传

无法识别的类型原样透传:

#[batch_impl(
    (i32, String),
    &str,
    Box<dyn std::fmt::Display>,
    fn(i32) -> bool,
    dyn Fn() + Send + Sync
)]
trait ComplexMarker {}

§11. 元组生成与矩阵

^ 右侧是数字或范围时,生成指定长度的元组(数字只作为指数使用):

写法展开
()^3(A, B, C)(带3个泛型参数)
(T,)^3(T, T, T)
(<Clone>)^3(A:Clone, B:Clone, C:Clone)
(T1, T2)^2笛卡尔积 (T1,T1), (T1,T2), (T2,T1), (T2,T2)
()^1..3(A,), (A, B)(长度1到2)
()^1..=3(A,), (A, B), (A, B, C)(长度1到3)
(T,)^2..4(T, T), (T, T, T)(长度2到3)

注意:(T) 是分组(非元组),(T,) 才是单元素元组。

#[batch_impl(()^1..=4 { fn describe(&self) -> &'static str { "tuple" } })]
trait DescribeTuple { fn describe(&self) -> &'static str; }
// → 4 个 impl:(A,)、(A, B)、(A, B, C)、(A, B, C, D)

§把整个矩阵包进 const 泛型定长数组

[] 作为 - 累加链的基座:

#[batch_impl(
    <const N: usize> []-[&, self, Box]^[u8, i8, ()^0..3]-N
)]
trait FixedMatrix {}
// → impl<const N: usize> FixedMatrix for [&u8; N]   { }
// → impl<const N: usize> FixedMatrix for [Box<i8>; N] { }
// → impl<const N: usize, A> FixedMatrix for [(A,); N] { }  // 元组 fresh 泛型自动外提
// → ...

§@ 常量 — 内置类型族命名

常用类型矩阵不必手写:@ 常量在预处理阶段展开为字面列表,与手写等价。

常量展开
@uint[u8, u16, u32, u64, u128, usize]
@int[i8, i16, i32, i64, i128, isize]
@float[f32, f64]
@num@uint + @int + @float(14 个)
@scalar@num + [bool, char](16 个)
@u8..u128[u8, u16, u32, u64, u128]含端点@i8..i128 / @f32..f64 同款)
#[batch_impl(@scalar)]
trait ScalarTrait {}
// → 16 个 impl:u8..char 各一个

三个入口(#[batch_impl] / #[batch_impl_only] / batch_trait!)都支持内置 常量。batch_trait! 额外支持自定义常量:宏参数前导 @name=值; 段定义, 后续段落复用。值是任意 token懒展开——原样入库,引用处拼接后递归 展开),因此值里可以直接写 DSL 运算、链式引用其他常量:

trait TraitA {}
trait TraitB {}
batch_trait!(
    @nums=[u8, u16, u32];
    @uints=@uint;                      // 引用内置常量
    @wrapped=[Box, Rc]^@nums;          // 值含 DSL 运算(引用处求值)
    @chain=@wrapped;                   // 链式引用用户常量
    TraitA: @chain;
    TraitB: [Box, Rc]^@uints;
);

引用可见性:常量定义内只能引用内置常量或此前已定义的用户常量—— 循环引用(@a=@a)与前向引用(@a=@b@b 定义在后)在定义处报错。

未知 @xxx、范围端点非法、自定义与内置重名、循环/前向引用均报 compile_error!

§batch_trait! 段级 @trait(跨段复用「泛型声明 + trait 名」)

batch_trait! 多段每段 trait 名不同——常量值里的 @trait 在分段后 逐段替换为本段 trait 路径

` ust

§use batch_impl::batch_trait;

§trait A {} trait B {}

batch_trait!{ @type_t = @trait ; // 打包「泛型声明 + 本段 trait 名」 A: @type_t [&, Box]^T; // → A [&, Box]^T B: @type_t Box^[T, Vec]; // → B Box^[T, Vec] } `

§宏元层完整化:@trait / @all 系 / @Cow / @0

batch_impl / batch_impl_only 持有 trait 定义,宏元层额外提供 trait 感知 常量(batch_trait! 是函数式宏、拿不到定义,遇下列记号报错):

记号展开场景
@traittrait 完整路径(batch_impl=本地名、batch_impl_only=外部路径);batch_trait! 中为段级:展开为本段 trait 路径blanket 包装 where 谓词;batch_trait! 跨段打包「泛型声明+trait 名」
@all / @all_methods / @all_constants / @all_types[item名, ...](Bracket 组)指令范围选择——#fill(@all) 等价旧 #fill(#all)
@all_required* / @all_default*按默认实现状态过滤的 Bracket 组只填必须的 / 只覆盖默认的
@CowCow<'_> + 固有约束谓词blanket 包装(deref target = T::Owned
@0(位置引用)目标泛型名(fresh T)仅 blanket 包装 where 谓词内

@all 系展开为 Bracket 组后走指令参数解析:# 不再作为范围标记—— # 只剩指令名一种格式(#fill/#delegate/#blanket/开放扩展),范围 选择统一归宏元层。减法不受影响:#fill(@all, -foo)#fill(@all, -[a,b])

指令参数支持 [a, b] 列表#fill([m1, m2]){...}- 排除也可写 -[a, b]@all 展开产物即此形态,用户手写等价)。

§12. 三个入口

用途
#[batch_impl]属性宏,在 trait 定义上标注,宏参数即 DSL
#[batch_impl_only]同上,但丢弃 trait 定义,只输出 impl 块
batch_trait!函数式宏,对已声明的 trait 批量生成 impl(支持多 trait)

三者接受相同的 DSL 参数。

§#[batch_impl_only]

trait 已在别处定义、只需批量生成 impl 的场景。trait 定义仍要写出(只用来读取方法签名),输出不含 trait:

#[batch_impl_only(usize #hello{"hi"})]
trait Greet { fn hello(&self) -> &str; } // 此 dummy 定义被丢弃
// → impl Greet for usize { fn hello(&self) -> &str { "hi" } }

支持 #path::to::Trait: 路径前缀,为外部模块中定义的 trait 生成 impl (路径末尾标识符必须与本地 dummy trait 名一致;#[batch_impl] 不支持此前缀):

#[batch_impl_only(#ext::traits::TraitName: usize, isize)]
trait TraitName { }
// → impl ext::traits::TraitName for usize {}
// → impl ext::traits::TraitName for isize {}

§batch_trait!

对已声明的 trait 批量生成 impl,; 分隔多个 trait 段。语法: [unsafe] Trait路径: impl-specs: 右侧接受类型 DSL 与 @ 常量(与 #[batch_impl] 相同的类型语法),额外支持多 trait 段、路径 trait(如 foo::C)、unsafe 段:

use batch_impl::batch_trait;

trait A {}
trait B<T> {}
unsafe trait UnsafeTrait {}

batch_trait!(
    A: usize, isize;
    B: <T> B<T> Vec<T>;
    unsafe UnsafeTrait: usize
);

限制batch_trait! 不支持 # 指令#fill/#delegate/#blanket/ 开放扩展)——指令需要 trait 定义作签名真相源,而 batch_trait! 是函数式宏、 拿不到 trait 定义。需要指令时请改用 #[batch_impl] / #[batch_impl_only]

§13. 错误提示

所有 DSL 语法错误通过 compile_error!() 输出中文提示并指向源码位置,永不 panic:

错误输入错误信息
batch_trait!(;)batch_trait! 中期望 trait 名称
batch_trait!(A)batch_trait! 中期望 ':' 分隔 trait 名称和 impl-specs
batch_trait!(A: B::)batch_trait! 中期望标识符作为 trait 名称
where 缺代码块batch-impl: \where` 谓词后缺少代码块 {…}`
where 谓词引用未声明形参batch-impl: 继承的 where 谓词 ... 引用形参 ...,请声明或手写 where

Macros§

batch_trait
对已声明的 trait 批量生成 impl 块的函数式宏。

Attribute Macros§

batch_impl
为 trait 批量生成 impl 块的属性宏。
batch_impl_only
#[batch_impl] 相同,但丢弃被标注的 trait 定义,只输出 impl 块。