batch-impl 0.5.1

A proc-macro library for batch generating trait impls with a powerful DSL
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
# batch-impl

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

```rust
use batch_impl::batch_impl;
# use std::rc::Rc;

// 一个 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) {}
```

## 核心心智模型

你写的是**一条"类型矩阵"的描述**,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 个有序对)。

## 快速开始

```toml
[dependencies]
batch-impl = "0.5.1"
```

需要 Rust 2024 edition 及以上。

```rust
use batch_impl::batch_impl;

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

// 2. 写一条 DSL:目标类型 + body(方法签名用 #fill 自动从 trait 抄)
#[batch_impl(
    [usize, isize] #fill(name){"number"},
    String #fill(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" } }
```

## 语法参考

### spec 结构

| 部分                  | 示例                                    | 何时需要               |
|-----------------------|-----------------------------------------|------------------------|
| `<impl-泛型>`         | `<T>`, `<T: Clone>`, `<const N: usize>` | impl 块需要泛型参数时  |
| `Trait名<trait-泛型>` | `MyTrait<T>`, `MyTrait<Vec<T>>`         | trait 定义有泛型参数时 |
| 目标类型              | `usize`, `Vec<T>`, `&str`               | 必需                   |
| `[...]` 列表          | `[A, B, C]`                             | 为多个类型同时实现     |
| `{ body }`            | `{ fn m(&self) -> usize { 0 } }`        | 需要自定义实现体时     |

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

### 运算符

DSL 通过四级优先级解析(从低到高):

| 优先级 | 运算符 | 结合方向 | 说明                              |
|--------|--------|----------|-----------------------------------|
| 0      | `;`    || `batch_trait!` 的段落分隔符       |
| 1      | `,`    || impl-spec 列表分隔                |
| 2      | `-`    | 左结合   | 应用(同 `^` 语义,链式累加参数) |
| 3      | `^`    | 右结合   | 应用(链式嵌套)                  |

`(` `)` 分组在所有运算符之上起作用。

结合示例:

- `A^B-C,D` = `(A^B)-C,D` = `A<B,C>,D`
- `[A,B]^[C,D]-E` = `([A,B]^[C,D])-E` = `[A<C>,A<D>,B<C>,B<D>]-E`
- `HashMap^K-V` = `(HashMap^K)-V` = `HashMap<K>-V` = `HashMap<K, V>`
- `fn^(A,B)-C` = `(fn^(A,B))-C` = `fn(A,B)->C`

> **注意**`Box^Vec-u32` 是错误写法(会被解释为 `Box<Vec, u32>`),应写为 `Box^Vec^u32`
### `^` 修饰符

左侧的修饰符可以是:

| 修饰符         | 含义                                              |
|----------------|---------------------------------------------------|
| `&`            | 引用                                              |
| `&mut`         | 可变引用                                          |
| `*const`       | 裸指针(不可变)                                  |
| `*mut`         | 裸指针(可变)                                    |
| `self`         | 恒等(不改变类型)                                |
| `unsafe`       | 标记 impl 为 `unsafe impl`                        |
| `fn`           | 函数类型前缀                                      |
| `#[attr]`      | 属性前缀                                          |
| `Ident`        | 容器(如 `Box`, `Vec`|
| `Ident<...>`   | 带预填泛型的容器(如 `HashMap<K>`),`^` 追加参数 |
| `(A,)`/`(A,B)` | 元组前缀                                          |
| `()`           | 空元组前缀                                        |
| `(<bound>)`    | 带 trait bound 的泛型元组前缀                     |
| `[A, B]`       | 多修饰符(笛卡尔积展开)                          |

| 写法                     | 展开                              |
|--------------------------|-----------------------------------|
| `&^T`                    | `&T`                              |
| `&mut^T`                 | `&mut T`                          |
| `*const^T`               | `*const T`                        |
| `*mut^T`                 | `*mut T`                          |
| `self^T`                 | `T`                               |
| `Box^T`                  | `Box<T>`                          |
| `Box^<X,Y>`              | `Box<X, Y>`(多参容器)           |
| `[Box, Vec]^T`           | `Box<T>, Vec<T>`                  |
| `Box^[T1, T2]`           | `Box<T1>, Box<T2>`                |
| `[Box, Vec]^[T1, T2]`    | 笛卡尔积共 4 项                   |
| `Box^Box^T`              | `Box<Box<T>>`(右结合嵌套)       |
| `HashMap<K>^V`           | `HashMap<K, V>`(预填泛型追加)   |
| `[HashMap<K>, Vec<K>]^V` | `HashMap<K, V>, Vec<K, V>`        |
| `&^Box^T`                | `&Box<T>`(修饰符链式应用)       |
| `*const^Vec^T`           | `*const Vec<T>`                   |
| `fn^(A,B)`               | `fn(A,B)`(函数类型)             |
| `#[attr]^T`              | 在 impl 块前添加属性              |

### `-` 运算符

与 `^` 同一运算,仅左结合(链式累加参数):

| 写法                 | 展开                                           |
|----------------------|------------------------------------------------|
| `Vec-u32`            | `Vec<u32>`                                     |
| `HashMap-u32-String` | `HashMap<u32, String>`(左结合,参数累加)     |
| `()-[A, B]`          | `(A,), (B,)`                                   |
| `()-[A, B]-[C, D]`   | `(A, C), (A, D), (B, C), (B, D)`               |

### 元组生成

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

| 写法          | 展开                                          |
|---------------|-----------------------------------------------|
| `()^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,)` 才是单元素元组。

### 歧义处理

- **`[]`**:有逗号是并列列表,无逗号是切片类型(如 `Box^[u32]``Box<[u32]>`- **`()`**`()` = 空元组,`(A,)` = 单元素元组,`(A)` = 分组
- **`()^0`**:生成空元组 `()`,即 `impl Trait for ()`
- **`[T; N]`**`[]` 内的 `;` 通过 DSL 的 `Semi` 优先级层级识别为定长数组分隔符

## 组合拳

### 共享 body + 列表

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

```rust
# use batch_impl::{batch_impl, batch_impl_only, batch_trait};
#[batch_impl([usize, isize, f32] {
    fn tag(&self) -> &'static str { "number" }
})]
trait Tagged { fn tag(&self) -> &'static str; }
```

### 嵌套泛型合并

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

```rust
# use batch_impl::{batch_impl, batch_impl_only, batch_trait};
use std::collections::HashMap;

#[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>
```

### 独立/共享 body 合并

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

```rust
# use batch_impl::{batch_impl, batch_impl_only, batch_trait};
#[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" } }
```

### 关联类型简洁写法

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

```rust
# use batch_impl::{batch_impl, batch_impl_only, batch_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() } }
```

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

```rust
# use batch_impl::{batch_impl, batch_impl_only, batch_trait};
#[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;
}
```

### 指令系统

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

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

```rust
# use batch_impl::{batch_impl, batch_impl_only, batch_trait};
#[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**:

```rust
# use batch_impl::{batch_impl, batch_impl_only, batch_trait};
#[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)。

```rust
# use batch_impl::{batch_impl, batch_impl_only, batch_trait};
#[batch_impl(usize #fill(#all){"default"})]
trait HasAll { fn method(&self) -> &str; const VALUE: &str; }
// → fn method 与 const VALUE 各生成 { "default" } body
```

**`#delegate(methods){target}` — 委托调用**:把方法委托到 target 表达式上调用同名方法。

```rust
# use batch_impl::{batch_impl, batch_impl_only, batch_trait};
// 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}` 连续附着自由组合:

```rust
# use batch_impl::{batch_impl, batch_impl_only, batch_trait};
#[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` 自动转换为 `#[name[(args){body}]]` 属性,交给用户的属性宏处理。工作流程:预处理器遇到 `#my_handler(args){body}` → 不认识 `my_handler` → 生成 `#[my_handler[(args){body}]]` → DSL 解析器当普通属性节点处理 → 编译器随后调用用户的 `#[my_handler]` 属性宏。这意味着指令系统是**开放的**。

### `where{...}` — where 子句

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

```rust
# use batch_impl::{batch_impl, batch_impl_only, batch_trait};
#[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); }
```

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

```rust
# use batch_impl::{batch_impl, batch_impl_only, batch_trait};
#[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{...}` 等价。

### fn 类型

```rust
# use batch_impl::{batch_impl, batch_impl_only, batch_trait};
#[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 / 指针 / 属性

```rust
# use batch_impl::{batch_impl, batch_impl_only, batch_trait};
#[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 {}
```

### 复杂类型透传

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

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

## 三个入口

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

三者接受相同的 DSL 参数。

### `#[batch_impl_only]`

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

```rust
# use batch_impl::{batch_impl, batch_impl_only, batch_trait};
# trait Greet { fn hello(&self) -> &str; } // 真实 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]` 不支持此前缀):

```ignore
// 路径前缀需要真实的外部模块上下文:doctest 的 fn main 内无法定义 pub 模块,
// 故此处仅示意语法(`mod` 是关键字不能作路径段,实际应为合法模块名)。
// 该特性的编译行为由 tests/regression.rs 中的路径 trait 用例覆盖。
#[batch_impl_only(#ext::traits::TraitName: usize, isize)]
trait TraitName { }
```

### `batch_trait!`

对已声明的 trait 批量生成 impl,`;` 分隔多个 trait 段。语法:`[unsafe] Trait路径: impl-specs`,接受与 `#[batch_impl]` 完全相同的 DSL 语法(`:` 右侧),额外支持多 trait 段、路径 trait(如 `foo::C`,见 tests/regression.rs)、unsafe 段:

```rust
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
);
```

## 错误提示

所有 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\` 谓词后缺少代码块 {...}`          |

## 内部架构

```text
lib.rs              宏入口 + 共享驱动(#[batch_impl] / #[batch_impl_only] / batch_trait!)
  ├── preprocess.rs      指令预处理:#name 指令展开(内置 + 自定义属性委托)
  ├── where_process.rs   裸 where 改写:`where 谓词 {body}` → 旧式 `where{谓词}`(预处理后、解析前,三接口共用)
  ├── preprocess_helpers.rs  预处理辅助:build_from_item / get_trait_item / collect_call_args
  ├── parse.rs           DSL 解析器:Cursor 游标 + 优先级攀爬(Op::Semi/Comma/Dash/Caret/Prim)
  ├── parse_atom.rs      原子层解析:属性 / fn / 分组 / 前缀 / 范围
  ├── generic.rs         泛型与尖括号解析:parse_generic / parse_angle_bracket_contents
  ├── types.rs           AST 节点(Ty 枚举 19 个变体,含 Error)+ Op 优先级定义;前缀/后缀包装内层用 Option<Box<Ty>> 表示裸状态
  ├── types_render.rs    AST 渲染:ToTokens impl for Ty + params_to_tokens 系列
  ├── apply.rs           运算符语义:Apply trait + 核心 apply() 折叠规则(^ 右结合 / 数组分发)
  ├── apply_tuple.rs     元组与容器运算符:TyTuple / TyGroup / TyFn / TyWithPrefix 等的 Apply impl + 元组展开(^N / 笛卡尔积 / 范围)
  ├── scan.rs            扫描与游标:Cursor<'a> + scan_with + ScanMode::Lossy / Strict
  ├── batch_trait_entry.rs  共享驱动:BFS 展开并列列表 → 逐叶子 generate_impl
  ├── path_prefix.rs     外部 trait 路径前缀:#Path::to::Trait: 状态机解析
  ├── codegen.rs         代码生成:extract_impl_parts 递归拆解 → generate_impl 渲染 impl 块
  └── diagnostic.rs      统一 compile_error_str(msg) 用于编译期诊断
```

解析流程:**token 流 → 指令预处理 → where 裸写改写 → Cursor 扫描取切片 → parse_item 优先级攀爬 → Ty AST → BFS 展开并列列表 → 逐叶子 generate_impl**

### 错误处理

所有 DSL 语法错误均通过 `compile_error!()` 输出友好的编译错误,**永不 panic**。`Ty::Error` 变体在 apply/codegen 链路中透传,`preprocess` 层通过 `Result<_, TokenStream>` 传播,并由 `diagnostic.rs::compile_error_str` 统一构造 `compile_error!` token 流。

### 测试

测试矩阵分三层:

| 目录        | 文件            | 用途                                                                                                                                            |
|-------------|-----------------|-------------------------------------------------------------------------------------------------------------------------------------------------|
| `examples/` | `quickstart.rs` | 可运行的 DSL 主特性 demo(`cargo run --example quickstart`),14 段覆盖基础→复杂场景                                                            |
| `tests/`    | `dsl.rs`        | 27 个 `#[test]`,覆盖核心特性的语义回归(含 where 子句、外部路径前缀)                                                                          |
| `tests/`    | `regression.rs` | 16 个 `#[test]`,覆盖 dsl.rs 未触碰的 corner case:嵌套 `>>`、路径类型、const 泛型、生命周期、dyn + Send、`batch_impl` vs `batch_trait!` 一致性 |
| `tests/`    | `ui.rs`         | `trybuild` UI 测试:9 个 `compile_fail` fixture 锁定诊断措辞 + 1 个 `pass` fixture                                                              |

运行:

```bash
cargo run --example quickstart       # 主特性 demo
cargo test --test dsl --test regression   # 功能与回归测试
cargo test --test ui                  # 诊断 UI 测试
# 重新生成 UI 快照:
TRYBUILD=overwrite cargo test --test ui
```

## 许可证

MIT OR Apache-2.0