use itertools::Itertools;
use quote::quote;
use syn::{parse_quote, FnArg};
use crate::{
conversion::{
api::{
Api, ApiName, CastMutability, DeletedOrDefaulted, Provenance, References,
TraitSynthesis,
},
apivec::ApiVec,
},
types::{make_ident, QualifiedName},
};
const SUPPORT_MUTABLE_CASTS: bool = false;
use super::{
fun::function_wrapper::{CppFunctionBody, CppFunctionKind},
pod::{PodAnalysis, PodPhase},
};
pub(crate) fn add_casts(apis: ApiVec<PodPhase>) -> ApiVec<PodPhase> {
apis.into_iter()
.flat_map(|api| {
let mut resultant_apis = match api {
Api::Struct {
ref name,
details: _,
ref analysis,
} => create_casts(&name.name, analysis).collect_vec(),
_ => Vec::new(),
};
resultant_apis.push(api);
resultant_apis.into_iter()
})
.collect()
}
fn create_casts<'a>(
name: &'a QualifiedName,
analysis: &'a PodAnalysis,
) -> impl Iterator<Item = Api<PodPhase>> + 'a {
analysis
.castable_bases
.iter()
.flat_map(move |base| cast_types().map(|mutable| create_cast(name, base, mutable)))
}
fn cast_types() -> impl Iterator<Item = CastMutability> {
if SUPPORT_MUTABLE_CASTS {
vec![
CastMutability::ConstToConst,
CastMutability::MutToConst,
CastMutability::MutToMut,
]
.into_iter()
} else {
vec![CastMutability::ConstToConst].into_iter()
}
}
fn create_cast(from: &QualifiedName, to: &QualifiedName, mutable: CastMutability) -> Api<PodPhase> {
let name = name_for_cast(from, to, mutable);
let ident = name.get_final_ident();
let from_typ = from.to_type_path();
let to_typ = to.to_type_path();
let return_mutability = match mutable {
CastMutability::ConstToConst | CastMutability::MutToConst => quote! { const },
CastMutability::MutToMut => quote! { mut },
};
let param_mutability = match mutable {
CastMutability::ConstToConst => quote! { const },
CastMutability::MutToConst | CastMutability::MutToMut => quote! { mut },
};
let fnarg: FnArg = parse_quote! {
this: * #param_mutability #from_typ
};
Api::Function {
name: ApiName::new_from_qualified_name(name),
fun: Box::new(crate::conversion::api::FuncToConvert {
ident,
doc_attrs: Vec::new(),
inputs: [fnarg].into_iter().collect(),
output: parse_quote! {
-> * #return_mutability #to_typ
},
vis: parse_quote! { pub },
virtualness: crate::conversion::api::Virtualness::None,
cpp_vis: crate::conversion::api::CppVisibility::Public,
special_member: None,
unused_template_param: false,
references: References::new_with_this_and_return_as_reference(),
original_name: None,
self_ty: Some(from.clone()),
synthesized_this_type: None,
add_to_trait: Some(TraitSynthesis::Cast {
to_type: to.clone(),
mutable,
}),
synthetic_cpp: Some((CppFunctionBody::Cast, CppFunctionKind::Function)),
is_deleted: DeletedOrDefaulted::Neither,
provenance: Provenance::SynthesizedOther,
variadic: false,
}),
analysis: (),
}
}
fn name_for_cast(
from: &QualifiedName,
to: &QualifiedName,
mutable: CastMutability,
) -> QualifiedName {
let suffix = match mutable {
CastMutability::ConstToConst => "",
CastMutability::MutToConst => "_to_const",
CastMutability::MutToMut => "_mut",
};
let name = format!(
"cast_{}_to_{}{}",
from.get_final_item(),
to.get_final_item(),
suffix
);
let name = make_ident(name);
QualifiedName::new(from.get_namespace(), name)
}