port-c-module

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Port Module Skill

模块移植Skill

Guide for porting a C module to Rust.
将C模块移植到Rust的指南。

Arguments

参数

The module name to port should be provided as an argument (e.g.,
/port-module triemap
).
Module to port:
$ARGUMENTS
需要提供要移植的模块名称作为参数(例如:
/port-module triemap
)。
待移植模块:
$ARGUMENTS

Usage

使用场景

Use this skill when starting to port a C module to Rust.
当你开始将C模块移植到Rust时,可以使用此Skill。

Instructions

操作步骤

1. Analyze the C Code

1. 分析C代码

First, understand the C module you're porting (look for
$ARGUMENTS.c
and
$ARGUMENTS.h
in
src/
):
  • Read the
    .c
    and
    .h
    files in
    src/
  • Identify what is exposed by the header file:
    • Does the rest of the codebase have access to the inner fields of the data structures defined in this module?
    • Are types always passed by value or by reference? A mix?
    • Can the corresponding Rust types be passed over the FFI boundary?
  • Understand data structures and their lifetimes
  • Identify which types and functions this module imports from other modules:
    • Determine if those types are implemented in Rust or C
    • If those types are implemented in Rust, identify the relevant Rust crate
    • If those types are implemented in C, understand if it makes sense to port them first to Rust or if it's preferable to invoke the C implementation from Rust via FFI
  • Note any global state or Redis module interactions
  • Identify which tests under
    tests/
    are relevant to this module
首先,了解你要移植的C模块(在
src/
目录下查找
$ARGUMENTS.c
$ARGUMENTS.h
文件):
  • 阅读
    src/
    目录下的
    .c
    .h
    文件
  • 识别头文件暴露的内容:
    • 代码库的其他部分是否可以访问此模块中定义的数据结构的内部字段?
    • 类型是始终按值传递还是按引用传递?还是两者混合?
    • 对应的Rust类型能否通过FFI边界传递?
  • 了解数据结构及其生命周期
  • 识别此模块从其他模块导入的类型和函数:
    • 确定这些类型是用Rust还是C实现的
    • 如果这些类型是用Rust实现的,找到对应的Rust crate
    • 如果这些类型是用C实现的,判断是先将它们移植到Rust,还是通过FFI从Rust调用C实现更合适
  • 记录任何全局状态或Redis模块交互
  • 识别
    tests/
    目录下与此模块相关的测试用例

2. Define A Porting Plan

2. 制定移植计划

Create a
$ARGUMENTS_plan.md
file to outline the steps and decisions for porting the module. Determine if the C code should be modified, at this stage, to ease the porting process. For example:
  • Introduce getters and setters to avoid exposing inner fields of data structures defined in this module.
  • Split the module into smaller, more manageable parts.
创建一个
$ARGUMENTS_plan.md
文件,概述移植模块的步骤和决策。 判断此时是否需要修改C代码以简化移植过程。例如:
  • 引入getter和setter方法,避免暴露此模块中定义的数据结构的内部字段。
  • 将模块拆分为更小、更易管理的部分。

3. Create the Rust Crate

3. 创建Rust Crate

bash
cd src/redisearch_rs
cargo new $ARGUMENTS --lib
bash
cd src/redisearch_rs
cargo new $ARGUMENTS --lib

4. Implement Pure Rust Logic

4. 实现纯Rust逻辑

  • Create idiomatic Rust code
  • Add comprehensive tests
    • Ensure that all C/C++ tests have equivalent Rust tests
  • Document public APIs with doc comments
  • For performance sensitive code, create microbenchmarks using
    criterion
  • Use
    proptest
    for property-based testing where appropriate
  • Testing code should be written with the same care reserved to production code
  • 编写符合Rust风格的代码
  • 添加全面的测试用例
    • 确保所有C/C++测试都有对应的Rust测试
  • 使用文档注释记录公共API
  • 对于性能敏感的代码,使用
    criterion
    创建微基准测试
  • 适当时使用
    proptest
    进行基于属性的测试
  • 测试代码的编写应与生产代码一样严谨

5. Compare Rust API with C API

5. 对比Rust API与C API

  • Review the public API of the new Rust module against the C API in the header file
  • Ensure that differences can be bridged by adding appropriate wrappers or adapters
  • Go back to step 1 if discovered differences cannot be bridged without a re-design
  • 将新Rust模块的公共API与头文件中的C API进行对比
  • 确保可以通过添加适当的包装器或适配器来弥合差异
  • 如果发现无法通过重新设计之外的方式弥合差异,请回到步骤1

6. Create FFI Wrapper

6. 创建FFI包装器

Create an FFI crate to expose the new Rust module to the C codebase:
bash
cd src/redisearch_rs/c_entrypoint
cargo new ${ARGUMENTS}_ffi --lib
FFI crate should:
  • Expose
    #[unsafe(no_mangle)] pub extern "C" fn
    functions
  • Handle null pointers and error cases
  • Convert between C and Rust types safely
  • Document all unsafe blocks with
    // SAFETY:
    comments
创建一个FFI crate,将新的Rust模块暴露给C代码库:
bash
cd src/redisearch_rs/c_entrypoint
cargo new ${ARGUMENTS}_ffi --lib
FFI crate应满足:
  • 暴露
    #[unsafe(no_mangle)] pub extern "C" fn
    函数
  • 处理空指针和错误情况
  • 安全地在C和Rust类型之间进行转换
  • // SAFETY:
    注释记录所有unsafe代码块

7. Wire Up C Code

7. 对接C代码

  • Delete the C header file and its implementation
  • Update the rest of the C codebase to import the new Rust header wherever the old C header was used
C header files for Rust FFI crates are auto-generated. No need to use their full path in imports, use just their name (e.g.
#include $ARGUMENTS.h;
for
${ARGUMENTS}_ffi
)
  • 删除C头文件及其实现
  • 更新C代码库的其余部分,在原来导入旧C头文件的地方导入新的Rust头文件
Rust FFI crate的C头文件是自动生成的。导入时无需使用完整路径,只需使用其名称即可(例如,对于
${ARGUMENTS}_ffi
,使用
#include $ARGUMENTS.h;

8. Test The Integration

8. 测试集成

bash
./build.sh RUN_UNIT_TESTS               # C/C++ unit tests
./build.sh RUN_PYTEST                   # Integration tests
bash
./build.sh RUN_UNIT_TESTS               # C/C++单元测试
./build.sh RUN_PYTEST                   # 集成测试

Example: Well-Ported Module

示例:移植良好的模块

See
src/redisearch_rs/trie_rs/
for a high-quality example:
  • Pure Rust implementation with comprehensive docs
  • Extensive test coverage
  • Clean FFI boundary in
    c_entrypoint/trie_ffi/
查看
src/redisearch_rs/trie_rs/
目录,这是一个高质量的示例:
  • 纯Rust实现,带有全面的文档
  • 广泛的测试覆盖率
  • c_entrypoint/trie_ffi/
    目录中有清晰的FFI边界