Skip to main content

arora_module_rust/
rustfmt.rs

1use crate::GenerationError;
2use std::{
3    ffi::OsStr,
4    io,
5    path::{Path, PathBuf},
6};
7
8/// Run `rustfmt` on all Rust files found under the given path.
9pub async fn apply_rustfmt<P: AsRef<Path>>(path: P) -> Result<(), GenerationError> {
10    let rust_files = list_all_files(path, |sub_path| {
11        sub_path.extension() == Some(OsStr::new("rs"))
12    })
13    .map_err(GenerationError::IoError)?;
14    // A one-shot subprocess: use std::process (synchronous) rather than
15    // tokio::process, which would pull tokio's `process`/`signal` features (and
16    // thus mio) — breaking wasm cross-compilation of crates that depend on this
17    // codegen crate.
18    let rustfmt_status = std::process::Command::new("rustfmt")
19        .args(&rust_files)
20        .status()
21        .map_err(GenerationError::IoError)?;
22    if rustfmt_status.success() {
23        Ok(())
24    } else {
25        Err(GenerationError::Generic(format!(
26            "rustfmt exited with non-zero status: {:?}",
27            rustfmt_status.code()
28        )))
29    }
30}
31
32/// Helper to list all files recursively under the given path,
33/// while filtering result (files only) with a custom predicate.
34pub fn list_all_files<P: AsRef<Path>, F: Fn(&Path) -> bool>(
35    path: P,
36    predicate: F,
37) -> io::Result<Vec<PathBuf>> {
38    list_all_files_ref(path, &predicate)
39}
40
41fn list_all_files_ref<P: AsRef<Path>, F: Fn(&Path) -> bool>(
42    path: P,
43    predicate: &F,
44) -> io::Result<Vec<PathBuf>> {
45    let path = path.as_ref();
46    if path.is_dir() {
47        let mut result = Vec::new();
48        for entry in path.read_dir()? {
49            let sub_result = list_all_files_ref(entry?.path(), predicate)?;
50            result.extend(sub_result);
51        }
52        Ok(result)
53    } else {
54        if (*predicate)(path) {
55            Ok(vec![path.to_path_buf()])
56        } else {
57            Ok(vec![])
58        }
59    }
60}