1use std::io::Write;
19
20use anyhow::Context as _;
21use cfg_expr::targets::get_builtin_target_by_triple;
22use rusty_bind_parser::binding_module::CargoFeature;
23use rusty_bind_parser::BindingModule;
24use syn::{File, Item};
25
26pub fn parse_ffi_module(input_rust_file_path: &str, output_dir: &str) -> anyhow::Result<()> {
31 let file = std::fs::read_to_string(input_rust_file_path)
32 .with_context(|| format!("Could not read a file `{input_rust_file_path}`"))?;
33
34 if !std::path::Path::new(output_dir).exists() {
35 std::fs::create_dir(output_dir)
36 .with_context(|| format!("Could not create a directory `{output_dir}`"))?;
37 }
38
39 let context = build_context().context("Failed to build context")?;
40
41 if let Ok(file) = syn::parse_str(&file) as Result<File, _> {
45 for item in file.items {
46 if let Item::Mod(module) = item {
47 let parsed = BindingModule::translate_module(module, &context)?;
48 let file = syn::parse2(parsed.get_tokens())?;
49 let rust_code = prettyplease::unparse(&file);
50 let generated_code = parsed.generate_binding_files();
51
52 let mut output_interface = std::fs::File::create(format!(
53 "{output_dir}/interface.rs"
54 ))
55 .with_context(|| format!("Could not create a file `{output_dir}/interface.rs`"))?;
56 output_interface
57 .write_all(rust_code.as_bytes())
58 .with_context(|| format!("Could not write file `{output_dir}/interface.rs`"))?;
59
60 let mut output_interface = std::fs::File::create(format!("{output_dir}/ffi_cxx.h"))
61 .with_context(|| format!("Could not create a file `{output_dir}/ffi_cxx.h`"))?;
62 output_interface
63 .write_all(generated_code.cpp_header.as_bytes())
64 .with_context(|| format!("Could not write file `{output_dir}/ffi_cxx.h`"))?;
65
66 let mut output_interface =
67 std::fs::File::create(format!("{output_dir}/ffi_swift.swift")).with_context(
68 || format!("Could not create a file `{output_dir}/ffi_swift.swift`"),
69 )?;
70 output_interface
71 .write_all(generated_code.swift_header.as_bytes())
72 .with_context(|| {
73 format!("Could not write file `{output_dir}/ffi_swift.swift`")
74 })?;
75
76 let mut output_interface = std::fs::File::create(format!(
77 "{output_dir}/ffi_swift.h"
78 ))
79 .with_context(|| format!("Could not create a file `{output_dir}/ffi_swift.h`"))?;
80 output_interface
81 .write_all(generated_code.cpp_externs.as_bytes())
82 .with_context(|| format!("Could not write file `{output_dir}/ffi_swift.h`"))?;
83
84 let mut output_interface = std::fs::File::create(format!(
85 "{output_dir}/ffi_swig.i"
86 ))
87 .with_context(|| format!("Could not create a file `{output_dir}/ffi_swig.i`"))?;
88 output_interface
89 .write_all(generated_code.swig_interface.as_bytes())
90 .with_context(|| {
91 format!("Could not write to file `{output_dir}/ffi_swig.i`")
92 })?;
93 }
94 }
95 }
96 Ok(())
97}
98
99fn build_context() -> anyhow::Result<rusty_bind_parser::BuildContext> {
100 let target = std::env::var("TARGET").context("TARGET env variable is not present")?;
101 let current_target_info =
102 get_builtin_target_by_triple(&target).context("Fail to parse TARGET env")?;
103
104 let features = std::env::vars()
105 .map(|kv| kv.0)
106 .filter(|key| key.starts_with("CARGO_FEATURE_"))
107 .map(|key| CargoFeature::new(&key["CARGO_FEATURE_".len()..]))
108 .collect();
109
110 let target_features = std::env::var("CARGO_CFG_TARGET_FEATURE")
111 .unwrap_or_default()
112 .split(',')
113 .map(Into::into)
114 .collect();
115
116 Ok(rusty_bind_parser::BuildContext::new(
117 current_target_info,
118 features,
119 target_features,
120 ))
121}