use std::borrow::Cow;
use clang::{Entity, EntityKind, EntityVisitResult, StorageClass};
use crate::type_ref::CppNameStyle;
use crate::{DefaultElement, Element, EntityElement};
impl<'tu> EntityElement<'tu> for Entity<'tu> {
fn entity(&self) -> Entity<'tu> {
*self
}
}
impl Element for Entity<'_> {
fn is_system(&self) -> bool {
DefaultElement::is_system(self.entity())
}
fn is_public(&self) -> bool {
DefaultElement::is_public(self.entity())
}
fn doc_comment(&self) -> Cow<str> {
self.get_comment().unwrap_or_default().into()
}
fn cpp_namespace(&self) -> Cow<str> {
DefaultElement::cpp_namespace(self.entity()).into()
}
fn cpp_name(&self, style: CppNameStyle) -> Cow<str> {
DefaultElement::cpp_name(self, self.entity(), style)
}
}
#[derive(Copy, Clone)]
pub enum WalkAction {
Continue,
Interrupt,
}
impl WalkAction {
pub fn continue_until(condition: bool) -> Self {
if condition {
WalkAction::Interrupt
} else {
WalkAction::Continue
}
}
}
impl From<WalkAction> for EntityVisitResult {
fn from(action: WalkAction) -> Self {
match action {
WalkAction::Continue => Self::Continue,
WalkAction::Interrupt => Self::Break,
}
}
}
#[derive(Copy, Clone)]
pub enum WalkResult {
Completed,
Interrupted,
}
impl WalkResult {
pub fn is_interrupted(self) -> bool {
matches!(self, WalkResult::Interrupted)
}
}
pub trait EntityExt<'tu> {
fn walk_children_while(&self, predicate: impl FnMut(Entity<'tu>) -> WalkAction) -> WalkResult;
fn walk_bases_while(&self, predicate: impl FnMut(Entity<'tu>) -> WalkAction) -> WalkResult;
fn walk_enums_while(&self, predicate: impl FnMut(Entity<'tu>) -> WalkAction) -> WalkResult;
fn walk_classes_while(&self, predicate: impl FnMut(Entity<'tu>) -> WalkAction) -> WalkResult;
fn walk_typedefs_while(&self, predicate: impl FnMut(Entity<'tu>) -> WalkAction) -> WalkResult;
fn walk_fields_while(&self, predicate: impl FnMut(Entity<'tu>) -> WalkAction) -> WalkResult;
fn walk_consts_while(&self, predicate: impl FnMut(Entity<'tu>) -> WalkAction) -> WalkResult;
fn walk_methods_while(&self, predicate: impl FnMut(Entity<'tu>) -> WalkAction) -> WalkResult;
}
impl<'tu> EntityExt<'tu> for Entity<'tu> {
fn walk_children_while(&self, mut predicate: impl FnMut(Entity<'tu>) -> WalkAction) -> WalkResult {
let res = self.visit_children(|child, _| predicate(child).into());
if res {
WalkResult::Interrupted
} else {
WalkResult::Completed
}
}
fn walk_bases_while(&self, mut predicate: impl FnMut(Entity<'tu>) -> WalkAction) -> WalkResult {
self.walk_children_while(|child| match child.get_kind() {
EntityKind::BaseSpecifier => predicate(child),
_ => WalkAction::Continue,
})
}
fn walk_enums_while(&self, mut predicate: impl FnMut(Entity<'tu>) -> WalkAction) -> WalkResult {
self.walk_children_while(|child| match child.get_kind() {
EntityKind::EnumDecl => predicate(child),
_ => WalkAction::Continue,
})
}
fn walk_classes_while(&self, mut predicate: impl FnMut(Entity<'tu>) -> WalkAction) -> WalkResult {
self.walk_children_while(|child| match child.get_kind() {
EntityKind::ClassDecl | EntityKind::StructDecl => predicate(child),
_ => WalkAction::Continue,
})
}
fn walk_typedefs_while(&self, mut predicate: impl FnMut(Entity<'tu>) -> WalkAction) -> WalkResult {
self.walk_children_while(|child| match child.get_kind() {
EntityKind::TypedefDecl | EntityKind::TypeAliasDecl => predicate(child),
_ => WalkAction::Continue,
})
}
fn walk_fields_while(&self, mut predicate: impl FnMut(Entity<'tu>) -> WalkAction) -> WalkResult {
self.walk_children_while(|child| match child.get_kind() {
EntityKind::FieldDecl => predicate(child),
_ => WalkAction::Continue,
})
}
fn walk_consts_while(&self, mut predicate: impl FnMut(Entity<'tu>) -> WalkAction) -> WalkResult {
self.walk_children_while(|child| match child.get_kind() {
EntityKind::VarDecl => {
if let Some(StorageClass::Static) = child.get_storage_class() {
if child.evaluate().is_some() {
predicate(child)
} else {
WalkAction::Continue
}
} else {
panic!("Non-static constant: {child:#?}")
}
}
_ => WalkAction::Continue,
})
}
fn walk_methods_while(&self, mut predicate: impl FnMut(Entity<'tu>) -> WalkAction) -> WalkResult {
self.walk_children_while(|child| match child.get_kind() {
EntityKind::Constructor | EntityKind::Method | EntityKind::FunctionTemplate | EntityKind::ConversionFunction => {
predicate(child)
}
_ => WalkAction::Continue,
})
}
}