diff --git a/text/3416-feature-metadata.md b/text/3416-feature-metadata.md index fd72a8c8a30..d8f84e53f9e 100644 --- a/text/3416-feature-metadata.md +++ b/text/3416-feature-metadata.md @@ -3,6 +3,7 @@ - RFC PR: [rust-lang/rfcs#3416](https://github.com/rust-lang/rfcs/pull/3416) - Rust Issue: [rust-lang/cargo#14157](https://github.com/rust-lang/cargo/issues/14157) +- Amendment adding a metadata schema: 2026-08-19 ## Summary @@ -121,6 +122,58 @@ 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. +### Metadata changes + +Because the `features` key in metadata output does not allow for additional +fields, a `features_v2` key is introduced. It follows the following rules: + +1. The type is an object with feature names as keys (same as `features`) and + objects as values. +2. The value objects *may* contain a key `enables`, a list of strings of + features to enable. With future RFCs, there will be additional keys. +3. If `enables` is not provided or is empty, the feature enables no other + features. +4. If `features` and `features_v2` are both present, they *must* have identical + feature names and enabled features. That is, the keys and values in + `features` are the same as the keys and `.enables`, respectively, in + `features_v2`. + +If a new `--format-version=2` is ever introduced, the content of `features` +will be replaced by `features_v2`. + +As an example, the following features table: + +```toml +[features] +foo = [] +# Note that `doc` is not accepted as part of this RFC, but it is included here +# to demonstrate additional keys. +bar = { enabled = ["foo"], doc = "simple docstring for bar" } +baz = { doc = "simple docstring for baz" } +``` + +Will include the following in its metadata: + +```json5 +"features": { + "foo": [], + "bar": ["foo"], + "baz": [] +}, +"features_v2": { + "foo": {}, + "bar": { "enables": ["foo"], "doc": "simple docstring for bar" }, + "baz": { "doc": "simple docstring for baz" } +} +``` + +The following `jq` query can be used to select `features_v2` or, if not +available, to get `features` in the same format: + +```jq +.features_v2 // (.features | map_values({enables: .})) +``` + ## Drawbacks [drawbacks]: #drawbacks @@ -151,6 +204,50 @@ like `dependencies`. However, we likely would want to prefer using new fields over adding more syntax, like with [disabling default features](https://github.com/rust-lang/cargo/issues/3126). +### Metadata + +There are a handful of alternatives for metadata design: + +* Instead of using `features_v2`, we could introduce metadata version 2 right + away. A new metadata version may want to include other changes outside of this + RFC's scope, so a way to work with existing metadata is preferred for now. +* Within `features_v2` JSON values, this RFC allows `enables` to be omitted + if empty: it could be always emitted instead. Metadata output is typically + machine-read so, given keys can easily be defaulted, requiring the key would + provide little value. For example, this simple `jq` query adds `"enables": []` + on keys where not present: + + ```jq + `.features_v2 | map_values({enables: .enables // []})` + ``` + + This decision is forward-compatible with unconditionally emitting `enables` + in the future (similar to accepting feature objects in `Cargo.toml` without + `enables`), so this decision does not block always emitting the key if desired + at some point. The reverse would not be true. +* `features_v2` could list only features that have additional metadata, relying + on the combination of `features` and `features_v2` to fully express the + metadata schema. Under this idea, the following could be considered valid: + + ```json5 + "features": { + "foo": [], + "bar": ["foo"], + }, + "features_v2": { + // No `"foo"` key, and no `enables` for `bar` + "bar": { "doc": "simple docstring for bar" }, + } + ``` + + This is not done because it conflicts with the idea that `features_v2` will + eventually replace `features`. By making `features_v2` contain all information + that `features` does, this transition will be easier for metadata consumers, + and the (small) complexity of object merging is avoided. +* `features_v2` could be called something else such as, from an informal + proposal, `features_metadata`. `features_v2` was selected to clearly convey + that it will be the form of `features` in a future metadata version. + ## Prior art [prior-art]: #prior-art