use std::io::Write;
use anyhow::Context;
use cfg_expr::targets::get_builtin_target_by_triple;
use rusty_bind_parser::binding_module::CargoFeature;
use rusty_bind_parser::BindingModule;
use syn::{File, Item};
pub fn parse_ffi_module(input_rust_file_path: &str, output_dir: &str) -> anyhow::Result<()> {
let file = std::fs::read_to_string(input_rust_file_path)
.with_context(|| format!("Could not read a file `{input_rust_file_path}`"))?;
if !std::path::Path::new(output_dir).exists() {
std::fs::create_dir(output_dir)
.with_context(|| format!("Could not create a directory `{output_dir}`"))?;
}
let context = build_context().context("Failed to build context")?;
if let Ok(file) = syn::parse_str(&file) as Result<File, _> {
for item in file.items {
if let Item::Mod(module) = item {
let parsed = BindingModule::translate_module(module, &context)?;
let rust_code = parsed.get_tokens().to_string();
let generated_code = parsed.generate_binding_files();
let mut output_interface = std::fs::File::create(format!(
"{output_dir}/interface.rs"
))
.with_context(|| format!("Could not create a file `{output_dir}/interface.rs`"))?;
output_interface
.write_all(rust_code.as_bytes())
.with_context(|| format!("Could not write file `{output_dir}/interface.rs`"))?;
let mut output_interface = std::fs::File::create(format!("{output_dir}/ffi_cxx.h"))
.with_context(|| format!("Could not create a file `{output_dir}/ffi_cxx.h`"))?;
output_interface
.write_all(generated_code.cpp_header.as_bytes())
.with_context(|| format!("Could not write file `{output_dir}/ffi_cxx.h`"))?;
let mut output_interface =
std::fs::File::create(format!("{output_dir}/ffi_swift.swift")).with_context(
|| format!("Could not create a file `{output_dir}/ffi_swift.swift`"),
)?;
output_interface
.write_all(generated_code.swift_header.as_bytes())
.with_context(|| {
format!("Could not write file `{output_dir}/ffi_swift.swift`")
})?;
let mut output_interface = std::fs::File::create(format!(
"{output_dir}/ffi_swift.h"
))
.with_context(|| format!("Could not create a file `{output_dir}/ffi_swift.h`"))?;
output_interface
.write_all(generated_code.cpp_externs.as_bytes())
.with_context(|| format!("Could not write file `{output_dir}/ffi_swift.h`"))?;
let mut output_interface = std::fs::File::create(format!(
"{output_dir}/ffi_swig.i"
))
.with_context(|| format!("Could not create a file `{output_dir}/ffi_swig.i`"))?;
output_interface
.write_all(generated_code.swig_interface.as_bytes())
.with_context(|| {
format!("Could not write to file `{output_dir}/ffi_swig.i`")
})?;
}
}
}
Ok(())
}
fn build_context() -> anyhow::Result<rusty_bind_parser::BuildContext> {
let target = std::env::var("TARGET").context("TARGET env variable is not present")?;
let current_target_info =
get_builtin_target_by_triple(&target).context("Fail to parse TARGET env")?;
let features = std::env::vars()
.map(|kv| kv.0)
.filter(|key| key.starts_with("CARGO_FEATURE_"))
.map(|key| CargoFeature::new(&key["CARGO_FEATURE_".len()..]))
.collect();
let target_features = std::env::var("CARGO_CFG_TARGET_FEATURE")
.unwrap_or_default()
.split(',')
.map(Into::into)
.collect();
Ok(rusty_bind_parser::BuildContext {
current_target_info,
features,
target_features,
})
}