use std::collections::HashSet;
use std::fs;
use std::path::{Path, PathBuf};
const CARVEOUT_FILES: &[&str] = &[
"src/library/identity.rs",
"src/library/assertions.rs",
"src/library/context.rs",
"src/library/sampling/lut.rs",
"src/library/register.rs",
];
#[test]
fn srd80b_no_handwritten_polydat_node_impl_outside_carveouts() {
let crate_root = Path::new(env!("CARGO_MANIFEST_DIR"));
let library_root = crate_root.join("src/library");
assert!(
library_root.exists(),
"expected polydat/src/library to exist at {}",
library_root.display(),
);
let mut offending: Vec<String> = Vec::new();
let carveout: HashSet<PathBuf> = CARVEOUT_FILES.iter()
.map(|p| crate_root.join(p))
.collect();
visit_rust_files(&library_root, &mut |path| {
if carveout.contains(path) {
return;
}
let body = match fs::read_to_string(path) {
Ok(s) => s,
Err(_) => return,
};
for (lineno, line) in body.lines().enumerate() {
let trimmed = line.trim_start();
if trimmed.contains('$') {
continue;
}
if line.starts_with("impl PolydatNode for")
|| line.starts_with("impl<") && line.contains("PolydatNode for")
{
let rel = path.strip_prefix(crate_root).unwrap_or(path);
offending.push(format!(
"{}:{}: hand-written `impl PolydatNode for`",
rel.display(),
lineno + 1,
));
}
}
});
assert!(
offending.is_empty(),
"SRD-80b invariant violated — hand-written `impl PolydatNode for X` \
blocks must use the `#[polydat_node]` macro, OR the file must be \
added to CARVEOUT_FILES in `polydat/tests/srd80b_invariant.rs` with \
a justifying rationale.\n\nOffending sites:\n {}\n",
offending.join("\n ")
);
}
fn visit_rust_files(dir: &Path, visit: &mut dyn FnMut(&Path)) {
let entries = match fs::read_dir(dir) {
Ok(e) => e,
Err(_) => return,
};
for entry in entries.flatten() {
let path = entry.path();
if path.is_dir() {
visit_rust_files(&path, visit);
} else if path.extension().is_some_and(|e| e == "rs") {
visit(&path);
}
}
}