1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
use std::{
    io::Write,
    process::{Command, Stdio},
};

/// Format generated Rust code using `rustfmt` run as external process.
///
/// Panics
/// -------
/// - `rustfmt` is not found in PATH
/// - `rustfmt` returns error
///   - The input of rustfmt is completely generated by this crate,
///     and thus it must be a bug, i.e. not a runtime error.
///
pub fn rustfmt(tt: String) -> String {
    let mut child = Command::new("rustfmt")
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn()
        .expect("Failed to spawn rustfmt process");

    // Write input from another thread for avoiding deadlock.
    // See https://doc.rust-lang.org/std/process/index.html#handling-io
    let mut stdin = child.stdin.take().expect("Failed to open stdin");
    std::thread::spawn(move || {
        stdin
            .write_all(tt.as_bytes())
            .expect("Failed to write to stdin");
    });
    let output = child
        .wait_with_output()
        .expect("Failed to wait output of rustfmt process");

    // non-UTF8 comment should be handled in the tokenize phase,
    // and not be included in IR.
    String::from_utf8(output.stdout).expect("rustfmt output contains non-UTF8 input")
}