mod analysis;
mod api;
mod codegen_cpp;
mod codegen_rs;
#[cfg(test)]
mod conversion_tests;
mod convert_error;
mod doc_attr;
mod error_reporter;
mod parse;
mod utilities;
use analysis::fun::FnAnalyzer;
use autocxx_parser::IncludeCppConfig;
pub(crate) use codegen_cpp::CppCodeGenerator;
pub(crate) use convert_error::ConvertError;
use itertools::Itertools;
use syn::{Item, ItemMod};
use crate::{CppFilePair, UnsafePolicy};
use self::{
analysis::{
abstract_types::mark_types_abstract, check_names, fun::FnPhase,
gc::filter_apis_by_following_edges_from_allowlist, pod::analyze_pod_apis,
remove_ignored::filter_apis_by_ignored_dependents, tdef::convert_typedef_targets,
},
api::{AnalysisPhase, Api},
codegen_rs::RsCodeGenerator,
parse::ParseBindgen,
};
const LOG_APIS: bool = true;
pub(crate) struct BridgeConverter<'a> {
include_list: &'a [String],
config: &'a IncludeCppConfig,
}
pub(crate) struct CodegenResults {
pub(crate) rs: Vec<Item>,
pub(crate) cpp: Option<CppFilePair>,
}
impl<'a> BridgeConverter<'a> {
pub fn new(include_list: &'a [String], config: &'a IncludeCppConfig) -> Self {
Self {
include_list,
config,
}
}
fn dump_apis<T: AnalysisPhase>(label: &str, apis: &[Api<T>]) {
if LOG_APIS {
log::info!(
"APIs after {}:\n{}",
label,
apis.iter().map(|api| { format!(" {:?}", api) }).join("\n")
)
}
}
fn dump_apis_with_deps(label: &str, apis: &[Api<FnPhase>]) {
if LOG_APIS {
log::info!(
"APIs after {}:\n{}",
label,
apis.iter()
.map(|api| { format!(" {:?}, deps={}", api, api.format_deps()) })
.join("\n")
)
}
}
pub(crate) fn convert(
&self,
mut bindgen_mod: ItemMod,
unsafe_policy: UnsafePolicy,
inclusions: String,
suppress_system_headers: bool,
) -> Result<CodegenResults, ConvertError> {
match &mut bindgen_mod.content {
None => Err(ConvertError::NoContent),
Some((_, items)) => {
let items_to_process = items.drain(..).collect();
let parser = ParseBindgen::new(self.config);
let apis = parser.parse_items(items_to_process)?;
Self::dump_apis("parsing", &apis);
let apis = convert_typedef_targets(self.config, apis);
let analyzed_apis = analyze_pod_apis(apis, self.config)?;
let analyzed_apis =
FnAnalyzer::analyze_functions(analyzed_apis, unsafe_policy, self.config);
Self::dump_apis_with_deps("analyze fns", &analyzed_apis);
let analyzed_apis = mark_types_abstract(self.config, analyzed_apis);
Self::dump_apis_with_deps("marking abstract", &analyzed_apis);
let analyzed_apis = check_names(analyzed_apis);
let analyzed_apis = filter_apis_by_ignored_dependents(analyzed_apis);
Self::dump_apis_with_deps("removing ignored dependents", &analyzed_apis);
let mut analyzed_apis =
filter_apis_by_following_edges_from_allowlist(analyzed_apis, self.config);
analysis::ctypes::append_ctype_information(&mut analyzed_apis);
Self::dump_apis_with_deps("GC", &analyzed_apis);
let cpp = CppCodeGenerator::generate_cpp_code(
inclusions,
&analyzed_apis,
self.config,
suppress_system_headers,
)?;
let rs = RsCodeGenerator::generate_rs_code(
analyzed_apis,
self.include_list,
bindgen_mod,
self.config,
);
Ok(CodegenResults { rs, cpp })
}
}
}
}