use crate::types::*; use clang::{EntityKind, Usr}; use thiserror::Error; use std::collections::BTreeMap; use std::convert::TryFrom; // TODO: factor out hardcoded strings #[derive(Debug)] pub(super) struct Children { namespaces: Option>>, variables: Option>>, structs: Option>>, functions: Option>>, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(super) enum ClangEntityKind { Namespace, Variable(VariableKind), Struct(StructKind), Function(FunctionKind), } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(super) enum VariableKind { Variable, Field, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(super) enum StructKind { Struct, Class, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(super) enum FunctionKind { Function, Method, } impl ClangEntityKind { fn to_str_singular(self) -> &'static str { match self { ClangEntityKind::Namespace => "namespace", ClangEntityKind::Variable(VariableKind::Variable) => "variable", ClangEntityKind::Variable(VariableKind::Field) => "field", ClangEntityKind::Struct(StructKind::Struct) => "struct", ClangEntityKind::Struct(StructKind::Class) => "class", ClangEntityKind::Function(FunctionKind::Function) => "function", ClangEntityKind::Function(FunctionKind::Method) => "method", } } fn to_str_plural(self) -> &'static str { match self { ClangEntityKind::Namespace => "namespaces", ClangEntityKind::Variable(VariableKind::Variable) => "variables", ClangEntityKind::Variable(VariableKind::Field) => "fields", ClangEntityKind::Struct(StructKind::Struct) => "structs", ClangEntityKind::Struct(StructKind::Class) => "classes", ClangEntityKind::Function(FunctionKind::Function) => "functions", ClangEntityKind::Function(FunctionKind::Method) => "methods", } } } #[derive(Debug, Error)] #[error("Unsupported Clang entity kind: {:?}", _0)] pub(super) struct TryFromEntityKindError(String); impl TryFrom for ClangEntityKind { type Error = TryFromEntityKindError; fn try_from(kind: EntityKind) -> Result { Ok(match kind { EntityKind::Namespace => ClangEntityKind::Namespace, EntityKind::VarDecl => ClangEntityKind::Variable(VariableKind::Variable), EntityKind::FieldDecl => ClangEntityKind::Variable(VariableKind::Field), EntityKind::FunctionDecl => ClangEntityKind::Function(FunctionKind::Function), EntityKind::Method | EntityKind::Constructor => { ClangEntityKind::Function(FunctionKind::Method) } EntityKind::StructDecl => ClangEntityKind::Struct(StructKind::Struct), EntityKind::ClassDecl => ClangEntityKind::Struct(StructKind::Class), kind => return Err(TryFromEntityKindError(format!("{:?}", kind))), }) } } pub(super) trait ClangEntity { fn kind(&self) -> ClangEntityKind; fn get_member_namespaces(&mut self) -> Option<&mut BTreeMap>> { None } fn get_member_variables(&mut self) -> Option<&mut BTreeMap>> { None } fn get_member_structs(&mut self) -> Option<&mut BTreeMap>> { None } fn get_member_functions(&mut self) -> Option<&mut BTreeMap>> { None } fn into_children(self) -> Children where Self: Sized, { Children { namespaces: None, variables: None, structs: None, functions: None, } } } /* pub(super) trait FromNamespaceParent: ClangEntity + Sized { fn from_namespace_parent<'a>( parent: &'a mut Described, name: &Usr, ) -> Option<&'a mut Described>; } */ pub(super) trait NamespaceParentManipulation { fn get_members_mut(&mut self) -> Option<&mut BTreeMap>>; } impl NamespaceParentManipulation for U where U: ClangEntity, { fn get_members_mut(&mut self) -> Option<&mut BTreeMap>> { self.get_member_namespaces() } } impl NamespaceParentManipulation for U where U: ClangEntity, { fn get_members_mut(&mut self) -> Option<&mut BTreeMap>> { self.get_member_variables() } } impl NamespaceParentManipulation for U where U: ClangEntity, { fn get_members_mut(&mut self) -> Option<&mut BTreeMap>> { self.get_member_functions() } } impl NamespaceParentManipulation for U where U: ClangEntity, { fn get_members_mut(&mut self) -> Option<&mut BTreeMap>> { self.get_member_structs() } } impl From> for Entity { fn from(entity: Described) -> Self { let mut children: BTreeMap> = BTreeMap::new(); let kind = EntityKind(String::from(entity.entity.kind().to_str_singular())); let clang_children = entity.entity.into_children(); if let Some(namespaces) = clang_children.namespaces { for (usr, namespace) in namespaces { children .entry(ChildrenKind(String::from( namespace.entity.kind().to_str_plural(), ))) .or_default() .insert(EntityId(usr.0), namespace.into()); } } if let Some(variables) = clang_children.variables { for (usr, variable) in variables { children .entry(ChildrenKind(String::from( variable.entity.kind().to_str_plural(), ))) .or_default() .insert(EntityId(usr.0), variable.into()); } } if let Some(structs) = clang_children.structs { for (usr, r#struct) in structs { children .entry(ChildrenKind(String::from( r#struct.entity.kind().to_str_plural(), ))) .or_default() .insert(EntityId(usr.0), r#struct.into()); } } if let Some(functions) = clang_children.functions { for (usr, function) in functions { children .entry(ChildrenKind(String::from( function.entity.kind().to_str_plural(), ))) .or_default() .insert(EntityId(usr.0), function.into()); } } Entity { name: entity.description.name, language: Language::Clang, kind, brief_description: entity.description.brief, documentation: entity.description.detailed, children, } } } #[derive(Debug, Clone, Default)] pub(super) struct Description { pub(super) name: String, pub(super) brief: String, pub(super) detailed: String, } #[derive(Debug, Clone)] pub(super) struct Described { pub(super) description: Description, pub(super) entity: T, } #[derive(Debug, Clone)] pub(super) struct Namespace { pub(super) member_namespaces: BTreeMap>, pub(super) member_variables: BTreeMap>, pub(super) member_structs: BTreeMap>, pub(super) member_functions: BTreeMap>, } impl ClangEntity for Namespace { fn kind(&self) -> ClangEntityKind { ClangEntityKind::Namespace } fn get_member_namespaces(&mut self) -> Option<&mut BTreeMap>> { Some(&mut self.member_namespaces) } fn get_member_variables(&mut self) -> Option<&mut BTreeMap>> { Some(&mut self.member_variables) } fn get_member_structs(&mut self) -> Option<&mut BTreeMap>> { Some(&mut self.member_structs) } fn get_member_functions(&mut self) -> Option<&mut BTreeMap>> { Some(&mut self.member_functions) } fn into_children(self) -> Children { Children { namespaces: Some(self.member_namespaces), variables: Some(self.member_variables), structs: Some(self.member_structs), functions: Some(self.member_functions), } } } /* impl FromNamespaceParent for Namespace { fn from_namespace_parent<'a>( parent: &'a mut Described, name: &Usr, ) -> Option<&'a mut Described> { parent.entity.member_namespaces.get_mut(name) } } */ #[derive(Debug, Clone)] pub(super) struct Variable { pub(super) kind: VariableKind, pub(super) r#type: String, } impl ClangEntity for Variable { fn kind(&self) -> ClangEntityKind { ClangEntityKind::Variable(self.kind) } } /* impl FromNamespaceParent for Variable { fn from_namespace_parent<'a>( parent: &'a mut Described, name: &Usr, ) -> Option<&'a mut Described> { parent.entity.member_variables.get_mut(name) } } */ #[derive(Debug, Clone)] pub(super) struct Struct { //pub(super) member_types: Vec, pub(super) kind: StructKind, pub(super) member_variables: BTreeMap>, pub(super) member_structs: BTreeMap>, pub(super) member_functions: BTreeMap>, } impl ClangEntity for Struct { fn kind(&self) -> ClangEntityKind { ClangEntityKind::Struct(self.kind) } fn get_member_variables(&mut self) -> Option<&mut BTreeMap>> { Some(&mut self.member_variables) } fn get_member_structs(&mut self) -> Option<&mut BTreeMap>> { Some(&mut self.member_structs) } fn get_member_functions(&mut self) -> Option<&mut BTreeMap>> { Some(&mut self.member_functions) } fn into_children(self) -> Children { Children { namespaces: None, variables: Some(self.member_variables), structs: Some(self.member_structs), functions: Some(self.member_functions), } } } /* impl FromNamespaceParent for Struct { fn from_namespace_parent<'a>( parent: &'a mut Described, name: &Usr, ) -> Option<&'a mut Described> { parent.entity.member_structs.get_mut(name) } } */ #[derive(Debug, Clone)] pub(super) struct Function { pub(super) kind: FunctionKind, pub(super) arguments: Vec, pub(super) return_type: String, } impl ClangEntity for Function { fn kind(&self) -> ClangEntityKind { ClangEntityKind::Function(self.kind) } } /* impl FromNamespaceParent for Function { fn from_namespace_parent<'a>( parent: &'a mut Described, name: &Usr, ) -> Option<&'a mut Described> { parent.entity.member_functions.get_mut(name) } } */ #[derive(Debug, Clone)] pub(super) struct FunctionArgument { pub(super) name: String, pub(super) r#type: String, }