mod build_macro;
mod implement;
mod implement_macro;
use build_macro::*;
use gen::*;
use implement_macro::*;
use syn::parse_macro_input;
struct RawString(String);
impl ToTokens for RawString {
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.push_str("r#\"");
tokens.push_str(&self.0);
tokens.push_str("\"#");
}
}
#[proc_macro]
pub fn build(stream: proc_macro::TokenStream) -> proc_macro::TokenStream {
let build = parse_macro_input!(stream as BuildMacro);
let tokens = RawString(build.into_tokens_string());
let workspace_windows_dir = gen::workspace_windows_dir();
let mut destination = workspace_windows_dir.clone();
destination.pop();
destination.push("target");
let destination = RawString(
destination
.to_str()
.expect("Invalid workspace target dir")
.to_string(),
);
let workspace_windows_dir = RawString(
workspace_windows_dir
.to_str()
.expect("Invalid workspace windows dir")
.to_string(),
);
let tokens = quote! {
{
use ::std::io::Write;
let mut path = ::std::path::PathBuf::from(
::std::env::var("OUT_DIR").expect("No `OUT_DIR` env variable set"),
);
path.push("windows.rs");
let mut file = ::std::fs::File::create(&path).expect("Failed to create windows.rs");
file.write_all(#tokens.as_bytes()).expect("Could not write generated code to output file");
let mut cmd = ::std::process::Command::new("rustfmt");
cmd.arg(&path);
let _ = cmd.output();
fn copy(source: &::std::path::Path, destination: &mut ::std::path::PathBuf) {
if let ::std::result::Result::Ok(files) = ::std::fs::read_dir(source) {
for file in files.filter_map(|file| file.ok()) {
if let ::std::result::Result::Ok(file_type) = file.file_type() {
if file_type.is_file() {
let path = file.path();
if let ::std::option::Option::Some(filename) = path.file_name() {
destination.push(filename);
let _ = ::std::fs::copy(path, &destination);
destination.pop();
}
}
}
}
}
}
fn copy_to_profile(source: &::std::path::Path, destination: &::std::path::Path, profile: &str) {
if let ::std::result::Result::Ok(files) = ::std::fs::read_dir(destination) {
for file in files.filter_map(|file| file.ok()) {
if let ::std::result::Result::Ok(file_type) = file.file_type() {
if file_type.is_dir() {
let mut path = file.path();
if let ::std::option::Option::Some(filename) = path.file_name() {
if filename == profile {
copy(source, &mut path);
} else {
copy_to_profile(source, &path, profile);
}
}
}
}
}
}
}
if ::std::path::PathBuf::from(#workspace_windows_dir).exists() {
println!("cargo:rerun-if-changed={}", #workspace_windows_dir);
let mut source = ::std::path::PathBuf::from(#workspace_windows_dir);
source.push(match ::std::env::var("CARGO_CFG_TARGET_ARCH").expect("No `CARGO_CFG_TARGET_ARCH` env variable set").as_str() {
"x86_64" => "x64",
"x86" => "x86",
"arm" => "arm",
"aarch64" => "arm64",
unexpected => panic!("Unexpected `{}` architecture set by `CARGO_CFG_TARGET_ARCH`", unexpected),
});
let destination = ::std::path::PathBuf::from(#destination);
let profile = ::std::env::var("PROFILE").expect("No `PROFILE` env variable set");
copy_to_profile(&source, &destination, &profile);
}
}
};
tokens.as_str().parse().unwrap()
}
#[proc_macro]
pub fn generate(stream: proc_macro::TokenStream) -> proc_macro::TokenStream {
let build = parse_macro_input!(stream as BuildMacro);
let mut tokens = String::new();
tokens.push_str("r#\"");
tokens.push_str(&build.into_tokens_string());
tokens.push_str("\"#");
tokens.parse().unwrap()
}
#[proc_macro_attribute]
pub fn implement(
attribute: proc_macro::TokenStream,
input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
implement::gen(attribute, input)
}