Skip to main content

wowlab_tidy/languages/toml/rules/cargo/
feature_no_std.rs

1use super::{assignment_line, is_cargo_manifest};
2use crate::{Example, TomlCtx, Violation, violation};
3
4#[rustfmt::skip]
5const EXAMPLES: &[Example] = &[
6    Example { label: "additive std feature", code: "[features]\ndefault = [\"std\"]\nstd = []\n", pass: true },
7    Example { label: "no features table", code: "[package]\nname = \"foo\"\n", pass: true },
8    Example { label: "no-std feature", code: "[features]\nno-std = []\n", pass: false },
9    Example { label: "no_std feature", code: "[features]\nno_std = []\n", pass: false },
10    Example { label: "nostd feature", code: "[features]\nnostd = []\n", pass: false },
11];
12
13crate::toml_rule!(
14    toml_cargo_feature_no_std,
15    "Ban subtractive no-std Cargo features; provide an additive std feature instead.",
16    "Features must be additive so any combination compiles; a no-std feature that removes functionality breaks feature unification (M-FEATURES-ADDITIVE).",
17    Medium,
18);
19
20fn check_toml_cargo_feature_no_std(ctx: &TomlCtx<'_>) -> Vec<Violation> {
21    if !is_cargo_manifest(ctx.file.rel) || !ctx.parse.errors.is_empty() {
22        return Vec::new();
23    }
24
25    let Ok(document) = toml::from_str::<toml::Table>(ctx.file.contents) else {
26        return Vec::new();
27    };
28    let Some(features) = document.get("features").and_then(toml::Value::as_table) else {
29        return Vec::new();
30    };
31
32    features
33        .keys()
34        .filter(|name| matches!(name.as_str(), "no-std" | "no_std" | "nostd"))
35        .map(|name| {
36            violation(
37                ctx.file.rel,
38                assignment_line(ctx.file.lines, name),
39                format!(
40                    "feature `{name}` is subtractive; invert it into an additive `std` feature"
41                ),
42            )
43        })
44        .collect()
45}
46
47#[cfg(test)]
48mod tests {
49    use super::*;
50
51    fn run(source: &str) -> Vec<Violation> {
52        crate::test_support::check_source_toml_at(
53            "crates/foo/Cargo.toml",
54            source,
55            check_toml_cargo_feature_no_std,
56        )
57    }
58
59    crate::example_tests!(EXAMPLES, check_toml_cargo_feature_no_std);
60}