Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions doc/book/src/reference/unstable.md

@weihanglo weihanglo Sep 27, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, @darkraider01! One small policy-related question before merging this.

Just noticed a codex/ branch among your recent Cargo works. Using LLM for things like understanding codebase is completely fine. However, our policy has some requirements that if PR was originally created by LLM, a pre-arranged reviewer and a disclosure are required. Also, communication shouldn't be LLM generated at all.

Could you let me know roughly how you used Codex/LLM here, and whether any of them was originally generated by LLM? Thanks!

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hi yes, sorry that was something very silly, i mostly use LLMS to review my work to find any other gaps left, so that just my lazy work when also asked it to push it after reviewing. That's why it was in draft, im sorry for the troubles!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries. Just be sure to follow the policy also for future contributions.

Original file line number Diff line number Diff line change
Expand Up @@ -2407,6 +2407,20 @@ foo = { enables = [] }

The required `enables` field is equivalent to the array-of-strings syntax.

With `feature-metadata` enabled, `cargo metadata --format-version 1` includes a
`features_v2` field alongside the existing `features` field. It mirrors every
feature as an object with an `enables` array and other metadata fields:

```json
"features_v2": {
"foo": { "enables": [] },
"serde": {
"enables": ["dep:serde"],
"doc": "Enables support for serialization via serde."
}
}
```

For other metadata fields, see the subsections below.

### feature-documentation
Expand Down
46 changes: 37 additions & 9 deletions src/workspace/package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use std::time::{Duration, Instant};

use crate::util::data_structures::{HashMap, HashSet};
use anyhow::Context as _;
use cargo_util_schemas::manifest::{Hints, RustVersion};
use cargo_util_schemas::manifest::{FeatureDefinition, Hints, RustVersion};
use futures::FutureExt;
use futures::TryStreamExt;
use futures::stream::FuturesUnordered;
Expand All @@ -31,8 +31,8 @@ use crate::util::network::retry::{Retry, RetryResult};
use crate::util::{self, GlobalContext, Progress, ProgressStyle, internal};
use crate::workspace::dependency::DepKind;
use crate::workspace::{
CliUnstable, Dependency, Features, Manifest, PackageId, PackageIdSpec, SerializedDependency,
SourceId, Target,
CliUnstable, Dependency, Feature, Features, Manifest, PackageId, PackageIdSpec,
SerializedDependency, SourceId, Target,
};
use crate::workspace::{Summary, Workspace};

Expand Down Expand Up @@ -78,6 +78,8 @@ pub struct SerializedPackage {
dependencies: Vec<SerializedDependency>,
targets: Vec<Target>,
features: BTreeMap<InternedString, Vec<InternedString>>,
#[serde(skip_serializing_if = "Option::is_none")]
features_v2: Option<BTreeMap<InternedString, SerializedFeature>>,
manifest_path: PathBuf,
metadata: Option<toml::Value>,
publish: Option<Vec<String>>,
Expand All @@ -98,6 +100,13 @@ pub struct SerializedPackage {
hints: Option<Hints>,
}

#[derive(Serialize)]
struct SerializedFeature {
enables: Vec<InternedString>,
#[serde(skip_serializing_if = "Option::is_none")]
doc: Option<String>,
}

impl Package {
/// Creates a package from a manifest and its location.
pub fn new(manifest: Manifest, manifest_path: &Path) -> Package {
Expand Down Expand Up @@ -210,12 +219,30 @@ impl Package {
.filter(|t| t.src_path().is_path())
.cloned()
.collect();
// Convert Vec<FeatureValue> to Vec<InternedString>
let crate_features = summary
.features()
.iter()
.map(|(k, v)| (*k, v.iter().map(|fv| fv.to_string().into()).collect()))
.collect();
let manifest_features = self.manifest().normalized_toml().features();
let mut crate_features = BTreeMap::new();
let mut features_v2 = cargo_features
.is_enabled(Feature::feature_metadata())
.then(BTreeMap::new);
for (k, v) in summary.features() {
let enables: Vec<InternedString> = v.iter().map(|fv| fv.to_string().into()).collect();
if let Some(features_v2) = &mut features_v2 {
let doc = manifest_features
.and_then(|mf| mf.get(k.as_str()))
.and_then(|feat_def| match feat_def {
FeatureDefinition::Metadata(meta) => meta.doc.clone(),
FeatureDefinition::Array(_) => None,
});
features_v2.insert(
*k,
SerializedFeature {
enables: enables.clone(),
doc,
},
);
}
crate_features.insert(*k, enables);
}

SerializedPackage {
name: package_id.name(),
Expand All @@ -232,6 +259,7 @@ impl Package {
.collect(),
targets,
features: crate_features,
features_v2,
manifest_path: self.manifest_path().to_path_buf(),
metadata: self.manifest().custom_metadata().cloned(),
authors: manmeta.authors.clone(),
Expand Down
74 changes: 74 additions & 0 deletions tests/testsuite/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4984,3 +4984,77 @@ fn metadata_ignores_build_target_configuration() -> anyhow::Result<()> {
);
Ok(())
}

#[cargo_test]
fn cargo_metadata_features_v2() {
Package::new("serde", "1.0.0").publish();
Package::new("log", "1.0.0").publish();

let p = project()
.file(
"Cargo.toml",
r#"
cargo-features = ["feature-metadata"]

[package]
name = "foo"
version = "0.5.0"
edition = "2015"

[dependencies]
serde = { version = "1.0.0", optional = true }
log = { version = "1.0.0", optional = true }

[features]
default = ["serde"]
empty = []
legacy = ["empty"]
serde = { enables = ["dep:serde"], doc = "Enables support for serialization via serde." }
table_empty = { enables = [] }
table_without_doc = { enables = ["empty"] }
Comment thread
weihanglo marked this conversation as resolved.
"#,
)
.file("src/lib.rs", "")
.build();

p.cargo("metadata --format-version 1")
.masquerade_as_nightly_cargo(&["feature-metadata"])
.with_stdout_data(
str![[r#"
{
"packages": [
{
"name": "foo",
"features": {
"default": ["serde"],
"empty": [],
"legacy": ["empty"],
"log": ["dep:log"],
"serde": ["dep:serde"],
"table_empty": [],
"table_without_doc": ["empty"]
},
"features_v2": {
"default": { "enables": ["serde"] },
"empty": { "enables": [] },
"legacy": { "enables": ["empty"] },
"log": { "enables": ["dep:log"] },
"serde": {
"enables": ["dep:serde"],
"doc": "Enables support for serialization via serde."
},
"table_empty": { "enables": [] },
"table_without_doc": { "enables": ["empty"] }
},
"...": "{...}"
},
"{...}",
"{...}"
],
"...": "{...}"
}
"#]]
.is_json(),
)
.run();
}
Loading