Summary

This RFC adds a “detailed” feature definition:

[features]
# same as `foo = []`
foo = { enables = [] }

This is to unblock the following RFCs:

Motivation

Features are widely used as a way to do things like reduce dependency count, gate std or alloc-dependent parts of code, or hide unstable API. Use is so common that many larger crates wind up with tens of feature gates, such as tokio with 24. Despite being a first class component of crate structure, there are some limitations that don’t have elegant solutions:

  • Documentation is difficult, often requiring library authors to manually manage a table of descriptions
  • There is no way to deprecate old features, as a way to help crates maintain semvar compliance
  • Features cannot be hidden from use in any way

This RFC proposes a plan that add that information to Cargo.toml, solving these problems.

Guide-level explanation

Usage is simple: features will be able to be specified as a table, instead of just a dependency array. This sample section of Cargo.toml shows new possibilities:

[features]
# Current configuration will continue to work
foo = []
# New configurations
bar = { enables = ["foo"], doc = "simple docstring here"}
baz = { enables = ["foo"], public = false}
qux = { enables = [], deprecated = true }
quux = { enables = [], deprecated = { since = "1.2.3", note = "don't use this!" } }

# Features can also be full tables if descriptions are longer
[features.corge]
enables = ["bar", "baz"]
doc = """
# corge

This could be a longer description of this feature
"""

The enables key is synonymous with the existing array, describing what other features are enabled by a given feature. For example, foo = ["dep:serde", "otherfeat"] will be identical to foo = { enables = ["dep:serde", "otherfeat"] }

All other keys are described in their individual RFCs.

General Implementation & Usage

Use cases for these new keys will likely develop with time, but one of the simplest applications is for information output with cargo add:

crab@rust foobar % cargo add regex
    Updating crates.io index
      Adding regex v1.7.3 to dependencies.
             Features:
             + perf             Enables all performance related features
             + perf-dfa         Enables the use of a lazy DFA for matching
             + perf-inline      Enables the use of aggressive inlining inside
                                match routines
             + perf-literal     Enables the use of literal optimizations for
                                speeding up matches
             + std              When enabled, this will cause regex to use the
                                standard library
             + unicode          Enables all Unicode features
             - deprecated (D)   Not a real feature, but it could be

    Updating crates.io index

Features like aho-corasick, memchr, or use_std would likely be public = false since they aren’t listed on the crate landing page.

Reference-level explanation

enables will take the place of the feature dependency array that currently exists. Semantics will remain unchanged.

This is a required key. If there are no requirements, an empty list should be provided (enables = []). This content is already in the index.

The availability of this new syntax should not require an MSRV bump. This means we need to make sure that if you use feature_name = [] in your Cargo.toml, then the published Cargo.toml should as well. However, we leave it as an implementation detail whether using feature_name = { enables =[] } requires an MSRV bump for users of your published package as we have not been actively streamlining the workflow for maintaining separate development and published MSRVs.

Drawbacks

  • Added complexity to Cargo. Parsing is trivial, but exact implementation details do add test surface area
  • Extending the Cargo.toml schema, particularly having a field support additional types, is disruptive to third-party parsers

Rationale and alternatives

This RFC has no impact on the Index Summaries. Future RFCs will need to work with that.

Naming

  • enables reads better on the line than enable
  • enables is likely an easier word for non-native speakers than activates
  • required is used elsewhere to say “this should automatically be available if requirements are met”

Schema

We could split the special feature syntax (dep:, etc) as distinct fields but we’d prefer trivial conversion from the “simple” schema to the “detailed” schema, like dependencies. However, we likely would want to prefer using new fields over adding more syntax, like with disabling default features.

Prior art

Unresolved questions

Future possibilities