Skip to content

Commit 0f0b572

Browse files
committed
readme english corrected
1 parent 4034e3e commit 0f0b572

File tree

1 file changed

+15
-18
lines changed

1 file changed

+15
-18
lines changed

README.md

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,42 +4,39 @@ A tool for separating the implementation of FFI interfaces from language-specifi
44

55
## Problem
66

7-
Making FFI (Foreing Function Interface) for Rust library is not an easy task. This involves making great amount of boilerplate code which wraps Rust API to `extern "C"` functions and `#[repr(C)]` structures.
8-
It's already hard for a single lagnuage, but when it's necessary to add more languages, situation complexifies.
7+
Making FFI (Foreign Function Interface) for a Rust library is not an easy task. This involves a large amount of boilerplate code that wraps the Rust API in `extern "C"` functions and `#[repr(C)]` structures.
8+
It's already hard for a single language, but when you need to add more languages, the situation becomes more complex.
99

10-
The root cause of this complexity is that in multi-language case is that we should either:
10+
The root cause of this complexity in a multi-language scenario is that you must either:
1111

12-
- Make separate crates for each language FFI. E.g we have Rust library "foo" and cdylib/staiclib crates "foo-c", "foo-csharp", "foo-java", etc. Each crate contains it's own independent repr-C wrappers. Code duplication is huge.
13-
- Generate all language-specific libraries from the same source. In this case we just replacing code duplication with code complexity: the single FFI library should conform all language targets.
12+
- Make separate crates for each language's FFI. For example, you have a Rust library "foo" and cdylib/staticlib crates "foo-c", "foo-csharp", "foo-java", etc. Each crate contains its own independent wrappers for "foo". Code duplication is huge.
13+
- Generate all language-specific libraries from the same source. In this case, you just replace code duplication with code complexity: the single FFI library must conform to all language targets.
1414

15-
One little example: the `cbindgen` supports wrapper types (`Option`, `MaybeUninit`) in the `extern "C"` functions. But the `csbindgen` (binding generator for C#) don't understand them. The following FFI function is good for C but can't be used for C#
15+
A small example: `cbindgen` supports wrapper types (`Option`, `MaybeUninit`) in `extern "C"` functions, but `csbindgen` (a binding generator for C#) doesn't understand them. The following FFI function works for C but can't be used for C#:
1616

1717
```rust
18-
#[repr(C)]
19-
struct Foo { ... }
20-
2118
#[no_mangle]
2219
pub extern "C" fn foo(dst: &mut MaybeUninit<Foo>, src: &Foo) { ... }
2320
```
2421

25-
And there are more such quirks which makes hard to support common source for multiple languages.
22+
And there are more such quirks, which make it hard to support a common source for multiple languages.
2623

2724
## Solution
2825

29-
The proposed solution is to make common Rust library (e.g. "foo-ffi") which wraps original "foo" library to FFI-compatible functions, but do not add `extern "C"` and `#[no_mangle]` modifiers to them. Instead it marks these funcions with `#[prebindgen]` macro.
26+
The proposed solution is to create a common Rust library (e.g., "foo-ffi") that wraps the original "foo" library in FFI-compatible functions, but does not add `extern "C"` and `#[no_mangle]` modifiers. Instead, it marks these functions with the `#[prebindgen]` macro.
3027

3128
```rust
3229
#[prebindgen]
3330
pub fn foo(dst: &mut MaybeUninit<Foo>, src: &Foo) { ... }
3431
```
3532

36-
The dependent language-specific crates ("foo-c", "foo-cs", etc) in this case contains only autogenerated code based on these marked functions, with added necessary `extern "C"` and `#[no_mangle]`, stipped out wrapper types, etc.
33+
The dependent language-specific crates ("foo-c", "foo-cs", etc.) in this case contain only autogenerated code based on these marked functions, with the necessary `extern "C"` and `#[no_mangle]` added, stripped-out wrapper types, etc.
3734

3835
### Architecture
3936

40-
Each element to export is marked in the source crate with the `#[prebindgen]` macro. When the source crate is compiled, these elements are written to an output directory. The `build.rs` of the destination crate reads these elements and creates FFI-compatible functions and proxy structures for them. The generated source file is included with the `include!()` macro in the dependent crate and parsed by the language binding generator (e.g., cbindgen).
37+
Each element to be exported is marked in the source crate with the `#[prebindgen]` macro. When the source crate is compiled, these elements are written to an output directory. The destination crate's `build.rs` reads these elements and creates FFI-compatible functions and proxy structures for them. The generated source file is included with the `include!()` macro in the dependent crate and parsed by the language binding generator (e.g., cbindgen).
4138

42-
It's important to keep in mind that `[build-dependencies]` and `[dependencies]` are different. The `#[prebindgen]` macro collects sources when compiling the `[build-dependencies]` instance of the source crate. Later, these sources are used to generate proxy calls to the `[dependencies]` instance, which may be built with a different feature set and for a different architecture. A set of assertions is put into the generated code to catch possible divergences, but it's the developer's job to manually resolve these errors.
39+
It's important to keep in mind that `[build-dependencies]` and `[dependencies]` are different. The `#[prebindgen]` macro collects sources when compiling the `[build-dependencies]` instance of the source crate. Later, these sources are used to generate proxy calls to the `[dependencies]` instance, which may be built with a different feature set and for a different architecture. A set of assertions is added to the generated code to catch possible divergences, but it's the developer's job to manually resolve these errors.
4340

4441
## Usage
4542

@@ -51,12 +48,12 @@ Mark structures and functions that are part of the FFI interface with the `prebi
5148
// example-ffi/src/lib.rs
5249
use prebindgen_proc_macro::prebindgen;
5350

54-
// Path to prebindgen output directory. The `build.rs` of the destination crate
51+
// Path to the prebindgen output directory; the destination crate's `build.rs`
5552
// reads the collected code from this path.
5653
pub const PREBINDGEN_OUT_DIR: &str = prebindgen_proc_macro::prebindgen_out_dir!();
5754

58-
// Features which the crate is compiled with. This constant is used
59-
// in the generated code to validate that it's compatible with the actual crate
55+
// Features with which the crate is compiled. This constant is used
56+
// in the generated code to validate that it's compatible with the actual crate.
6057
pub const FEATURES: &str = prebindgen_proc_macro::features!();
6158

6259
// Group structures and functions for selective handling
@@ -111,7 +108,7 @@ fn main() {
111108
// Create a source from the common FFI crate's prebindgen data
112109
let source = prebindgen::Source::new(example_ffi::PREBINDGEN_OUT_DIR);
113110

114-
// Create converter with transparent wrapper stripping
111+
// Create a converter with transparent wrapper stripping
115112
let converter = prebindgen::batching::FfiConverter::builder(source.crate_name())
116113
.edition(prebindgen::RustEdition::Edition2024)
117114
.strip_transparent_wrapper("std::mem::MaybeUninit")

0 commit comments

Comments
 (0)