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 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
#![crate_type = "proc-macro"] #![recursion_limit = "250"] extern crate proc_macro; use std::{process::Command}; use proc_macro::TokenStream; use proc_macro2::TokenStream as Tokens; use syn::{DeriveInput}; use quote::quote; mod derive; #[proc_macro_derive(Casserole, attributes(casserole))] pub fn derive_casserole(input: TokenStream) -> TokenStream { derive_wrap(input, |input, ()| derive::derive_object_casserole("casserole", &input), ()) } #[proc_macro] pub fn derive_casserole_prelude(input: TokenStream) -> TokenStream { derive_wrap(input, |input, ()| derive::derive_object_casserole("crate", &input), ()) } fn derive_wrap<F, P, T>(input: TokenStream, f: F, p: P) -> TokenStream where F: for<'a> FnOnce(&'a DeriveInput, P) -> T, T: quote::ToTokens { let input: DeriveInput = syn::parse(input).unwrap(); let name = &input.ident; let b = f(&input, p); let res = quote!(#b); if let Some((_, value)) = std::env::vars().find(|(key, _)| key.as_str() == "DERIVE_SAVE_DIR") { let dir = std::path::Path::new(value.as_str()); tokens_to_rustfmt_file(&dir.join(format!("derive_{}.rs", name)), &res); } res.into() } fn tokens_to_rustfmt_file(filename: &std::path::Path, expanded: &Tokens) { let mut file = std::fs::File::create(&filename).unwrap(); use std::io::Write; file.write_all(format!("{}", expanded).as_bytes()).unwrap(); Command::new("rustfmt") .args(&[filename]) .output() .expect("failed to execute process"); }