ralph-flow-pi 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +428 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +56 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/prompts.d.ts +25 -0
- package/dist/commands/prompts.d.ts.map +1 -0
- package/dist/commands/prompts.js +249 -0
- package/dist/commands/prompts.js.map +1 -0
- package/dist/commands/tools.d.ts +47 -0
- package/dist/commands/tools.d.ts.map +1 -0
- package/dist/commands/tools.js +633 -0
- package/dist/commands/tools.js.map +1 -0
- package/dist/engine/check-bash.d.ts +121 -0
- package/dist/engine/check-bash.d.ts.map +1 -0
- package/dist/engine/check-bash.js +373 -0
- package/dist/engine/check-bash.js.map +1 -0
- package/dist/engine/check.d.ts +47 -0
- package/dist/engine/check.d.ts.map +1 -0
- package/dist/engine/check.js +298 -0
- package/dist/engine/check.js.map +1 -0
- package/dist/engine/core.d.ts +153 -0
- package/dist/engine/core.d.ts.map +1 -0
- package/dist/engine/core.js +1984 -0
- package/dist/engine/core.js.map +1 -0
- package/dist/engine/lock.d.ts +27 -0
- package/dist/engine/lock.d.ts.map +1 -0
- package/dist/engine/lock.js +121 -0
- package/dist/engine/lock.js.map +1 -0
- package/dist/engine/runner.d.ts +108 -0
- package/dist/engine/runner.d.ts.map +1 -0
- package/dist/engine/runner.js +510 -0
- package/dist/engine/runner.js.map +1 -0
- package/dist/engine/skills.d.ts +53 -0
- package/dist/engine/skills.d.ts.map +1 -0
- package/dist/engine/skills.js +109 -0
- package/dist/engine/skills.js.map +1 -0
- package/dist/engine/step-tools.d.ts +22 -0
- package/dist/engine/step-tools.d.ts.map +1 -0
- package/dist/engine/step-tools.js +45 -0
- package/dist/engine/step-tools.js.map +1 -0
- package/dist/engine/types.d.ts +136 -0
- package/dist/engine/types.d.ts.map +1 -0
- package/dist/engine/types.js +20 -0
- package/dist/engine/types.js.map +1 -0
- package/dist/headless.d.ts +57 -0
- package/dist/headless.d.ts.map +1 -0
- package/dist/headless.js +318 -0
- package/dist/headless.js.map +1 -0
- package/dist/pi/adapter.d.ts +135 -0
- package/dist/pi/adapter.d.ts.map +1 -0
- package/dist/pi/adapter.js +231 -0
- package/dist/pi/adapter.js.map +1 -0
- package/dist/pi/interactive.d.ts +28 -0
- package/dist/pi/interactive.d.ts.map +1 -0
- package/dist/pi/interactive.js +58 -0
- package/dist/pi/interactive.js.map +1 -0
- package/dist/pi/tui.d.ts +12 -0
- package/dist/pi/tui.d.ts.map +1 -0
- package/dist/pi/tui.js +12 -0
- package/dist/pi/tui.js.map +1 -0
- package/dist/tui/app.d.ts +25 -0
- package/dist/tui/app.d.ts.map +1 -0
- package/dist/tui/app.js +47 -0
- package/dist/tui/app.js.map +1 -0
- package/dist/tui/embed.d.ts +42 -0
- package/dist/tui/embed.d.ts.map +1 -0
- package/dist/tui/embed.js +38 -0
- package/dist/tui/embed.js.map +1 -0
- package/dist/tui/extension.d.ts +88 -0
- package/dist/tui/extension.d.ts.map +1 -0
- package/dist/tui/extension.js +114 -0
- package/dist/tui/extension.js.map +1 -0
- package/dist/tui/history-editor.d.ts +38 -0
- package/dist/tui/history-editor.d.ts.map +1 -0
- package/dist/tui/history-editor.js +55 -0
- package/dist/tui/history-editor.js.map +1 -0
- package/dist/tui/launcher.d.ts +24 -0
- package/dist/tui/launcher.d.ts.map +1 -0
- package/dist/tui/launcher.js +97 -0
- package/dist/tui/launcher.js.map +1 -0
- package/dist/tui/render.d.ts +87 -0
- package/dist/tui/render.d.ts.map +1 -0
- package/dist/tui/render.js +266 -0
- package/dist/tui/render.js.map +1 -0
- package/dist/tui/run-app.d.ts +49 -0
- package/dist/tui/run-app.d.ts.map +1 -0
- package/dist/tui/run-app.js +317 -0
- package/dist/tui/run-app.js.map +1 -0
- package/dist/tui/run-model.d.ts +162 -0
- package/dist/tui/run-model.d.ts.map +1 -0
- package/dist/tui/run-model.js +280 -0
- package/dist/tui/run-model.js.map +1 -0
- package/dist/tui/run-view.d.ts +71 -0
- package/dist/tui/run-view.d.ts.map +1 -0
- package/dist/tui/run-view.js +167 -0
- package/dist/tui/run-view.js.map +1 -0
- package/dist/tui/welcome-header.d.ts +40 -0
- package/dist/tui/welcome-header.d.ts.map +1 -0
- package/dist/tui/welcome-header.js +90 -0
- package/dist/tui/welcome-header.js.map +1 -0
- package/package.json +55 -0
- package/skills/c-to-rust-audit/SKILL.md +67 -0
- package/skills/c-to-rust-implement/SKILL.md +151 -0
- package/skills/c-to-rust-implement/references/c-to-rust-patterns.md +86 -0
- package/skills/c-to-rust-implement/references/conditional-compilation.md +47 -0
- package/skills/c-to-rust-implement/references/crate-reference.md +15 -0
- package/skills/c-to-rust-implement/references/error-strategies.md +80 -0
- package/skills/c-to-rust-implement/references/inline-asm.md +37 -0
- package/skills/c-to-rust-plan/SKILL.md +166 -0
- package/skills/c-to-rust-plan/references/detection-commands.md +66 -0
- package/skills/c-to-rust-test-gen/SKILL.md +130 -0
- package/skills/c-to-rust-test-gen/references/proptest-patterns.md +81 -0
- package/skills/c-to-rust-test-gen/references/test-porting.md +56 -0
- package/skills/c-to-rust-validate/SKILL.md +121 -0
- package/skills/everything2rust-audit/SKILL.md +69 -0
- package/skills/everything2rust-design/SKILL.md +121 -0
- package/skills/everything2rust-design/references/domain-playbooks.md +68 -0
- package/skills/everything2rust-design/references/paradigm-map.md +99 -0
- package/skills/everything2rust-implement/SKILL.md +101 -0
- package/skills/everything2rust-spec/SKILL.md +86 -0
- package/skills/everything2rust-spec/references/oracle-strategies.md +96 -0
- package/skills/everything2rust-survey/SKILL.md +99 -0
- package/skills/everything2rust-test-gen/SKILL.md +68 -0
- package/skills/everything2rust-test-gen/references/harness-patterns.md +186 -0
- package/skills/everything2rust-validate/SKILL.md +85 -0
- package/workflows/c-to-rust.yaml +202 -0
- package/workflows/everything2rust.yaml +259 -0
- package/workflows/loop.yaml +68 -0
- package/workflows/spec.yaml +183 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# C→Rust 惯用模式转换表
|
|
2
|
+
|
|
3
|
+
C 语义到 Rust 惯用模式的专家级对照。实现 C 到 Rust 翻译时的权威参考。
|
|
4
|
+
|
|
5
|
+
## 内存管理
|
|
6
|
+
|
|
7
|
+
| C 模式 | Rust 翻译 | 说明 |
|
|
8
|
+
|--------|----------|------|
|
|
9
|
+
| `T* p = malloc(n * sizeof(T))` | `let p: Vec<T> = vec![T::default(); n]` 或 `Vec::with_capacity(n)` | Vec 管理堆内存 |
|
|
10
|
+
| `free(p)` | 让 `Drop` 自动处理——返回有主类型,不存裸指针 | 析构自动调用 |
|
|
11
|
+
| `memcpy(dst, src, n)` | `dst[..n].copy_from_slice(&src[..n])` | 前提:dst/src 是切片 |
|
|
12
|
+
| `memset(p, 0, n)` | `p[..n].fill(0)` | 或直接用 `vec![0u8; n]` |
|
|
13
|
+
| `realloc(p, new_sz)` | 新建 Vec,复制旧内容,丢弃旧 | 在安全 Rust 中无直接等价物 |
|
|
14
|
+
| `memcmp(a, b, n)` | `a[..n] == b[..n]` | 切片比较,短路求值 |
|
|
15
|
+
|
|
16
|
+
## 错误处理
|
|
17
|
+
|
|
18
|
+
| C 模式 | Rust 翻译 | 说明 |
|
|
19
|
+
|--------|----------|------|
|
|
20
|
+
| `return -1` / `return ERR_CODE` | `Err(Error::ErrCode)` | 枚举变体对应错误码 |
|
|
21
|
+
| `if (ret < 0) goto cleanup` | `let result = fallible_op()?;` | `?` 操作符自动传播错误 |
|
|
22
|
+
| `errno = EINVAL` | `Err(Error::InvalidInput { details })` | 带上下文 |
|
|
23
|
+
| 出参传错误 `int* err` | 返回 `Result<T, Error>`,无出参 | 多返回值用元组 |
|
|
24
|
+
| `goto cleanup` 集中清理 | RAII:`Drop` 处理清理 | 作用域退出自动执行 |
|
|
25
|
+
|
|
26
|
+
## 数据结构
|
|
27
|
+
|
|
28
|
+
| C 模式 | Rust 翻译 | 说明 |
|
|
29
|
+
|--------|----------|------|
|
|
30
|
+
| 柔性数组 `struct { int len; T data[]; }` | `struct { data: Vec<T> }` | len 由 `data.len()` 派生 |
|
|
31
|
+
| 标签联合 `struct { int type; union { A a; B b; }; }` | `enum { VariantA(A), VariantB(B) }` | 穷尽匹配,无隐式 fallthrough |
|
|
32
|
+
| 链表 `struct node { T data; node* next; }` | `std::collections::LinkedList<T>` 或 `Vec<T>` | 大多数情况 Vec 更高效 |
|
|
33
|
+
| 不透明句柄 `typedef struct ctx ctx_t;` | `pub struct Ctx { /* 私有字段 */ }` + `impl Ctx` | 封装 |
|
|
34
|
+
| 位域 `struct { unsigned flag : 1; }` | `bitflags` crate 或手动位运算 + 命名常量 | Rust 无原生位域 |
|
|
35
|
+
|
|
36
|
+
## 控制流
|
|
37
|
+
|
|
38
|
+
| C 模式 | Rust 翻译 | 说明 |
|
|
39
|
+
|--------|----------|------|
|
|
40
|
+
| `for (int i = 0; i < n; i++)` | `for item in &slice` 或 `for (i, item) in slice.iter().enumerate()` | 迭代器 |
|
|
41
|
+
| `while (*p != '\0') p++` | `s.find('\0')` 或 `s.bytes().position(\|b\| b == 0)` | 不用手动推进指针 |
|
|
42
|
+
| `switch(val) { case X: ... }` | `match val { X => ..., Y => ... }` | 穷尽匹配,无 fallthrough |
|
|
43
|
+
| 函数指针表 / vtable | `trait` + `Box<dyn Trait>` 或 `enum` 分发 | trait 更安全 |
|
|
44
|
+
| `goto` 错误处理 | RAII + `?` 操作符 | Rust 无 goto |
|
|
45
|
+
|
|
46
|
+
## 并发与状态
|
|
47
|
+
|
|
48
|
+
| C 模式 | Rust 翻译 | 说明 |
|
|
49
|
+
|--------|----------|------|
|
|
50
|
+
| `static mut STATE: T` | `static STATE: OnceLock<Mutex<T>>` | 线程安全全局状态 |
|
|
51
|
+
| `pthread_mutex_lock/unlock` | `std::sync::Mutex<T>` 的 `.lock().unwrap()` | 自动释放 |
|
|
52
|
+
| 线程局部 `__thread T x` | `std::cell::RefCell` + `thread_local!` 宏 | 线程局部可变 |
|
|
53
|
+
| 一次性初始化 `if (!init) { init(); init=1; }` | `OnceLock::get_or_init(\|\| { ... })` | 线程安全 |
|
|
54
|
+
|
|
55
|
+
## 转换示例
|
|
56
|
+
|
|
57
|
+
```rust
|
|
58
|
+
// C 源码:
|
|
59
|
+
// int codec_encode(const uint8_t* in, size_t in_len, uint8_t* out, size_t* out_len) {
|
|
60
|
+
// if (!in || !out || !out_len) return CODEC_ERR_INVALID;
|
|
61
|
+
// if (*out_len < in_len + 4) return CODEC_ERR_OVERFLOW;
|
|
62
|
+
// // ... 编码逻辑 ...
|
|
63
|
+
// *out_len = encoded_len;
|
|
64
|
+
// return 0;
|
|
65
|
+
// }
|
|
66
|
+
|
|
67
|
+
// Rust 实现:
|
|
68
|
+
pub fn encode(input: &[u8], output: &mut [u8]) -> Result<usize, Error> {
|
|
69
|
+
// if (!in) → 切片引用不可能为 null(由类型系统保证)
|
|
70
|
+
if output.len() < input.len() + 4 {
|
|
71
|
+
return Err(Error::Overflow);
|
|
72
|
+
}
|
|
73
|
+
// ... 编码逻辑(原样翻译算法,但用 Rust 语法)...
|
|
74
|
+
Ok(encoded_len)
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## 常见陷阱
|
|
79
|
+
|
|
80
|
+
- C 的 int 返回 0=成功 / -1=失败 → Rust 的 `Result<(), Error>`
|
|
81
|
+
- C 的 size_t 出参 → Rust 的 `Result<usize, Error>` 直接返回长度
|
|
82
|
+
- C 的 NULL 检查 → Rust 引用不可能为 null,去掉所有 `if (!ptr)` 检查
|
|
83
|
+
- C 的数组 + 长度参数对 → Rust 切片 `&[T]`,长度由 `.len()` 获取
|
|
84
|
+
- C 的 void* 泛型 → Rust 泛型 `<T>` 或 trait bound
|
|
85
|
+
- C 的 #ifdef 条件编译 → Rust 的 `#[cfg(...)]` 或 feature flag
|
|
86
|
+
- C 的宏函数 → Rust 的 `macro_rules!` 或普通泛型函数
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# 条件编译翻译指南
|
|
2
|
+
|
|
3
|
+
C 项目中的 `#ifdef` / `#ifndef` / `#if` 翻译为 Rust 的 `#[cfg(...)]` 或 feature flag。
|
|
4
|
+
|
|
5
|
+
## 简单映射
|
|
6
|
+
|
|
7
|
+
| C 预处理 | Rust 等价 |
|
|
8
|
+
|----------|----------|
|
|
9
|
+
| `#ifdef _WIN32` | `#[cfg(target_os = "windows")]` |
|
|
10
|
+
| `#ifdef __linux__` | `#[cfg(target_os = "linux")]` |
|
|
11
|
+
| `#ifdef __APPLE__` | `#[cfg(target_os = "macos")]` |
|
|
12
|
+
| `#ifdef __x86_64__` | `#[cfg(target_arch = "x86_64")]` |
|
|
13
|
+
| `#ifdef __aarch64__` | `#[cfg(target_arch = "aarch64")]` |
|
|
14
|
+
| `#ifdef DEBUG` | `#[cfg(debug_assertions)]` |
|
|
15
|
+
| `#ifdef FEATURE_X` | `#[cfg(feature = "x")]` + Cargo.toml `[features]` |
|
|
16
|
+
| `#if !defined(X)` | `#[cfg(not(feature = "x"))]` |
|
|
17
|
+
| `#if defined(A) && !defined(B)` | `#[cfg(all(feature = "a", not(feature = "b")))]` |
|
|
18
|
+
| `#if defined(A) \|\| defined(B)` | `#[cfg(any(feature = "a", feature = "b"))]` |
|
|
19
|
+
| `#else` | 单独的 `#[cfg(not(...))]` 块 |
|
|
20
|
+
| `#if VERSION >= 3` | 无法直接映射——用 feature flag 替代 |
|
|
21
|
+
|
|
22
|
+
## 多条件互斥编译
|
|
23
|
+
|
|
24
|
+
C 代码 `#if defined(A) ... #elif defined(B) ... #else ...`:
|
|
25
|
+
|
|
26
|
+
```rust
|
|
27
|
+
#[cfg(feature = "a")]
|
|
28
|
+
fn platform_impl() { /* A 实现 */ }
|
|
29
|
+
|
|
30
|
+
#[cfg(all(not(feature = "a"), feature = "b"))]
|
|
31
|
+
fn platform_impl() { /* B 实现 */ }
|
|
32
|
+
|
|
33
|
+
#[cfg(all(not(feature = "a"), not(feature = "b")))]
|
|
34
|
+
fn platform_impl() { /* 默认实现 */ }
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Feature Flag 声明
|
|
38
|
+
|
|
39
|
+
在 `Cargo.toml` 中声明:
|
|
40
|
+
```toml
|
|
41
|
+
[features]
|
|
42
|
+
default = []
|
|
43
|
+
a = []
|
|
44
|
+
b = []
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**注意**:plan.json 的 api_inventory 会记录条件编译影响哪些函数——实现时确保所有条件路径都有对应的 Rust 分支。
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Rust Crate 速查表
|
|
2
|
+
|
|
3
|
+
根据 C 模式选择合适的 Rust crate。仅在 C 源码中有对应模式时引入,优先用标准库。
|
|
4
|
+
|
|
5
|
+
| C 模式 | 推荐 crate | Cargo.toml | 使用场景 |
|
|
6
|
+
|--------|-----------|-----------|---------|
|
|
7
|
+
| 位域/标志位 | `bitflags` | `bitflags = "2"` | `struct { unsigned flag : 1; }` |
|
|
8
|
+
| 安全 transmute | `bytemuck` | `bytemuck = { version = "1", features = ["derive"] }` | 字节流到 struct 的安全转换 |
|
|
9
|
+
| 小数组/VLA | `smallvec` | `smallvec = "1"` | 栈优先的变长数组 |
|
|
10
|
+
| 解析器/编解码 | `winnow` | `winnow = "0.6"` | 逐字节推进的解析循环 |
|
|
11
|
+
| 低级网络 | `socket2` | `socket2 = "0.5"` | socket/bind/accept 等 |
|
|
12
|
+
| FFI 边界 | `libc` | `libc = "0.2"` | 仅在 FFI 边界,包裹在 unsafe 块中 |
|
|
13
|
+
| 零拷贝 | `zerocopy` | `zerocopy = "0.7"` | 从字节切片安全读取 struct |
|
|
14
|
+
|
|
15
|
+
**原则**:如果 C 项目本身不依赖外部 C 库,优先用标准库——不引入额外依赖。
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Error Type Composition Strategies
|
|
2
|
+
|
|
3
|
+
Two strategies for composing error types across Rust modules during C-to-Rust translation.
|
|
4
|
+
|
|
5
|
+
## Strategy A — Layered Error (Recommended for shallow dependency chains)
|
|
6
|
+
|
|
7
|
+
Each module defines its own `Error` enum. Upper layers compose lower layers via `#[from]`.
|
|
8
|
+
|
|
9
|
+
**选择条件(满足全部即可选 A)**:
|
|
10
|
+
- 依赖深度 ≤ 3(Error 嵌套从 A→B→C 不超过 3 层)
|
|
11
|
+
- 模块间无同名错误类别(如两个模块都有 `Io(std::io::Error)`)
|
|
12
|
+
- main.rs 不需要统一处理所有错误
|
|
13
|
+
|
|
14
|
+
```rust
|
|
15
|
+
// src/codec.rs
|
|
16
|
+
#[derive(Error, Debug, PartialEq)]
|
|
17
|
+
pub enum Error {
|
|
18
|
+
#[error("codec: invalid input")]
|
|
19
|
+
InvalidInput,
|
|
20
|
+
#[error("codec: output buffer overflow")]
|
|
21
|
+
Overflow,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// src/storage.rs — depends on codec
|
|
25
|
+
use crate::codec;
|
|
26
|
+
|
|
27
|
+
#[derive(Error, Debug, PartialEq)]
|
|
28
|
+
pub enum Error {
|
|
29
|
+
#[error("storage: IO error: {0}")]
|
|
30
|
+
Io(String),
|
|
31
|
+
#[error(transparent)]
|
|
32
|
+
Codec(#[from] codec::Error), // transparent forward
|
|
33
|
+
#[error("storage: data corruption")]
|
|
34
|
+
Corruption,
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`lib.rs` re-exports:
|
|
39
|
+
```rust
|
|
40
|
+
pub use error::Error;
|
|
41
|
+
pub mod codec;
|
|
42
|
+
pub mod storage;
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Cross-module `?` operator auto-converts via `#[from]`, no manual `map_err` needed.
|
|
46
|
+
|
|
47
|
+
## Strategy B — Flat Error (Recommended for deep dependency chains)
|
|
48
|
+
|
|
49
|
+
When dependency chains are deep or multiple modules share error categories, layered Error nesting becomes verbose. Use a single top-level unified Error:
|
|
50
|
+
|
|
51
|
+
```rust
|
|
52
|
+
// src/error.rs
|
|
53
|
+
#[derive(Error, Debug)]
|
|
54
|
+
pub enum AppError {
|
|
55
|
+
#[error("codec: {0}")]
|
|
56
|
+
Codec(#[from] codec::Error),
|
|
57
|
+
#[error("storage: {0}")]
|
|
58
|
+
Storage(#[from] storage::Error),
|
|
59
|
+
#[error("network: {0}")]
|
|
60
|
+
Network(#[from] network::Error),
|
|
61
|
+
#[error("internal: {0}")]
|
|
62
|
+
Internal(String),
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### When to Choose Strategy B (any one condition is sufficient)
|
|
67
|
+
|
|
68
|
+
- **Dependency depth > 3**(Error 从 A→B→C→D 嵌套超过 3 层时,调用方需写 4+ 层 `map_err`)
|
|
69
|
+
- **Multiple modules share the same error category**(如两个模块都产生 IO/Parse 类错误,用 Flat Error 避免重复定义)
|
|
70
|
+
- **Main.rs / top-level needs to handle all errors uniformly**(统一错误处理,不分模块来源)
|
|
71
|
+
- **Module count > 10**(辅助指标,仅当同时满足前面任一条件时才作为决定因素)
|
|
72
|
+
|
|
73
|
+
### Decision Table
|
|
74
|
+
|
|
75
|
+
| 依赖深度 | 同名错误类别 | 模块数 | 推荐策略 |
|
|
76
|
+
|---------|------------|-------|---------|
|
|
77
|
+
| ≤ 3 | 0 | ≤ 10 | Strategy A |
|
|
78
|
+
| ≤ 3 | ≥ 1 | any | Strategy B |
|
|
79
|
+
| > 3 | any | any | Strategy B |
|
|
80
|
+
| any | any | > 10 | 倾向 Strategy B |
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# 内联汇编处理策略
|
|
2
|
+
|
|
3
|
+
C 项目中的内联汇编(`__asm__` / `__asm` / `asm`)需要特殊处理。
|
|
4
|
+
|
|
5
|
+
## 检测命令
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
grep -rn '__asm__\|__asm\b\|asm[ \t]*(' <source_c_dir>/src/ --include='*.c'
|
|
9
|
+
grep -rn '__asm__\|__asm\b\|asm[ \t]*(' <source_c_dir>/inc/ --include='*.h'
|
|
10
|
+
grep -rn '__asm\b' <source_c_dir>/src/ --include='*.c' # MSVC 语法
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## 评估替代方案(按优先级)
|
|
14
|
+
|
|
15
|
+
1. **Rust 标准库内联函数**:`std::arch::x86_64::*`(如 `_mm_add_ps`)——稳定、安全
|
|
16
|
+
2. **`core::arch::asm!()` 宏**:需 nightly Rust + `#![feature(asm)]`
|
|
17
|
+
3. **FFI 桥接**:将汇编提取为独立 C 文件,通过 FFI 调用
|
|
18
|
+
|
|
19
|
+
## asm!() 使用规范
|
|
20
|
+
|
|
21
|
+
若必须使用 `asm!()`:
|
|
22
|
+
- 包裹在最小 `unsafe` 块中,写清 `// SAFETY:` 注释
|
|
23
|
+
- 汇编操作数约束完整(in/out/lateout/clobber)
|
|
24
|
+
- 在 plan.json 对应模块的 notes 中记录
|
|
25
|
+
- 供 validate Gate 2 审计
|
|
26
|
+
|
|
27
|
+
## SIMD 优化
|
|
28
|
+
|
|
29
|
+
若汇编用于 SIMD 性能优化:
|
|
30
|
+
- 优先尝试 `std::simd`(nightly)或 `std::arch` 内联函数
|
|
31
|
+
- 提供纯 Rust fallback:`#[cfg(not(target_feature = "..."))]`
|
|
32
|
+
|
|
33
|
+
## 标记规则
|
|
34
|
+
|
|
35
|
+
- plan.json 中对应模块标记 `difficulty: "global"` + `notes: "含内联汇编"`
|
|
36
|
+
- plan.json 的 `inline_asm_modules` 数组包含该模块名
|
|
37
|
+
- `recommended_crates` 中添加 `"asm-shim"` 标记
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: c-to-rust-plan
|
|
3
|
+
description: 分析 C 项目,探测真实布局/测试框架/构建系统,提取 API,划分依赖分层,产出 plan.json、api-inventory.md 和 function-contracts.md。在 c-to-rust 工作流的 analyze 步骤触发。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
你是接手一个陌生 C 代码库的工程师。目标:先**探测**项目的真实形态(不要假设目录结构),再产出机器可读的实现计划(plan.json)、人类可读的 API 参考(api-inventory.md)和语义参考(function-contracts.md)。这份计划驱动后续全部步骤:测试基线、TDD 实现顺序、独立审查、最终验收。
|
|
7
|
+
|
|
8
|
+
## 输入 / 输出
|
|
9
|
+
|
|
10
|
+
> `<产出目录>` = DO 提示词「产出目录」一节给出的路径(形如 `.ralph-flow/artifacts/<任务摘要>-<后缀>/`)。
|
|
11
|
+
|
|
12
|
+
- 输入:C 项目路径(source_c_dir)、输出项目名(默认 = 源码目录名 + `_rust`)
|
|
13
|
+
- 输出:
|
|
14
|
+
- `<产出目录>/plan.json` — 探测结果 + 模块/分层/API/难度/crate
|
|
15
|
+
- `<产出目录>/api-inventory.md` — 人类可读:每个 C 公开函数 → 拟议 Rust 签名
|
|
16
|
+
- `<产出目录>/function-contracts.md` — 复杂函数的语义要点,给后续 audit 步骤用
|
|
17
|
+
|
|
18
|
+
## 核心原则
|
|
19
|
+
|
|
20
|
+
- **先探测再假设** — 目录布局、测试框架、构建系统都从项目实际情况探测,不硬编码 `src/`、`inc/`、`test_`
|
|
21
|
+
- **头文件是公开 API 的权威来源**;**源文件是内部(static)函数的权威来源**
|
|
22
|
+
- **按内聚性分组** — 共享类型/数据结构的函数归入同一 Rust 模块
|
|
23
|
+
- **简单模块优先** — 无依赖的纯数据变换放 layer 1,先积累惯性
|
|
24
|
+
- **传递闭包** — 递归解析 #include 链构建依赖图
|
|
25
|
+
- **优先标准库** — 能用 std 就不引外部 crate
|
|
26
|
+
|
|
27
|
+
## 执行流程
|
|
28
|
+
|
|
29
|
+
所有探测/提取的精确命令见 **[references/detection-commands.md](references/detection-commands.md)**。下面只讲每步要产出什么。
|
|
30
|
+
|
|
31
|
+
### 1. 探测项目布局(不要假设)
|
|
32
|
+
|
|
33
|
+
用 find 列出真实的源/头/测试文件位置,归纳出源码目录、头文件目录、测试目录(可能是 `src/`+`include/`、`lib/`、扁平根目录等任意组合),写入 `project_layout`。测试文件特征:在 `test/`、`tests/`、`t/` 目录或文件名含 `test`/`spec`/`check`。
|
|
34
|
+
|
|
35
|
+
### 2. 探测测试框架(决定 baseline 如何移植测试)
|
|
36
|
+
|
|
37
|
+
grep 框架特征识别 Unity / CMocka / Check / CuTest / 自定义 main / 朴素 `test_` 约定,写入 plan.json `test_framework`:
|
|
38
|
+
`{ "name": "unity|cmocka|check|cutest|custom|plain", "test_files": [...], "assert_macros": [...], "test_decl_pattern": "...", "runner_entry": "..." }`。
|
|
39
|
+
|
|
40
|
+
### 3. 探测构建系统(决定如何编译 C 测试)
|
|
41
|
+
|
|
42
|
+
识别 Makefile / CMake / meson 等,写入 plan.json `build_system`:`{ "type", "build_cmd", "test_cmd", "test_binary", "include_flags", "cc" }`。无构建系统则给出手动编译命令(含正确的 `-I<headerdir>`)。
|
|
43
|
+
|
|
44
|
+
### 4. 提取公开 API(从头文件)
|
|
45
|
+
|
|
46
|
+
ctags 主方案 + grep 兜底,对探测到的头文件目录提取每个公开函数:名称、返回类型、参数、错误约定(返回码 / errno / 出参)。额外识别回调签名(函数指针类型)和条件编译块(`#ifdef`/`#if`,记录宏名)。
|
|
47
|
+
|
|
48
|
+
### 5. 提取内部函数 + 检测高级特性
|
|
49
|
+
|
|
50
|
+
grep 提取 static 内部函数;检测内联汇编(→ difficulty=global,记入 inline_asm_modules)与 C11/C17 高级特性(_Generic/_Atomic/_Alignas/restrict/setjmp/longjmp/alloca/VLA/volatile/signal)。结果记入每个模块的 `c_advanced_features`(见第 8 步 schema)。
|
|
51
|
+
|
|
52
|
+
### 6. 构建模块依赖图
|
|
53
|
+
|
|
54
|
+
按 .c 的 `#include` 关系建有向图:A.c include B.h ⇒ A 直接依赖 B;取传递闭包。
|
|
55
|
+
叶子模块(无人 include 其头)→ layer 1;只依赖 layer 1 → layer 2;以此类推。无环。
|
|
56
|
+
|
|
57
|
+
### 7. 难度分级 + crate 推荐
|
|
58
|
+
|
|
59
|
+
| 难度 | C 特征 | 实现顺序 |
|
|
60
|
+
|------|--------|---------|
|
|
61
|
+
| **trivial** | 纯数据变换,无堆分配无状态 | 最先 |
|
|
62
|
+
| **owned** | malloc/free 对,单一所有者 → Box/Vec/Drop | 早期 |
|
|
63
|
+
| **stateful** | init/deinit + 内部状态 → struct+Drop | 中期 |
|
|
64
|
+
| **callback** | 函数指针控制反转 → FnMut/trait 对象 | 后期 |
|
|
65
|
+
| **global** | static 可变 / 内联汇编 → OnceLock/Mutex 或重构 | 最后 |
|
|
66
|
+
|
|
67
|
+
crate 仅在 C 源码存在对应模式时引入,优先 std:位域→`bitflags`;字节转换→`bytemuck`;小数组/VLA→`smallvec`;解析器→`winnow` 或手写;FFI 边界→`libc`(仅 FFI 用)。
|
|
68
|
+
|
|
69
|
+
### 8. 写出 plan.json
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"output_name": "<project>_rust",
|
|
74
|
+
"output_dir": "<projectDir 下的绝对路径>/<project>_rust",
|
|
75
|
+
"source_c_dir": "/abs/path/C-project",
|
|
76
|
+
"c_test_dir": "/abs/path/探测到的测试目录",
|
|
77
|
+
"project_layout": {
|
|
78
|
+
"source_dirs": ["src"], "header_dirs": ["include"], "test_dirs": ["tests"]
|
|
79
|
+
},
|
|
80
|
+
"test_framework": {
|
|
81
|
+
"name": "unity", "test_files": ["tests/test_codec.c"],
|
|
82
|
+
"assert_macros": ["TEST_ASSERT_EQUAL", "TEST_ASSERT_TRUE"],
|
|
83
|
+
"test_decl_pattern": "void test_<name>(void)", "runner_entry": "RUN_TEST"
|
|
84
|
+
},
|
|
85
|
+
"build_system": {
|
|
86
|
+
"type": "make", "build_cmd": "make clean && make", "test_cmd": "./test_runner",
|
|
87
|
+
"test_binary": "./test_runner", "include_flags": "-Iinclude", "cc": "gcc"
|
|
88
|
+
},
|
|
89
|
+
"layers": [["codec"], ["storage", "network"], ["api"]],
|
|
90
|
+
"modules": [
|
|
91
|
+
{
|
|
92
|
+
"name": "codec", "c_files": ["src/codec.c"], "c_headers": ["include/codec.h"],
|
|
93
|
+
"target_file": "src/codec.rs", "layer": 1,
|
|
94
|
+
"depends_on": [], "transitive_depends_on": [],
|
|
95
|
+
"difficulty": "trivial",
|
|
96
|
+
"public_functions": ["encode", "decode", "checksum"],
|
|
97
|
+
"internal_functions": ["validate_header", "calc_padding"],
|
|
98
|
+
"types": ["codec_ctx_t"],
|
|
99
|
+
"error_codes": ["CODEC_ERR_INVALID", "CODEC_ERR_OVERFLOW"],
|
|
100
|
+
"recommended_crates": [],
|
|
101
|
+
"c_advanced_features": {
|
|
102
|
+
"has_generic": false, "has_atomic": false, "has_alignas": false,
|
|
103
|
+
"has_restrict": false, "has_setjmp": false, "has_alloca": false,
|
|
104
|
+
"has_vla": false, "has_volatile": false, "has_signal": false
|
|
105
|
+
},
|
|
106
|
+
"notes": ""
|
|
107
|
+
}
|
|
108
|
+
],
|
|
109
|
+
"api_inventory": [
|
|
110
|
+
{
|
|
111
|
+
"c_name": "codec_encode", "rust_name": "encode",
|
|
112
|
+
"c_signature": "int codec_encode(const uint8_t* in, size_t in_len, uint8_t* out, size_t* out_len)",
|
|
113
|
+
"rust_signature": "fn encode(input: &[u8], output: &mut [u8]) -> Result<usize, CodecError>",
|
|
114
|
+
"module": "codec", "error_variants": ["CodecInvalid", "CodecOverflow"],
|
|
115
|
+
"condition": null, "notes": "in_len/out_len 由切片长度替代"
|
|
116
|
+
}
|
|
117
|
+
],
|
|
118
|
+
"conditional_compilation": {
|
|
119
|
+
"detected_macros": ["_WIN32", "__linux__", "USE_SSL"],
|
|
120
|
+
"feature_flags": { "use_ssl": { "c_macro": "USE_SSL", "rust_cfg": "feature = \"ssl\"" } }
|
|
121
|
+
},
|
|
122
|
+
"inline_asm_modules": [],
|
|
123
|
+
"completed_modules": []
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
字段约束:
|
|
128
|
+
- 所有路径绝对路径;`output_dir` 必须在工作区(projectDir)下,确保后续步骤可访问
|
|
129
|
+
- `layers`:数组的数组,下标 0 = layer 1(无依赖),每个模块名恰好出现在一层
|
|
130
|
+
- `depends_on` 只引用更低层(无环);`transitive_depends_on` 是传递闭包
|
|
131
|
+
- `difficulty` ∈ {trivial, owned, stateful, callback, global}
|
|
132
|
+
- `internal_functions`:该模块全部 static 函数名(可空)
|
|
133
|
+
- `c_advanced_features`:全部字段初始化为布尔
|
|
134
|
+
- `project_layout`、`test_framework`、`build_system` 必须反映**探测结果**,非默认值
|
|
135
|
+
- `completed_modules` 初始化为空数组
|
|
136
|
+
- modules 覆盖每个非测试、非 vendor/third_party 的 .c
|
|
137
|
+
|
|
138
|
+
### 9. 写出 api-inventory.md
|
|
139
|
+
|
|
140
|
+
人类可读表格:公开 API 表(C 签名 → Rust 签名 → 错误变体)、内部函数表、推荐 crate 表、依赖分层表。
|
|
141
|
+
|
|
142
|
+
### 10. 写出 function-contracts.md
|
|
143
|
+
|
|
144
|
+
对 difficulty 为 **stateful**、**callback**、**global** 的模块中**最有翻译风险的函数**,记录其语义要点。不必逐函数全部记录——关注那些逻辑复杂、有多阶段操作、有非平凡状态转换、或有容易遗漏的错误路径的函数。
|
|
145
|
+
|
|
146
|
+
对每个记录的函数,包含:
|
|
147
|
+
- **做什么**(一句话)
|
|
148
|
+
- **核心逻辑**(自然的语言描述,不是伪代码)
|
|
149
|
+
- **关键不变性**(该函数保证的、调用方依赖的)
|
|
150
|
+
- **错误/异常分支**(不只是 happy path)
|
|
151
|
+
- **与其他函数的协作**(谁调用它、它调用谁、共享什么状态)
|
|
152
|
+
|
|
153
|
+
trivial 和 owned 难度的模块通常不需要逐函数记录,模块级概述即可。
|
|
154
|
+
|
|
155
|
+
这个文件是给后续 audit 步骤用的——让审计师知道 "这个函数应该做什么",然后去 Rust 实现中验证它确实做了这些。
|
|
156
|
+
|
|
157
|
+
## 完成标准
|
|
158
|
+
|
|
159
|
+
- plan.json 合法 JSON,modules 覆盖所有非测试/非 vendor 的 .c
|
|
160
|
+
- 每模块含 public_functions、internal_functions、difficulty、recommended_crates、transitive_depends_on、c_advanced_features
|
|
161
|
+
- plan.json 含 output_name、output_dir(工作区内绝对路径)、source_c_dir、c_test_dir、project_layout、test_framework、build_system、conditional_compilation、inline_asm_modules、completed_modules
|
|
162
|
+
- project_layout/test_framework/build_system 来自真实探测
|
|
163
|
+
- 依赖分层无环,传递闭包正确
|
|
164
|
+
- api-inventory.md 列出所有 C 公开函数及拟议 Rust 签名
|
|
165
|
+
- function-contracts.md 对复杂函数记录了语义要点
|
|
166
|
+
- 三个文件写入 `<产出目录>/`
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# 探测命令参考(c-to-rust-plan)
|
|
2
|
+
|
|
3
|
+
## 目录
|
|
4
|
+
|
|
5
|
+
- 1. 项目布局探测
|
|
6
|
+
- 2. 测试框架探测
|
|
7
|
+
- 3. 构建系统探测
|
|
8
|
+
- 4. 公开 API 提取(头文件)
|
|
9
|
+
- 5. 内部函数 + 高级特性检测
|
|
10
|
+
|
|
11
|
+
## 1. 项目布局探测
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
find <source_c_dir> -name '*.c' -not -path '*/vendor/*' -not -path '*/third_party/*' -not -path '*/3rd*/*'
|
|
15
|
+
find <source_c_dir> -name '*.h' -not -path '*/vendor/*' -not -path '*/third_party/*'
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
由实际结果归纳源码目录、头文件目录、测试目录。布局可能是 `src/`+`include/`、`lib/`、扁平根目录或任意组合。
|
|
19
|
+
测试文件特征:在 `test/`、`tests/`、`t/` 目录,或文件名含 `test`/`spec`/`check`。
|
|
20
|
+
|
|
21
|
+
## 2. 测试框架探测
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
grep -rln 'unity.h\|UNITY_BEGIN\|RUN_TEST\|TEST_ASSERT' <test_dir> # Unity
|
|
25
|
+
grep -rln 'cmocka.h\|cmocka_unit_test\|assert_int_equal' <test_dir> # CMocka
|
|
26
|
+
grep -rln '<check.h>\|START_TEST\|ck_assert' <test_dir> # Check
|
|
27
|
+
grep -rln 'CuTest\|CuAssert' <test_dir> # CuTest
|
|
28
|
+
grep -rln 'int main' <test_dir> # 自定义 main + assert()
|
|
29
|
+
grep -rln 'void test_\|static void test_' <test_dir> # 朴素 test_ 约定
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## 3. 构建系统探测
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
ls <source_c_dir>/{Makefile,makefile,CMakeLists.txt,configure,meson.build,*.mk} 2>/dev/null
|
|
36
|
+
grep -rn 'cc\|gcc\|clang\|-I' <source_c_dir>/Makefile* 2>/dev/null | head
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
记录 type、build_cmd、test_cmd、test_binary、include_flags(正确的 `-I<headerdir>`)、cc。无构建系统则给手动编译命令。
|
|
40
|
+
|
|
41
|
+
## 4. 公开 API 提取(头文件)
|
|
42
|
+
|
|
43
|
+
ctags 主方案(处理函数指针返回值、多行声明),grep 兜底:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
ctags -x --c-kinds=pf --format=2 <header_dir>/*.h 2>/dev/null # 函数原型/定义
|
|
47
|
+
ctags -x --c-kinds=stue --format=2 <header_dir>/*.h 2>/dev/null # struct/typedef/union/enum
|
|
48
|
+
ctags -x --c-kinds=d --format=2 <header_dir>/*.h 2>/dev/null # 宏常量
|
|
49
|
+
grep -nE '^\s*\w+(\s+\*?\s*\w+)+\([^)]*\)\s*;' <header_dir>/*.h # grep 兜底
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
每个公开函数提取:名称、返回类型、参数、错误约定(返回码 / errno / 出参)。
|
|
53
|
+
额外识别回调签名(函数指针类型)和条件编译块(`#ifdef`/`#if`,记录宏名)。
|
|
54
|
+
|
|
55
|
+
## 5. 内部函数 + 高级特性检测
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
grep -rnE '^\s*static\s+\w+\s+\w+\(' <source_dir> # static 内部函数
|
|
59
|
+
grep -rn '__asm__\|__asm\b\|\basm[ \t]*(' <source_dir> <header_dir> # 内联汇编 → difficulty=global
|
|
60
|
+
# C11/C17 特性(Rust 无直接等价,提前发现避免返工)
|
|
61
|
+
grep -rn '_Generic(\|_Atomic\b\|_Alignas\b\|\brestrict\b\|setjmp\|longjmp\|alloca(\|\bvolatile\b\|\bsignal\b' <source_dir> <header_dir>
|
|
62
|
+
grep -rnE '[a-zA-Z_]\s+[a-zA-Z_]+\[[a-zA-Z_]+\]\s*;' <source_dir> # 变长数组 VLA
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
每个特性结果记入模块 `c_advanced_features` 的对应布尔字段:
|
|
66
|
+
has_generic / has_atomic / has_alignas / has_restrict / has_setjmp / has_alloca / has_vla / has_volatile / has_signal。
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: c-to-rust-test-gen
|
|
3
|
+
description: 创建 C-to-Rust 迁移的 TDD 红阶段基线:Rust binary 骨架、API 桩、按 C 测试框架移植全部测试、属性测试。在 c-to-rust 工作流的 baseline 步骤触发。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
你在搭 TDD 的红阶段。产出一个 Rust 项目:每个 C 测试都有对应的 Rust `#[test]`,所有 API 桩编译通过,测试因 `todo!()` 而运行时失败。这个基线是**契约**——实现正确时测试自动转绿。
|
|
7
|
+
|
|
8
|
+
## 输入 / 输出
|
|
9
|
+
|
|
10
|
+
> `<产出目录>` = DO 提示词「产出目录」一节给出的路径(形如 `.ralph-flow/artifacts/<任务摘要>-<后缀>/`)。
|
|
11
|
+
|
|
12
|
+
- 输入:`plan.json`(含 project_layout、test_framework、build_system)、C 源码与测试
|
|
13
|
+
- 输出:
|
|
14
|
+
- `<output_name>_rust/` — Cargo binary 项目:`src/main.rs`、`src/lib.rs`、`src/types.rs`(完整定义)、
|
|
15
|
+
`src/error.rs`、`src/<module>.rs`(桩)、`tests/oracle_*.rs`、`tests/prop_*.rs`
|
|
16
|
+
- 状态:`cargo build` 通过,`cargo test` 有 FAILED(红阶段,todo!() panic)
|
|
17
|
+
|
|
18
|
+
## 核心原则(superpower TDD)
|
|
19
|
+
|
|
20
|
+
- **先看 C 测试变绿** — 移植前用 build_system 跑通 C 测试套件;红阶段的"红"必须来自我们的 Rust 桩,不是来自坏掉的 C 基线
|
|
21
|
+
- **100% 测试覆盖移植** — 每个 C 测试用例 → 一个 Rust `#[test]`,断言含义逐一保留
|
|
22
|
+
- **API 签名在此确定** — 桩签名是给实现阶段的契约。若实现中发现签名确需调整,那是正常工程演进,直接改签名并同步更新依赖它的测试与 plan.json(不必推倒重来)
|
|
23
|
+
- **错误路径必须测** — 每个 Err 变体都有触发场景
|
|
24
|
+
- **属性测试兜底** — 对数据变换函数用 roundtrip/确定性/空输入不崩溃做 proptest;对有状态 API 用操作序列状态机保证不 panic
|
|
25
|
+
|
|
26
|
+
## 执行流程
|
|
27
|
+
|
|
28
|
+
复制此清单并随进度勾选:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
RED 基线进度:
|
|
32
|
+
- [ ] 1. C 测试套件确认全绿
|
|
33
|
+
- [ ] 2. cargo new binary 项目,Cargo.toml 配好依赖
|
|
34
|
+
- [ ] 3. types.rs / error.rs 完整定义;lib.rs 声明全部模块
|
|
35
|
+
- [ ] 4. 每个公开函数 + internal_function 建 todo!("module::fn") 桩
|
|
36
|
+
- [ ] 5. 按框架移植全部 C 测试 → oracle_*.rs(断言精度保留)
|
|
37
|
+
- [ ] 6. 补属性测试 prop_*.rs
|
|
38
|
+
- [ ] 7. 验证红阶段:cargo build 通过、cargo test FAILED、桩数≥函数数
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 1. 确认 C 测试套件全绿
|
|
42
|
+
|
|
43
|
+
用 plan.json `build_system` 的命令编译并运行 C 测试:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
cd <source_c_dir>
|
|
47
|
+
<build_cmd> && <test_cmd>; echo "exit=$?"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
退出码必须为 0。若不通过:先修 C 项目,或在 plan.json 标注排除的损坏测试(记 notes)。
|
|
51
|
+
|
|
52
|
+
### 2. 初始化 Rust binary 项目
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
cargo new <output_name>_rust # 在工作区内,cargo 会自动 git init
|
|
56
|
+
cd <output_name>_rust
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`Cargo.toml`:
|
|
60
|
+
```toml
|
|
61
|
+
[package]
|
|
62
|
+
name = "<output_name>_rust"
|
|
63
|
+
edition = "2021"
|
|
64
|
+
|
|
65
|
+
[dependencies]
|
|
66
|
+
thiserror = "1"
|
|
67
|
+
# 仅在 plan.json recommended_crates 出现时才加(bitflags/bytemuck/smallvec/...)
|
|
68
|
+
|
|
69
|
+
[dev-dependencies]
|
|
70
|
+
proptest = "1"
|
|
71
|
+
rstest = "0.18"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`src/main.rs`:薄入口,解析 `--help` 与子命令,转调 lib。
|
|
75
|
+
`src/lib.rs`:`pub mod` 声明 plan.json 的全部模块。
|
|
76
|
+
|
|
77
|
+
### 3. 定义共享类型与错误(完整,非桩)
|
|
78
|
+
|
|
79
|
+
- `src/types.rs`:把头文件中跨模块共享的 struct/enum 翻译成完整 Rust 定义。模块私有类型放各自模块文件。
|
|
80
|
+
- `src/error.rs`:从 plan.json `api_inventory[].error_variants` 汇总,thiserror 派生:
|
|
81
|
+
|
|
82
|
+
```rust
|
|
83
|
+
use thiserror::Error;
|
|
84
|
+
#[derive(Error, Debug, PartialEq)]
|
|
85
|
+
pub enum AppError {
|
|
86
|
+
#[error("codec: invalid input")] CodecInvalid,
|
|
87
|
+
#[error("codec: output buffer overflow")] CodecOverflow,
|
|
88
|
+
// 每个 C 错误码一个变体
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### 4. 创建 API 桩
|
|
93
|
+
|
|
94
|
+
每个模块 `src/<module>.rs`:用 plan.json `api_inventory[].rust_signature` 写正确签名,函数体 = `todo!("<module>::<fn>")`。internal_functions 同样建桩。桩签名是契约。
|
|
95
|
+
|
|
96
|
+
### 5. 按测试框架移植 C 测试
|
|
97
|
+
|
|
98
|
+
读 plan.json `test_framework`,把每个 C 测试用例映射成 `tests/oracle_<module>.rs` 里的 `#[test]`。
|
|
99
|
+
各框架的用例声明、断言宏,以及"断言语义精确归一表"(精度不降级)见
|
|
100
|
+
**[references/test-porting.md](references/test-porting.md)**。
|
|
101
|
+
错误路径:对每个 error_variant,确认至少一个测试触发它。
|
|
102
|
+
|
|
103
|
+
### 6. 属性测试
|
|
104
|
+
|
|
105
|
+
`tests/prop_<module>.rs`:数据变换函数 → roundtrip / 确定性 / 空输入不崩溃;有状态 API → 操作序列状态机 proptest(保证不 panic)。
|
|
106
|
+
模板与模式见 **[references/proptest-patterns.md](references/proptest-patterns.md)**。
|
|
107
|
+
|
|
108
|
+
### 7. 验证红阶段状态
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
cargo build # 必须通过——所有桩编译
|
|
112
|
+
cargo test 2>&1 # 必须出现 FAILED——红阶段(todo!() panic,不是编译错误)
|
|
113
|
+
|
|
114
|
+
# 红阶段完整性:桩数 ≥ 函数数
|
|
115
|
+
TODO_COUNT=$(grep -rc 'todo!' src/ --include='*.rs' | awk -F: '{s+=$2} END{print s}')
|
|
116
|
+
FUNC_COUNT=$(jq '[.api_inventory|length] + [.modules[].internal_functions|length] | add' <产出目录>/plan.json)
|
|
117
|
+
echo "stubs=$TODO_COUNT funcs=$FUNC_COUNT" # 需 TODO_COUNT >= FUNC_COUNT
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
若 `cargo test` 全绿,说明桩写错了(应有 `todo!()`)。每个 `todo!()` 必须含 `"module::fn"` 标签便于实现阶段定位。
|
|
121
|
+
|
|
122
|
+
## 完成标准
|
|
123
|
+
|
|
124
|
+
- `cargo build` 通过;`cargo test` 有 FAILED(todo!() panic,非编译错误)
|
|
125
|
+
- Cargo.toml 是 binary target,含 thiserror + proptest/rstest
|
|
126
|
+
- `src/main.rs`、`src/lib.rs`(声明全部模块)、`src/types.rs`(字段完整)、`src/error.rs` 存在
|
|
127
|
+
- 每个 C 测试用例都有对应 Rust `#[test]`,断言精度保留
|
|
128
|
+
- `TODO_COUNT >= FUNC_COUNT`,每个 `todo!()` 含 `module::fn` 标签
|
|
129
|
+
- 每个公开函数至少被一个 oracle 或 property 测试覆盖;每个 error_variant 至少有一个触发测试
|
|
130
|
+
- 每个模块有对应的 `tests/oracle_<module>.rs` 和 `tests/prop_<module>.rs`
|