From 0141c461da63b91a2dd85e2eea632ecc5254d47c Mon Sep 17 00:00:00 2001 From: yyc12345 Date: Thu, 6 Aug 2026 20:22:17 +0800 Subject: [PATCH] doc: writing design doc --- assets/c-friendly-ffi-design.md | 81 +++++++++++++++++++++++++++++++++ docs/header-instruction.md | 0 docs/type-map-instruction.md | 0 3 files changed, 81 insertions(+) create mode 100644 assets/c-friendly-ffi-design.md delete mode 100644 docs/header-instruction.md delete mode 100644 docs/type-map-instruction.md diff --git a/assets/c-friendly-ffi-design.md b/assets/c-friendly-ffi-design.md new file mode 100644 index 0000000..70d1644 --- /dev/null +++ b/assets/c-friendly-ffi-design.md @@ -0,0 +1,81 @@ +# C-friendly FFI Design + +This document is a guide for authoring Rust libraries that expose a C-friendly FFI +and distributing them as ordinary CMake/pkg-config packages. It covers how to design +C-friendly FFI signatures, how to pass primitive types, enums, strings and +Rust-specific constructs such as `Option` and `Result` across the boundary, and how +to write the accompanying C/C++ header files. + +## Allowed Data Types + +Under this section we discuss which data types are allowed to appear in an FFI +interface, how to pass them across the boundary, and how to convert Rust data types +into these allowed types. + +### Primitive Type Conversion + +This subsection covers the conversion of primitive types. The rules described here +apply to both parameter and return value positions. + +#### Types Allowed to Cross the Boundary Directly + +The following types are allowed to be passed directly across the FFI boundary. The +left column lists the Rust type and the right column lists the corresponding C/C++ +type. + +| Rust | C/C++ | +|------|-------| +| `bool` | `bool` | +| `f32` | `float` | +| `f64` | `double` | +| `i8` | `int8_t` | +| `i16` | `int16_t` | +| `i32` | `int32_t` | +| `i64` | `int64_t` | +| `u8` | `uint8_t` | +| `u16` | `uint16_t` | +| `u32` | `uint32_t` | +| `u64` | `uint64_t` | +| `usize` | `uintptr_t` | +| `isize` | `intptr_t` | + +#### Required Header Files in the Generated C/C++ Headers + +The generated C/C++ header files must include the appropriate header files for the +types listed above. + +- In C, the `bool` type is provided by ``. C++ supports `bool` natively + and does not need any header file. +- In C, the integer types are provided by ``. In C++, they are provided + by ``. +- In C, the `uintptr_t` and `intptr_t` types are provided by ``. In C++, + they are provided by ``. +- The floating-point types do not require any header file. + +#### The u128 and i128 Problem + +The `u128` and `i128` types have very poor support in the C/C++ standard libraries. +Therefore they cannot be passed directly across the FFI boundary. + +To transfer data of these types, refer to the later section about passing opaque +structs. + +#### The char Problem + +In C/C++, the type closest to the Rust `char` type is `char32_t`. However, the Rust +`char` type only holds valid Unicode scalar values, which conflicts with `char32_t` +being any 32-bit unsigned integer. + +In addition, the Rust official documentation explicitly states that the `char` type +does not have FFI safety, so it cannot be used as a value passed across the FFI +boundary. + +The solution is to use the Rust `u32` type for passing. Under this scheme: + +- On the Rust side: + - The function signature uses `u32` as the parameter type. + - For input parameters, use `char::try_from` to perform a fallible conversion that + validates the incoming character. + - For output parameters, use `u32::from` for the conversion. +- On the C/C++ header side: + - The function signature uses `char32_t` as the parameter type. diff --git a/docs/header-instruction.md b/docs/header-instruction.md deleted file mode 100644 index e69de29..0000000 diff --git a/docs/type-map-instruction.md b/docs/type-map-instruction.md deleted file mode 100644 index e69de29..0000000