alex/volcanic
Automated vulkan bindings
BRANCH main
SNAPSHOT Improved loading api and made ready for publish
DOWNLOAD
root codegen src manifest.rs
pub fn update_features(manifest: &str, features: &[String]) -> String {
let feature_section = feature_section(features);
let lines: Vec<_> = manifest.lines().collect();
let Some(start) = lines.iter().position(|line| line.trim() == "[features]") else {
let separator = if manifest.ends_with('\n') {
"\n"
} else {
"\n\n"
};
return format!("{manifest}{separator}{feature_section}");
};
let end = lines
.iter()
.enumerate()
.skip(start + 1)
.find_map(|(idx, line)| {
let trimmed = line.trim();
(trimmed.starts_with('[') && trimmed.ends_with(']')).then_some(idx)
})
.unwrap_or(lines.len());
let mut updated = String::new();
let prefix_end = lines[..start]
.iter()
.rposition(|line| !line.trim().is_empty())
.map(|idx| idx + 1)
.unwrap_or(0);
if prefix_end > 0 {
updated.push_str(&lines[..prefix_end].join("\n"));
updated.push_str("\n\n");
}
updated.push_str(&feature_section);
if end < lines.len() {
updated.push('\n');
updated.push_str(&lines[end..].join("\n"));
updated.push('\n');
}
updated
}
fn feature_section(features: &[String]) -> String {
let mut out = String::new();
out.push_str("[features]\n");
out.push_str("default = []\n");
out.push_str("everything = [\n");
for feature in features {
out.push_str(&format!(" \"{feature}\",\n"));
}
out.push_str("]\n\n");
out.push_str("loader = [\"dep:libloading\"]\n");
for feature in features {
let dependencies = feature_dependencies(feature);
if dependencies.is_empty() {
out.push_str(&format!("{feature} = []\n"));
} else {
out.push_str(&format!("{feature} = ["));
for (idx, dependency) in dependencies.iter().enumerate() {
if idx > 0 {
out.push_str(", ");
}
out.push_str(&format!("\"{dependency}\""));
}
out.push_str("]\n");
}
}
out
}
fn feature_dependencies(feature: &str) -> &'static [&'static str] {
match feature {
"core_1_1" => &["core_1_0"],
"core_1_2" => &["core_1_1"],
"core_1_3" => &["core_1_2"],
"core_1_4" => &["core_1_3"],
_ => &[],
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn preserves_manifest_sections_after_features() {
let manifest = "[package]\nname = \"example\"\n\n[features]\nold = []\n\n[dev-dependencies]\nexample = \"1\"\n";
let updated = update_features(manifest, &["core_1_0".into(), "core_1_1".into()]);
assert!(updated.starts_with("[package]\nname = \"example\"\n"));
assert!(updated.ends_with("[dev-dependencies]\nexample = \"1\"\n"));
assert!(!updated.contains("old ="));
assert!(updated.contains("core_1_1 = [\"core_1_0\"]"));
assert_eq!(
update_features(&updated, &["core_1_0".into(), "core_1_1".into()]),
updated
);
}
}