use sigmd::model::Interface;
use uuid::Uuid;
use super::{BuildContext, Error, Score, clang, function::build_function, ty::strip_modifiers};
#[derive(Debug)]
pub struct ScoredInterface {
pub interface: Interface,
pub score: Score,
}
pub fn build_interface(
cursor: clang::Entity<'_>,
ctx: &BuildContext,
) -> Result<ScoredInterface, Error> {
let name = match cursor.get_name() {
Some(name) => name,
None => {
return Err(Error::UndefinedProperty {
property: "name",
entity: format!("{:?}", cursor.get_kind()),
});
}
};
let mut annotation = None;
let mut base = None;
let mut method_scores = Vec::new();
let mut methods = Vec::new();
for child in cursor.get_children() {
match child.get_kind() {
clang::EntityKind::AnnotateAttr if annotation.is_none() => {
annotation = child.get_name();
}
clang::EntityKind::BaseSpecifier if base.is_none() => {
base = child
.get_name()
.map(|spelling| strip_modifiers(&spelling).to_string());
}
clang::EntityKind::Method => match build_function(child, ctx) {
Ok(scored) => {
method_scores.push(scored.score);
methods.push(scored.function);
}
Err(err) => {
tracing::trace!(%err, name, "skipping non-method decl");
}
},
_ => {}
}
}
let annotation = match annotation {
Some(annotation) => annotation,
None => {
return Err(Error::UndefinedProperty {
property: "annotation",
entity: name.clone(),
});
}
};
let uuid_text = match annotation.strip_prefix("__UUID|") {
Some(uuid_text) => uuid_text.to_lowercase(),
None => {
return Err(Error::UndefinedProperty {
property: "uuid annotation",
entity: name.clone(),
});
}
};
let uuid = Uuid::try_from(uuid_text.as_str())?;
let interface = Interface::builder()
.name(name)
.uuid(uuid)
.maybe_base(base)
.methods(methods)
.build();
let score = interface_score(&method_scores);
Ok(ScoredInterface { interface, score })
}
fn interface_score(method_scores: &[Score]) -> Score {
Score(method_scores.iter().map(|score| score.0 + 1).sum())
}