Skip to content

Commit 7e5a828

Browse files
committed
Refactor features
1 parent 7826313 commit 7e5a828

File tree

1 file changed

+72
-57
lines changed

1 file changed

+72
-57
lines changed

tools/build-templated-pages/src/features.rs

Lines changed: 72 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::{cmp::Ordering, fs::File};
22

33
use serde::Serialize;
44
use tera::{Context, Tera};
5-
use toml_edit::Document;
5+
use toml_edit::{Document, Key, RawString, Table, Value};
66

77
use crate::Command;
88

@@ -25,29 +25,9 @@ impl PartialOrd for Feature {
2525
}
2626
}
2727

28-
fn parse_features(panic_on_missing: bool) -> Vec<Feature> {
29-
let manifest_file = std::fs::read_to_string("Cargo.toml").unwrap();
30-
let manifest = manifest_file.parse::<Document>().unwrap();
31-
32-
let features = manifest["features"].as_table().unwrap();
33-
let default: Vec<_> = features
34-
.get("default")
35-
.unwrap()
36-
.as_array()
37-
.unwrap()
38-
.iter()
39-
.flat_map(|v| {
40-
std::iter::once(v.as_str().unwrap().to_string()).chain(
41-
features
42-
.get(v.as_str().unwrap())
43-
.unwrap()
44-
.as_array()
45-
.unwrap()
46-
.iter()
47-
.map(|v| v.as_str().unwrap().to_string()),
48-
)
49-
})
50-
.collect();
28+
fn parse_features(what_to_run: Command) -> Vec<Feature> {
29+
let features = get_manifest_features();
30+
let default = get_default_features(&features);
5131

5232
features
5333
.get_values()
@@ -58,53 +38,88 @@ fn parse_features(panic_on_missing: bool) -> Vec<Feature> {
5838
if key == "default" {
5939
None
6040
} else {
61-
let name = key
62-
.as_repr()
63-
.unwrap()
64-
.as_raw()
65-
.as_str()
66-
.unwrap()
67-
.to_string();
68-
if let Some(description) = key.leaf_decor().prefix() {
69-
let description = description.as_str().unwrap().to_string();
70-
if !description.starts_with("\n# ") || !description.ends_with('\n') {
71-
panic!("Missing description for feature {name}");
41+
let key_name = get_key_name(key);
42+
let key_prefix = key.leaf_decor().prefix();
43+
if what_to_run.contains(Command::CHECK_MISSING) {
44+
if let Some(description) = key_prefix {
45+
create_feature(&default, key_name, description)
46+
} else {
47+
panic!("Missing description for feature {key_name}");
7248
}
73-
let description = description
74-
.strip_prefix("\n# ")
75-
.unwrap()
76-
.strip_suffix('\n')
77-
.unwrap()
78-
.to_string();
79-
Some(Feature {
80-
is_default: default.contains(&name),
81-
name,
82-
description,
83-
})
84-
} else if panic_on_missing {
85-
panic!("Missing description for feature {name}");
8649
} else {
87-
None
50+
let feature = |description| create_feature(&default, key_name, description);
51+
key_prefix.map(feature).unwrap()
8852
}
8953
}
9054
})
9155
.collect()
9256
}
9357

94-
pub(crate) fn check(what_to_run: Command) {
95-
let mut features = parse_features(what_to_run.contains(Command::CHECK_MISSING));
58+
fn get_manifest_features() -> Table {
59+
let manifest_file = std::fs::read_to_string("Cargo.toml").unwrap();
60+
let manifest = manifest_file.parse::<Document>().unwrap();
61+
let features = manifest["features"].as_table().unwrap().clone();
62+
features
63+
}
64+
65+
fn create_feature(default: &[String], name: String, description: &RawString) -> Option<Feature> {
66+
let description = description.as_str().unwrap().to_string();
67+
if let Some(stripped_description) = description
68+
.strip_prefix("\n# ")
69+
.and_then(|d| d.strip_suffix('\n'))
70+
{
71+
let is_default = default.contains(&name);
72+
let description = get_description(stripped_description.to_string(), &name);
73+
Some(Feature {
74+
is_default,
75+
name,
76+
description,
77+
})
78+
} else {
79+
panic!("Missing description for feature {name}");
80+
}
81+
}
82+
83+
fn get_description(description: String, name: &String) -> String {
84+
let description = description.to_string();
85+
if !description.starts_with("\n# ") || !description.ends_with('\n') {
86+
panic!("Missing description for feature {name}");
87+
}
88+
let stripped_description = description.strip_prefix("\n# ").unwrap().strip_suffix('\n');
89+
stripped_description.unwrap().to_string()
90+
}
91+
92+
fn get_key_name(key: &Key) -> String {
93+
let key_repr = key.as_repr().unwrap();
94+
key_repr.as_raw().as_str().unwrap().to_string()
95+
}
96+
97+
fn get_default_features(features: &Table) -> Vec<String> {
98+
let value = |v: &Value| {
99+
let feature_name = v.as_str().unwrap();
100+
let feature = |v: &Value| v.as_str().unwrap().to_string();
101+
let features_to_array = |name| features.get(name).unwrap().as_array().unwrap();
102+
let map = features_to_array(feature_name).iter().map(feature);
103+
std::iter::once(feature_name.to_string()).chain(map)
104+
};
105+
let features_to_array = |name| features.get(name).unwrap().as_array().unwrap();
106+
features_to_array("default")
107+
.iter()
108+
.flat_map(value)
109+
.collect()
110+
}
111+
112+
pub(crate) fn check(command: Command) {
113+
let mut features = parse_features(command);
96114
features.sort();
97115

98-
if what_to_run.contains(Command::UPDATE) {
116+
if command.contains(Command::UPDATE) {
99117
let mut context = Context::new();
100118
context.insert("features", &features);
119+
let file = File::create("docs/cargo_features.md").expect("error creating file");
101120
Tera::new("docs-template/*.md.tpl")
102121
.expect("error parsing template")
103-
.render_to(
104-
"features.md.tpl",
105-
&context,
106-
File::create("docs/cargo_features.md").expect("error creating file"),
107-
)
122+
.render_to("features.md.tpl", &context, file)
108123
.expect("error rendering template");
109124
}
110125
}

0 commit comments

Comments
 (0)