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.