use crate::conversion::api::{FuncToConvert, UnanalyzedApi};
use crate::{
conversion::api::ApiDetail,
conversion::ConvertError,
types::{Namespace, TypeName},
};
use std::collections::{HashMap, HashSet};
use syn::{ForeignItem, Ident, ImplItem, ItemImpl, Type};
pub(crate) struct ParseForeignMod {
ns: Namespace,
funcs_to_convert: Vec<FuncToConvert>,
method_receivers: HashMap<Ident, TypeName>,
}
impl ParseForeignMod {
pub(crate) fn new(ns: Namespace) -> Self {
Self {
ns,
funcs_to_convert: Vec::new(),
method_receivers: HashMap::new(),
}
}
pub(crate) fn convert_foreign_mod_items(
&mut self,
foreign_mod_items: Vec<ForeignItem>,
virtual_this_type: Option<TypeName>,
) {
for i in foreign_mod_items {
let r = self.parse_foreign_item(i, &virtual_this_type);
match r {
Err(err) if err.is_ignorable() => {
eprintln!("Ignored item discovered whilst parsing: {}", err)
}
Err(_) => r.unwrap(),
Ok(_) => {}
}
}
}
fn parse_foreign_item(
&mut self,
i: ForeignItem,
virtual_this_type: &Option<TypeName>,
) -> Result<(), ConvertError> {
match i {
ForeignItem::Fn(item) => {
self.funcs_to_convert.push(FuncToConvert {
item,
virtual_this_type: virtual_this_type.clone(),
self_ty: None,
});
Ok(())
}
ForeignItem::Static(item) => Err(ConvertError::StaticData(item.ident.to_string())),
_ => Err(ConvertError::UnexpectedForeignItem),
}
}
pub(crate) fn convert_impl_items(&mut self, imp: ItemImpl) {
let ty_id = match *imp.self_ty {
Type::Path(typ) => typ.path.segments.last().unwrap().ident.clone(),
_ => return,
};
for i in imp.items {
if let ImplItem::Method(itm) = i {
let effective_fun_name = if itm.sig.ident == "new" {
ty_id.clone()
} else {
itm.sig.ident
};
self.method_receivers.insert(
effective_fun_name,
TypeName::new(&self.ns, &ty_id.to_string()),
);
}
}
}
pub(crate) fn finished(&mut self, apis: &mut Vec<UnanalyzedApi>) {
while !self.funcs_to_convert.is_empty() {
let mut fun = self.funcs_to_convert.remove(0);
fun.self_ty = self.method_receivers.get(&fun.item.sig.ident).cloned();
apis.push(UnanalyzedApi {
ns: self.ns.clone(),
id: fun.item.sig.ident.clone(),
deps: HashSet::new(), detail: ApiDetail::Function { fun, analysis: () },
})
}
}
}