autozig 0.1.2

Safe autogenerated interop between Rust and Zig
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
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597

# AutoZig 架构设计文档

本文档详细说明了 AutoZig 的内部架构设计和实现细节。

## 📐 总体架构

AutoZig 采用三阶段编译流水线,参考了 autocxx 的设计理念,并针对 Zig 的特性进行了优化。

```
用户代码 (src/main.rs with autozig!)
┌─────────────────────────────────────┐
│  阶段 1: 解析 (Parsing)              │
│  - parser: 解析宏输入                │
│  - scanner: 扫描源文件               │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│  阶段 2: 构建 (Build - build.rs)    │
│  - engine: 核心构建引擎              │
│  - zig_compiler: Zig 编译器包装      │
│  - bindgen: 生成 FFI 绑定            │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│  阶段 3: 宏展开 (Macro Expansion)   │
│  - macro: 生成安全包装器             │
│  - type_mapper: 类型转换             │
└─────────────────────────────────────┘
编译后的 Rust 二进制 + 静态链接的 Zig 代码
```

## 🔧 核心组件

### 1. Parser (`autozig-parser`)

**职责**: 解析 `autozig!` 宏的输入

**关键文件**:
- `src/lib.rs`: 主解析逻辑

**功能**:
- 解析混合的 Zig/Rust 语法
- 识别 `---` 分隔符
- 提取 Zig 代码部分
- 解析 Rust 函数签名(用于生成安全包装器)

**示例输入**:
```rust
autozig! {
    // Zig 部分
    export fn add(a: i32, b: i32) i32 {
        return a + b;
    }
    ---
    // Rust 签名部分
    fn add(a: i32, b: i32) -> i32;
}
```

**输出**: `AutoZigConfig` 结构,包含:
- `zig_code`: String - 提取的 Zig 代码
- `rust_signatures`: Vec<RustFunctionSignature> - 解析的函数签名

### 2. Engine (`autozig-engine`)

**职责**: 核心构建引擎,orchestrate 整个编译流程

**关键文件**:
- `src/lib.rs`: 主引擎逻辑
- `src/scanner.rs`: 源代码扫描器
- `src/zig_compiler.rs`: Zig 编译器包装
- `src/type_mapper.rs`: 类型映射表

**工作流程**:

```rust
AutoZigEngine::build() {
    1. 扫描源文件 (.rs)
       └→ scanner.scan()
       
    2. 提取所有 autozig! 宏中的 Zig 代码
       └→ 合并为单个 generated_autozig.zig
       
    3. 调用 Zig 编译器
       └→ zig build-lib -static -femit-h
       └→ 生成 libautozig.a 和 generated_autozig.h
       
    4. 运行 bindgen
       └→ 从 .h 文件生成 Rust FFI 绑定
       └→ 输出到 OUT_DIR/bindings.rs
       
    5. 配置 Cargo 链接
       └→ println!("cargo:rustc-link-lib=static=autozig")
}
```

#### 2.1 Scanner (`scanner.rs`)

**功能**:
- 递归遍历源目录
- 使用正则表达式匹配 `autozig! { ... }`
- 提取 Zig 代码(分隔符之前的部分)
- 合并所有 Zig 代码

**正则表达式**:
```rust
let re = Regex::new(r"autozig!\s*\{([\s\S]*?)\}")?;
```

**注意事项**:
- 当前实现使用简单正则,不处理嵌套大括号
- 生产版本应使用 syn 进行完整的语法解析

#### 2.2 Zig Compiler (`zig_compiler.rs`)

**功能**:
- 包装 `zig` 命令行工具
- 编译 Zig 源码为静态库
- 生成 C ABI 兼容的头文件

**关键命令**:
```bash
zig build-lib source.zig \
    -static \
    -femit-h=output.h \
    -femit-bin=output.a \
    -target native
```

**环境变量**:
- `ZIG_PATH`: 自定义 Zig 编译器路径(可选)
- 默认使用系统 PATH 中的 `zig`

#### 2.3 Type Mapper (`type_mapper.rs`)

**功能**:
- 维护 Zig ↔ Rust 类型映射表
- 识别需要特殊处理的类型(如切片)
- 分析参数转换策略

**类型映射表**:

| Zig 类型 | Rust FFI 类型 | 注释 |
|---------|--------------|------|
| `i8`, `i16`, `i32`, `i64` | `i8`, `i16`, `i32`, `i64` | 直接映射 |
| `u8`, `u16`, `u32`, `u64` | `u8`, `u16`, `u32`, `u64` | 直接映射 |
| `f32`, `f64` | `f32`, `f64` | 直接映射 |
| `bool` | `u8` | Zig bool 在 C ABI 中是 u8 |
| `[*]const u8` | `*const u8` | 原始指针 |
| `void` | `()` | 单元类型 |

**参数转换策略**:

```rust
enum ParamConversion {
    Direct,           // 基本类型直接传递
    SliceToPtrLen,    // &[T] → (ptr, len)
    StrToPtrLen,      // &str → (ptr, len)
}
```

### 3. Macro (`autozig-macro`)

**职责**: 过程宏实现,生成最终的 Rust 代码

**关键文件**:
- `src/lib.rs`: 宏实现

**工作流程**:

```rust
#[proc_macro]
pub fn autozig(input: TokenStream) -> TokenStream {
    1. 解析输入
       └→ parse_macro_input!(input as AutoZigConfig)
       
    2. 生成 FFI 模块引用
       └→ mod ffi { include!(concat!(env!("OUT_DIR"), "/bindings.rs")); }
       
    3. 如果有 Rust 签名,生成安全包装器
       └→ pub fn safe_func(...) { unsafe { ffi::raw_func(...) } }
       
    4. 处理类型转换
       └→ &[u8] → (ptr, len)
       └→ &str → (ptr, len)
}
```

**生成的代码示例**:

输入:
```rust
autozig! {
    export fn compute_hash(ptr: [*]const u8, len: usize) u64 { ... }
    ---
    fn compute_hash(data: &[u8]) -> u64;
}
```

输出:
```rust
mod ffi {
    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}

pub fn compute_hash(data: &[u8]) -> u64 {
    unsafe {
        ffi::compute_hash(data.as_ptr(), data.len())
    }
}
```

### 4. Build Support (`autozig-build`)

**职责**: build.rs 辅助库

**关键文件**:
- `src/lib.rs`: Builder API

**使用示例**:
```rust
// build.rs
fn main() -> anyhow::Result<()> {
    autozig_build::build("src")?;
    Ok(())
}
```

## 🔄 完整编译流程

### 时间线视图

```
T0: cargo build 开始
T1: build.rs 执行
    ├→ autozig_build::build("src")
    ├→ 扫描 src/*.rs
    ├→ 提取 Zig 代码
    ├→ 写入 OUT_DIR/generated_autozig.zig
    ├→ 调用 zig build-lib
    │   └→ 生成 OUT_DIR/libautozig.a
    │   └→ 生成 OUT_DIR/generated_autozig.h
    ├→ 调用 bindgen
    │   └→ 生成 OUT_DIR/bindings.rs
    └→ 配置链接器
T2: rustc 编译 src/main.rs
    ├→ 展开 autozig! 宏
    ├→ 生成安全包装器代码
    ├→ 包含 OUT_DIR/bindings.rs
    └→ 编译所有 Rust 代码
T3: 链接阶段
    ├→ 链接 Rust 对象文件
    ├→ 链接 libautozig.a (Zig 代码)
    └→ 生成最终可执行文件
T4: 完成
```

### 数据流视图

```
源代码 (main.rs)
    ├─→ [Parser] ─→ AutoZigConfig
    │                    ├─ zig_code: String
    │                    └─ rust_signatures: Vec<Sig>
    ├─→ [Scanner] ─→ 合并的 Zig 代码
    │                    └─→ generated_autozig.zig
    └─→ [Engine]
            ├─→ [ZigCompiler]
            │       ├─→ libautozig.a
            │       └─→ generated_autozig.h
            └─→ [Bindgen]
                    └─→ bindings.rs (Raw FFI)

宏展开 (autozig!)
    └─→ [Macro]
            ├─ include FFI bindings
            └─ generate safe wrappers
                    └─→ 最终 Rust 代码
```

## 🎯 设计决策

### 为什么使用静态链接?

**优点**:
1. **简单性**: 不需要管理动态库路径
2. **可移植性**: 单个二进制文件,无外部依赖
3. **性能**: 可能有更好的内联优化
4. **部署**: 更容易分发

**缺点**:
1. 二进制文件更大
2. 无法在运行时替换 Zig 代码

### 为什么在 build.rs 而不是宏中编译?

**原因**:
1. **编译时机**: build.rs 在宏展开前运行
2. **环境隔离**: build.rs 有独立的依赖
3. **文件操作**: 更容易处理文件 I/O
4. **错误处理**: 更清晰的错误报告

### 为什么使用 bindgen?

**原因**:
1. **成熟工具**: bindgen 是 Rust FFI 的标准工具
2. **Zig C ABI**: Zig 的 `export` 函数使用 C ABI
3. **减少工作**: 不需要手动写 FFI 绑定

### 为什么需要两种语法(Zig + Rust 签名)?

**原因**:
1. **灵活性**: 纯 Zig 适合简单用例
2. **安全性**: Rust 签名允许生成安全包装器
3. **类型转换**: 明确指定 Rust 侧的类型
4. **渐进式**: 可以先写 Zig,后续添加安全包装

## 🔒 安全性考虑

### 内存安全

1. **指针传递**:
   - Zig 接收 `[*]const u8``len`
   - Rust 保证切片的生命周期有效
   - 不允许 Zig 持有指针超过函数调用范围

2. **生命周期**:
   - 所有传递给 Zig 的引用都是临时的
   - Zig 函数必须在调用期间完成所有操作
   - 不支持异步或回调(需要额外设计)

3. **类型安全**:
   - 通过 bindgen 确保 C ABI 兼容性
   - Rust 侧的安全包装器处理类型转换
   - 编译时检查类型匹配

### 未定义行为预防

1. **空指针检查**:
   - 当前实现未检查空指针
   - 生产版本应添加检查
   - 或使用 `Option<&[T]>` 语义

2. **整数溢出**:
   - Zig 使用 wrapping 语义 (`+%`)
   - Rust 在 debug 模式检查溢出
   - 需要明确文档说明行为差异

3. **并发安全**:
   - Zig 代码不应使用全局可变状态
   - 如需共享状态,使用 Rust 的并发原语
   - 通过接口传递状态指针

## 🚀 未来改进方向

### 短期目标

1. **完善安全包装器生成**:
   - 自动处理 `&str``(ptr, len)` 转换
   - 支持 `&[T]` 的泛型转换
   - 处理返回值的生命周期

2. **改进错误处理**:
   - 更好的编译错误消息
   - Zig 编译错误的友好显示
   - 源码位置追踪

3. **测试基础设施**:
   - 集成测试套件
   - 自动化测试 Zig 编译
   - 跨平台测试

### 中期目标

1. **高级类型支持**:
   - Zig 结构体 ↔ Rust 结构体
   - 枚举类型映射
   - 可选类型 (`?T``Option<T>`)

2. **性能优化**:
   - 缓存 Zig 编译结果
   - 增量编译支持
   - 并行构建多个 autozig! 宏

3. **更好的IDE支持**:
   - rust-analyzer 集成
   - Zig 代码的语法高亮
   - 跳转到定义

### 长期目标

1. **异步支持**:
   - Zig 异步函数 ↔ Rust async/await
   - 回调函数支持
   - 事件循环集成

2. **动态链接选项**:
   - 支持生成 .so/.dylib
   - 插件系统
   - 热重载

3. **标准库集成**:
   - 预定义的常用 Zig 标准库绑定
   - 数据结构互操作
   - 字符串处理工具

## 🐛 已知限制

### 当前版本限制

1. **语法解析**:
   - 使用简单正则表达式,不处理嵌套大括号
   - 可能错误匹配注释中的 `autozig!`
   - **解决方案**: 使用 syn 完整解析

2. **类型系统**:
   - 仅支持基本类型
   - 不支持复杂结构体
   - 不支持泛型
   - **解决方案**: 逐步添加类型支持

3. **错误处理**:
   - Zig 错误无法传递到 Rust
   - 必须在 Zig 侧处理所有错误
   - **解决方案**: 设计错误传递机制

4. **并发**:
   - 未测试多线程环境
   - Zig 全局状态可能不安全
   - **解决方案**: 添加线程安全文档

### 平台限制

1. **依赖 Zig 编译器**:
   - 需要用户安装 Zig
   - 版本兼容性未充分测试
   - **建议**: 锁定 Zig 0.11 或 0.12

2. **交叉编译**:
   - 未测试交叉编译场景
   - 目标三元组映射可能不完整
   - **解决方案**: 添加目标映射表

## 📊 性能考虑

### 编译时间

**影响因素**:
1. Zig 编译器调用(每次构建 ~1-5 秒)
2. bindgen 运行(取决于头文件复杂度)
3. 源文件扫描(对大项目可能显著)

**优化策略**:
1. 缓存编译结果
2. 仅在 Zig 代码变化时重新编译
3. 并行处理多个 autozig! 宏

### 运行时性能

**FFI 开销**:
- 函数调用:极小(内联可能)
- 类型转换:几乎为零(仅指针操作)
- 无动态分配(静态链接)

**与直接 C FFI 比较**:
- **相同**: 都通过 C ABI 调用
- **优势**: Zig 的安全特性(边界检查等)
- **劣势**: 无(性能相当)

## 🧪 测试策略

### 单元测试

**parser 测试**:
```rust
#[test]
fn test_parse_zig_only() {
    let config: AutoZigConfig = parse_quote! {
        export fn add(a: i32, b: i32) i32 { return a + b; }
    };
    assert!(!config.zig_code.is_empty());
}
```

**type_mapper 测试**:
```rust
#[test]
fn test_type_mapping() {
    let mapper = TypeMapper::new();
    assert_eq!(mapper.map_type("i32"), Some("i32"));
}
```

### 集成测试

**完整流程测试**:
1. 创建临时项目
2. 写入测试代码
3. 运行 `cargo build`
4. 验证编译成功
5. 运行可执行文件
6. 验证输出正确

### 性能测试

**基准测试**:
- FFI 调用延迟
- 类型转换开销
- 编译时间测量

## 📖 参考资料

### 相关项目

1. **autocxx**: https://github.com/google/autocxx
   - 本项目的主要灵感来源
   - C++ FFI 的类似方法

2. **bindgen**: https://github.com/rust-lang/rust-bindgen
   - Rust FFI 绑定生成器
   - AutoZig 的核心依赖

3. **cxx**: https://github.com/dtolnay/cxx
   - 安全的 C++ FFI
   - 不同的设计理念

4. **Zig**: https://ziglang.org/
   - Zig 语言官网
   - C 互操作文档

### 技术文档

1. **Zig C ABI**: https://ziglang.org/documentation/master/#C
2. **Rust FFI**: https://doc.rust-lang.org/nomicon/ffi.html
3. **Procedural Macros**: https://doc.rust-lang.org/reference/procedural-macros.html

## 🤝 贡献指南

### 代码风格

- 遵循 Rust 标准风格(`rustfmt`- 所有公共 API 必须有文档注释
- 使用 `#![forbid(unsafe_code)]`(除非绝对必要)

### 提交流程

1. Fork 项目
2. 创建功能分支
3. 编写测试
4. 确保所有测试通过
5. 提交 Pull Request

### 测试要求

- 所有新功能必须有测试
- 保持测试覆盖率 > 80%
- 集成测试验证端到端流程

## 📝 总结

AutoZig 通过三阶段编译流水线实现了 Rust 和 Zig 之间的安全互操作:

1. **解析阶段**: 提取和解析 Zig 代码及 Rust 签名
2. **构建阶段**: 编译 Zig 为静态库并生成 FFI 绑定
3. **宏展开阶段**: 生成安全的 Rust 包装器

关键设计决策:
- ✅ 静态链接(简单、可移植)
- ✅ build.rs 驱动(时序正确)
- ✅ bindgen 生成绑定(成熟可靠)
- ✅ 可选安全包装器(灵活实用)

项目目前处于实验阶段,适合:
- 探索 Rust-Zig 互操作
- 性能关键的小型模块
- 学习 FFI 和构建系统

不适合:
- 生产环境(尚未充分测试)
- 复杂类型互操作(功能有限)
- 需要稳定 API(仍在演进)

---

**版本**: 0.1.0
**最后更新**: 2024-01-04
**维护者**: AutoZig Contributors