static_reflect_derive_internals/
utils.rs1use proc_macro2::{TokenStream, Ident};
2use syn::{Item};
3use std::io::{Write};
4use std::fmt::Display;
5use quote::quote;
6
7pub fn is_derive_enabled(name: &str) -> bool {
8 match std::env::var(format!("DEBUG_DERIVE_{}", name)) {
9 Ok(s) => &*s == "1" || s.eq_ignore_ascii_case("true"),
10 Err(_) => false,
11 }
12}
13
14pub fn item_name(item: &Item) -> Box<dyn Display> {
15 let ident: &Ident = match *item {
16 Item::Fn(ref f) => &f.sig.ident,
17 Item::Static(ref s) => &s.ident,
18 Item::Struct(ref s) => &s.ident,
19 _ => return Box::new(format!("{}", quote!(item))) as Box<dyn Display>
20 };
21 Box::new(ident.clone()) as Box<dyn Display>
22}
23
24pub fn debug_proc_macro(macro_name: &str, input: &dyn Display, result: &TokenStream) {
25 if !is_derive_enabled(macro_name) { return }
26 let original = format!("{}", result);
27 match rustfmt_expr(&original) {
28 Ok(formatted) => {
29 eprintln!("{}!({}):", macro_name, input);
30 for line in formatted.lines() {
31 eprintln!(" {}", line);
32 }
33 },
34 Err(error) => {
35 eprintln!("{}!({}) caused rustfmt error:", macro_name, input);
36 for line in error.lines() {
37 eprintln!(" {}", line);
38 }
39 eprintln!(" original code: {}", original)
40 }
41 }
42}
43
44pub fn debug_derive(trait_name: &str, target: &dyn Display, result: &TokenStream) {
45 if !is_derive_enabled(trait_name) { return }
46 let original = format!("{}", result);
47 match rustfmt(&original) {
48 Ok(formatted) => {
49 eprintln!("derive({}) for {}:", trait_name, target);
50 for line in formatted.lines() {
51 eprintln!(" {}", line);
52 }
53 },
54 Err(error) => {
55 eprintln!("derive({}) for {} caused rustfmt error:", trait_name, target);
56 for line in error.lines() {
57 eprintln!(" {}", line);
58 }
59 eprintln!(" original code: {}", original)
60 }
61 }
62}
63
64pub fn rustfmt_expr(target: &str) -> Result<String, String> {
65 let dummy = format!(r#"fn expr() {{ {} }}"#, target);
66 rustfmt(&dummy)
67}
68
69pub fn rustfmt(target: &str) -> Result<String, String> {
70 use std::process::{Command, Stdio};
71 let mut child = match Command::new("rustfmt")
72 .stdin(Stdio::piped())
73 .stdout(Stdio::piped())
74 .stderr(Stdio::piped())
75 .spawn() {
76 Ok(child) => child,
77 Err(_) => {
78 return Ok(target.into())
84 }
85 };
86 match child.stdin.as_mut().unwrap().write_all(target.as_bytes()).and_then(|()| {
87 let output = child.wait_with_output()?;
88 let utf_err = |cause: std::string::FromUtf8Error| {
89 std::io::Error::new(std::io::ErrorKind::InvalidData, cause)
90 };
91 let stdout = String::from_utf8(output.stdout)
92 .map_err(utf_err)?;
93 let stderr = String::from_utf8(output.stderr)
94 .map_err(utf_err)?;
95 Ok((output.status, stdout, stderr))
96 }) {
97 Ok((status, stdout, stderr)) => {
98 if status.success() {
99 Ok(stdout)
100 } else {
101 Err(stderr)
102 }
103 },
104 Err(e) => {
105 Err(format!("Unexpected IO error: {}", e))
106 }
107 }
108}