Lukasz Anforowicz | dcdb524a | 2025-03-24 19:26:41 | [diff] [blame] | 1 | # Rust FFI |
| 2 | |
| 3 | This document tries to provide guidance for C++/Rust FFI. |
| 4 | CLs to improve this guidance are welcomed. |
| 5 | |
| 6 | ## General guidance |
| 7 | |
Lukasz Anforowicz | b878f00 | 2025-06-27 12:26:54 | [diff] [blame] | 8 | ### Supported FFI tools |
| 9 | |
Lukasz Anforowicz | dcdb524a | 2025-03-24 19:26:41 | [diff] [blame] | 10 | Chromium recommends using [the `cxx` crate](https://cxx.rs/) for C++/Rust FFI. |
| 11 | For introductory guidance, please see |
| 12 | [the `cxx` chapter](https://google.github.io/comprehensive-rust/chromium/interoperability-with-cpp.html) |
| 13 | in the Chromium day of the Comprehensive Rust course. |
| 14 | |
| 15 | Chromium also supports the following tools: |
| 16 | |
| 17 | * [`bindgen`](https://rust-lang.github.io/rust-bindgen/) - see |
| 18 | `//build/rust/rust_bindgen.gni` for usage instructions. |
| 19 | |
| 20 | At this point Chromium's `//build/rust/*.gni` templates do not support other FFI |
| 21 | tools like: |
| 22 | |
| 23 | * [`cbindgen`](https://github.com/mozilla/cbindgen) |
| 24 | * [`crubit`](https://github.com/google/crubit) |
| 25 | |
Lukasz Anforowicz | b878f00 | 2025-06-27 12:26:54 | [diff] [blame] | 26 | ### Related Rust idioms |
Lukasz Anforowicz | dcdb524a | 2025-03-24 19:26:41 | [diff] [blame] | 27 | |
Lukasz Anforowicz | b878f00 | 2025-06-27 12:26:54 | [diff] [blame] | 28 | We can't provide comprehensive, generic Rust guidance here, but let's |
| 29 | mention a few items that may be worth using in the FFI layer: |
| 30 | |
| 31 | * [`From`](https://doc.rust-lang.org/std/convert/trait.From.html) (or |
| 32 | [`TryFrom`](https://doc.rust-lang.org/std/convert/trait.TryFrom.html)) |
| 33 | is an idiomatic way of implementing a conversion between two types |
| 34 | (e.g. between FFI layer types like |
| 35 | [`ffi::ColorType`](https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/experimental/rust_png/ffi/FFI.rs;l=20-27;drc=70253db1ecfe261003756f0d81ae30929cc77ee4) |
| 36 | and third-party crate types like |
| 37 | [`png::ColorType`](https://docs.rs/png/0.17.6/png/enum.ColorType.html)). |
| 38 | See an example trait implementation |
| 39 | [here](https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/experimental/rust_png/ffi/FFI.rs;l=221-231;drc=70253db1ecfe261003756f0d81ae30929cc77ee4) |
| 40 | and an example of spelling the conversion as `foo.into()` |
| 41 | [here](https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/experimental/rust_png/ffi/FFI.rs;l=651;drc=70253db1ecfe261003756f0d81ae30929cc77ee4). |
| 42 | Note that when implementing the conversion for types defined in other crates, |
| 43 | you may need to work around the |
| 44 | [orphan rule](https://doc.rust-lang.org/reference/items/implementations.html#r-items.impl.trait.orphan-rule) |
| 45 | by implementing |
| 46 | [`Into`](https://doc.rust-lang.org/std/convert/trait.Into.html) |
| 47 | (or |
| 48 | [`TryInto`](https://doc.rust-lang.org/std/convert/trait.TryInto.html)) |
| 49 | trait instead. |
| 50 | |
| 51 | * [Question mark operator](https://doc.rust-lang.org/reference/expressions/operator-expr.html#r-expr.try) |
| 52 | is an ergonomic, idiomatic way for checking errors. |
| 53 | When using it in the FFI layer, this may require splitting some functions |
| 54 | into 1) one that returns `Result<T, E>` and uses `?` sugar, |
| 55 | and 2) one that translates `Result<T, E>` into FFI-friendly |
| 56 | status. See an example |
| 57 | [here](https://source.chromium.org/chromium/chromium/src/+/main:components/user_data_importer/utility/zip_ffi_glue.rs;l=297;drc=33f81e080c4c06d18880ec04832511bda3929972) |
| 58 | and |
| 59 | [here](https://source.chromium.org/chromium/chromium/src/+/main:components/user_data_importer/utility/zip_ffi_glue.rs;l=421-427;drc=33f81e080c4c06d18880ec04832511bda3929972). |
Lukasz Anforowicz | af3fafa | 2025-07-17 18:03:27 | [diff] [blame] | 60 | Additional example |
| 61 | [here](https://chromium-review.googlesource.com/c/chromium/src/+/6733098/18/components/user_data_importer/utility/zip_ffi_glue.rs#484) |
| 62 | avoids having to come up with a separate name by using an anonymous function. |
Lukasz Anforowicz | b878f00 | 2025-06-27 12:26:54 | [diff] [blame] | 63 | |
| 64 | * [`let Ok(foo) = ... else { ... }`](https://doc.rust-lang.org/rust-by-example/flow_control/let_else.html) |
| 65 | is another ergonomic way for checking errors. See |
| 66 | [an example here](https://source.chromium.org/chromium/chromium/src/+/main:components/user_data_importer/utility/zip_ffi_glue.rs;l=328-333;drc=33f81e080c4c06d18880ec04832511bda3929972). |
| 67 | |
| 68 | ## `cxx` guidance |
| 69 | |
| 70 | ### Best practices |
Lukasz Anforowicz | dcdb524a | 2025-03-24 19:26:41 | [diff] [blame] | 71 | |
| 72 | * Generate C++ side of bindings into a project-specific or crate-specific |
| 73 | `namespace`. For example: `#[cxx::bridge(namespace = "some_cpp_namespace")]`. |
| 74 | * Maintain binding declarations in a **single** `#[cxx::bridge]` declaration. |
| 75 | `cxx` supports reusing types across multiple `bridge`s, but there are some |
| 76 | rough edges. |
| 77 | |
Lukasz Anforowicz | b878f00 | 2025-06-27 12:26:54 | [diff] [blame] | 78 | ### Suggestions |
Lukasz Anforowicz | dcdb524a | 2025-03-24 19:26:41 | [diff] [blame] | 79 | |
| 80 | TODO: Provide some examples or suggestions on how to structure FFI bindings |
| 81 | (even if these suggestions wouldn't necessarily rise to the level of "best |
| 82 | practices"). |