Rust API Design Principles

This policy lays out guidelines for designing the user-facing parts of core Rust libraries in Chromium. It is meant to provide guidance on relative priorities to help decide between different possible designs.

Note: These guidelines are aimed at core Rust libraries (e.g. //base) which expect to see broad, general use across Chromium. They may or may not apply to code designed for more specialized parts of the codebase. Conversely, since these guidelines are aimed at libraries in Chromium, they have different considerations than the Rust standard library, which aims to support all possible use cases.

These design principles are undergoing constant development; expect more to be added in the future. Existing guidelines should change only rarely.

Core Design Goals

The first of these goals is the most important; beyond that, these goals are not ordered.

  1. APIs must promote the use of Rust in Chromium. If Chromium developers are unwilling to use an API (because it’s unergonomic, not performant, etc), then it is a bad design.
  2. Therefore…
    1. APIs should be performant, imposing as little runtime overhead as possible.
    2. APIs should be ergonomic, requiring as little boilerplate as possible.
    3. APIs should be idiomatic Rust, to make it easy for Rust developers to use it, and for C++ developers to familiarize themselves with Rust.
  3. APIs should minimize the potential for misuse, especially misuse with security implications (such as undefined behavior).

Compatibility with the Generic Rust Guidelines

  1. APIs should follow the Rust API Guidelines

(Un)Safety

  1. APIs should not require users to use unsafe code if at all possible.
    1. This includes unsafe functions, as well as those that require unsafe in order to use the result (e.g. by returning a raw pointer).
    2. Examples of exceptions are code that imposes such a large performance hit that it’s deemed unacceptable to use, or that requires patterns that are annoying enough that developers will try to avoid using them.
  2. If we provide an unsafe API, we should try to provide an equivalent safe API and encourage its use when possible.
  3. Internal use of unsafe is acceptable, so long it is encapsulated and not exposed to the user, and there isn’t an easy safe alternative.

C/C++ Interop via FFI

Chromium has three options available for interoperation with C and C++:

  1. Bindgen: Automatically generates bindings for C code. Supported by the Rust maintainers.
  2. Cxx: Generates user-specified bindings to C++ code. A third-party crate with minimal new feature development.
  3. Crubit: Automatically generates bindings for C++ code. Supported by the Crubit team at Google. In active development and not yet fully supported in Chromium.

For more information, see ffi.md. In the long run, we prefer Crubit, but since it's not yet fully supported we use Cxx for now. Therefore, these guidelines aim to minimize the migration cost from Cxx to Crubit in the future.

  1. For C bindings, use bindgen.
  2. For C++ bindings, use Crubit if possible, and Cxx otherwise.
  3. Wrap FFI functions in safe, idiomatic Rust APIs.
  4. When using Cxx, keep APIs minimal, to minimize the surface area of a future migration to Crubit.