Rust

This describes Rust-specific guidance for checking code into //piper/third_party/rust.

IMPORTANT: Read go/thirdparty first.

Introduction

This file describes how to add code to the //piper/third_party/rust directory.

Most third-party Rust code will originate from crates.io, and belongs in the //third_party/rust/ namespace at its crate name in a subdirectory based on the version (see versions below).

Licensing

As anywhere in //third_party, the guidance from go/thirdpartylicenses applies.

Crates should come with a license specification in the Cargo.toml file. The tool for importing new crates will automatically fill in the appropriate license metadata in third_party, but if that's missing you'll need to fill that in manually. You'll need to add a LICENSE file manually if there's not one included with the source distribution, as the metadata specification in Cargo.toml isn't enough for the third-party tooling to check.

Many open-source Rust packages are dual-licensed under the Apache 2.0 and MIT licenses, following the example of the Rust language implementation. Both of these licenses are "notice" type licenses, but we have received guidance from emailremoved@ that there is a slight preference for Apache 2.0.

See go/thirdpartylicenses#same for more general guidance on dual-licensed code.

Versions

Because Rust handles multiple versions of a crate in a binary gracefully, we allow 3 versions of a crate in //third_party/rust without prior permission. Beyond 3 versions requires an exception granted by third-party-removed and third-party-removed, and will require a justification. Only one version of a crate should be used by first-party Google code at any time, except during the one-month upgrade window specified by go/thirdparty. The limit of one version exposed to google3 must be enforced with visibility restrictions. Versions with security or soundness defects are disallowed.

Versions should be checked in to a directory corresponding to the "version epoch" of the version. That is, a 1.x.y version of the foo library lives in //third_party/rust/foo/v1/..., with //third_party/rust/foo/v1:foo as the default target. For pre-1.0 versions, the version epoch is the first two components, so 0.4.x goes in a v0_4 directory. Only one version is allowed per epoch unless you get a third-party-removed and third-party-removed exemption.

Note that if you're adding the first version of a crate, you'll need to add //third_party/rust/foo/{OWNERS,METADATA} to keep compliance tooling happy. Those files have constant content, so you can copy them from any neighboring directory.

Procedural Macros (aka proc-macro crates)

Procedural macros are a powerful part of the Rust ecosystem allowing syntax extensions. The trade-off is that they are unhygienic and capable of executing arbitrary code at build time. When being imported into third-party, the reviewer should be familiar with writing procedural macros and able to prevent these pitfalls. proc-macros that depend on environmental context (for example: environment variables, network access, git repos, etc.) are disallowed.

Unsafe code

The unsafe keyword in Rust is a necessary feature. Most code does not need it, and instead should be using a library which handles the problem in a safe way. We shouldn't ban unsafe completely (it’s needed for FFI, and to do some things efficiently, and for direct access to compiler intrinsics), so we have some unsafe experts ensure incoming uses of unsafe are reasonable.

Adding or updating third-party packages

Unit tests

We require any unit tests for a crate to be made part of the third-party-removed Presubmit target. This is to ensure that upgrades of any crate are reasonably safe without substantial testing burdens.

If package needs modification

Prefer upstream contributions followed by automated imports.