mod byvalue_checker;
mod byvalue_scanner;
use std::collections::HashSet;
use autocxx_parser::TypeConfig;
pub(crate) use byvalue_checker::ByValueChecker;
use byvalue_scanner::identify_byvalue_safe_types;
use syn::{Item, ItemStruct};
use crate::{
conversion::{
api::{Api, ApiAnalysis, ApiDetail, TypeKind, UnanalyzedApi},
codegen_rs::make_non_pod,
parse::type_converter::TypeConverter,
ConvertError,
},
types::{Namespace, TypeName},
};
pub(crate) struct PodAnalysis;
impl ApiAnalysis for PodAnalysis {
type TypeAnalysis = TypeKind;
type FunAnalysis = ();
}
pub(crate) fn analyze_pod_apis(
apis: Vec<UnanalyzedApi>,
type_config: &TypeConfig,
type_converter: &mut TypeConverter,
) -> Result<(Vec<Api<PodAnalysis>>, ByValueChecker), ConvertError> {
let byvalue_checker = identify_byvalue_safe_types(&apis, type_config)?;
let mut extra_apis = Vec::new();
let mut results: Vec<_> = apis
.into_iter()
.map(|api| analyze_pod_api(api, &byvalue_checker, type_converter, &mut extra_apis))
.collect::<Result<Vec<_>, ConvertError>>()?;
let mut more_extra_apis = Vec::new();
let mut more_results = extra_apis
.into_iter()
.map(|api| analyze_pod_api(api, &byvalue_checker, type_converter, &mut more_extra_apis))
.collect::<Result<Vec<_>, ConvertError>>()?;
assert!(more_extra_apis.is_empty());
results.append(&mut more_results);
Ok((results, byvalue_checker))
}
fn analyze_pod_api(
api: UnanalyzedApi,
byvalue_checker: &ByValueChecker,
type_converter: &mut TypeConverter,
extra_apis: &mut Vec<UnanalyzedApi>,
) -> Result<Api<PodAnalysis>, ConvertError> {
let ty_id = api.typename();
let mut new_deps = api.deps;
let api_detail = match api.detail {
ApiDetail::ConcreteType(details) => ApiDetail::ConcreteType(details),
ApiDetail::StringConstructor => ApiDetail::StringConstructor,
ApiDetail::Function { fun, analysis } => ApiDetail::Function { fun, analysis },
ApiDetail::Const { const_item } => ApiDetail::Const { const_item },
ApiDetail::Typedef { type_item } => ApiDetail::Typedef { type_item },
ApiDetail::CType { id } => ApiDetail::CType { id },
ApiDetail::Type {
ty_details,
for_extern_c_ts,
is_forward_declaration,
mut bindgen_mod_item,
analysis: _,
} => {
let type_kind = if is_forward_declaration {
TypeKind::ForwardDeclaration
} else if byvalue_checker.is_pod(&ty_id) {
if let Some(Item::Struct(ref s)) = bindgen_mod_item {
get_struct_field_types(type_converter, &api.ns, &s, &mut new_deps, extra_apis)?;
} TypeKind::Pod
} else {
if let Some(Item::Struct(ref mut s)) = bindgen_mod_item {
make_non_pod(s);
} new_deps.clear();
TypeKind::NonPod
};
ApiDetail::Type {
ty_details,
for_extern_c_ts,
is_forward_declaration,
bindgen_mod_item,
analysis: type_kind,
}
}
};
Ok(Api {
ns: api.ns,
id: api.id,
use_stmt: api.use_stmt,
deps: new_deps,
additional_cpp: api.additional_cpp,
detail: api_detail,
})
}
fn get_struct_field_types(
type_converter: &mut TypeConverter,
ns: &Namespace,
s: &ItemStruct,
deps: &mut HashSet<TypeName>,
extra_apis: &mut Vec<UnanalyzedApi>,
) -> Result<(), ConvertError> {
for f in &s.fields {
let annotated = type_converter.convert_type(f.ty.clone(), ns, false)?;
extra_apis.extend(annotated.extra_apis);
deps.extend(annotated.types_encountered);
}
Ok(())
}