use crate::types::Entity; 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, PartialEq, Eq)] pub(super) enum ClangEntityKind { Namespace, Variable(VariableKind), Struct(StructKind), Function(FunctionKind), } #[derive(Debug, Clone, PartialEq, Eq)] pub(super) enum VariableKind { Variable, Field, } #[derive(Debug, Clone, PartialEq, Eq)] pub(super) enum StructKind { Struct, Class, } #[derive(Debug, Clone, PartialEq, Eq)] pub(super) enum FunctionKind { Function, Method, } #[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) -> &'static str; 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::new(); let kind = String::from(entity.entity.kind()); let clang_children = entity.entity.into_children(); if let Some(namespaces) = clang_children.namespaces { children.insert( String::from("namespace"), namespaces .into_iter() .map(|(usr, namespace)| (usr.0, namespace.into())) .collect(), ); } if let Some(variables) = clang_children.variables { children.insert( String::from("variable"), variables .into_iter() .map(|(usr, variable)| (usr.0, variable.into())) .collect(), ); } if let Some(structs) = clang_children.structs { children.insert( String::from("struct"), structs .into_iter() .map(|(usr, the_struct)| (usr.0, the_struct.into())) .collect(), ); } if let Some(functions) = clang_children.functions { children.insert( String::from("function"), functions .into_iter() .map(|(usr, function)| (usr.0, function.into())) .collect(), ); } Entity { name: entity.description.name, language: String::from("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) -> &'static str { "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) -> &'static str { match self.kind { VariableKind::Variable => "variable", VariableKind::Field => "field", } } } /* 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) -> &'static str { match self.kind { StructKind::Struct => "struct", StructKind::Class => "class", } } 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) -> &'static str { match self.kind { FunctionKind::Function => "function", FunctionKind::Method => "method", } } } /* 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, }