mod attrs;
mod debug;
mod sql_safe_name;
pub use attrs::*;
pub use debug::*;
pub use sql_safe_name::*;
use proc_macro2::TokenStream;
use std::path::Path;
pub fn write_to_file(path: &Path, tokens: &TokenStream) -> syn::Result<()> {
let content = tokens.to_string();
let code = match syn::parse_file(&content) {
Ok(output) => {
std::panic::catch_unwind(|| prettyplease::unparse(&output)).unwrap_or_else(|panic| {
if let Some(s) = panic.downcast_ref::<String>() {
eprintln!("prettyplease::unparse panicked. Using raw output. Panic message: {s}");
} else {
eprintln!("prettyplease::unparse panicked. Using raw output");
}
content
})
}
Err(e) => {
eprintln!("syntax error found. Using raw token stream. Error = {e}");
content
}
};
write_string_to_file(tokens, path, &code)
}
pub fn write_string_to_file(
span: &dyn syn::spanned::Spanned,
path: &Path,
content: &str,
) -> syn::Result<()> {
use std::io::Write;
let display_path = path.display();
match std::fs::read_to_string(path) {
Ok(existing_code) if existing_code == content => {}
_ => {
println!("writing to {display_path}");
let mut file = std::fs::File::create(path).map_err(|e| {
eprintln!("Unable to create file {display_path}. {e}");
syn::Error::new(span.span(), e)
})?;
file.write_all(content.as_bytes()).map_err(|e| {
eprintln!("Unable to write to file {display_path}. {e}");
syn::Error::new(span.span(), e)
})?;
file.sync_all().map_err(|e| {
eprintln!("Unable to sync file {display_path}. {e}");
syn::Error::new(span.span(), e)
})?;
}
}
Ok(())
}
pub fn embed_generated_code(
embed: bool,
name: &syn::Ident,
output: proc_macro2::TokenStream,
macro_out: &str,
) -> Result<proc_macro2::TokenStream, syn::Error> {
let embed =
embed || std::env::var("CIDO_EMBED_GENERATED_CODE").map_or(false, |s| s == "1" || s == "true");
if embed {
let out_dir = std::env::var("OUT_DIR")
.or_else(|_| std::env::var("TMPDIR"))
.unwrap_or_else(|_| "/tmp".to_string());
let out_file = format!("{out_dir}/{name}.{macro_out}.rs");
println!("Including {name} instead of generating in {out_file}");
write_to_file(out_file.as_ref(), &output).map_err(|e| {
syn::Error::new(
name.span(),
format_args!("Unable to write output to file {out_file}. {e}"),
)
})?;
Ok(quote::quote!(::std::include! {#out_file}))
} else {
Ok(output)
}
}