clifford_codegen/codegen/
format.rs1use proc_macro2::TokenStream;
7use std::io::Write;
8use std::process::{Command, Stdio};
9
10pub fn format_tokens(tokens: &TokenStream) -> String {
29 let unformatted = tokens.to_string();
30 format_code(&unformatted).unwrap_or(unformatted)
31}
32
33fn format_code(code: &str) -> Option<String> {
37 let mut child = Command::new("rustfmt")
38 .arg("--edition=2024")
39 .stdin(Stdio::piped())
40 .stdout(Stdio::piped())
41 .stderr(Stdio::null())
42 .spawn()
43 .ok()?;
44
45 if let Some(mut stdin) = child.stdin.take() {
47 stdin.write_all(code.as_bytes()).ok()?;
48 }
49
50 let output = child.wait_with_output().ok()?;
52
53 if output.status.success() {
54 String::from_utf8(output.stdout).ok()
55 } else {
56 None
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63 use quote::quote;
64
65 #[test]
66 fn formats_simple_struct() {
67 let tokens = quote! {
68 pub struct Foo{x:i32,y:i32}
69 };
70
71 let formatted = format_tokens(&tokens);
72
73 assert!(formatted.contains("struct Foo"));
75 assert!(formatted.contains("x"));
76 assert!(formatted.contains("y"));
77 }
78
79 #[test]
80 fn handles_complex_code() {
81 let tokens = quote! {
82 impl<T: Float> Vector<T> {
83 pub fn new(x: T, y: T) -> Self {
84 Self { x, y }
85 }
86
87 pub fn x(&self) -> T {
88 self.x
89 }
90 }
91 };
92
93 let formatted = format_tokens(&tokens);
94 assert!(formatted.contains("impl<T: Float> Vector<T>"));
95 assert!(formatted.contains("pub fn new"));
96 }
97}