use crate::types::{Namespace, QualifiedName};
use syn::{
ForeignItemFn, Ident, ImplItem, ItemConst, ItemEnum, ItemStruct, ItemType, ItemUse, Type,
};
use super::{
convert_error::{ConvertErrorWithContext, ErrorContext},
ConvertError,
};
#[derive(Copy, Clone, Eq, PartialEq)]
pub(crate) enum TypeKind {
Pod, NonPod, Abstract, }
impl TypeKind {
pub(crate) fn can_be_instantiated(&self) -> bool {
match self {
TypeKind::Pod | TypeKind::NonPod => true,
TypeKind::Abstract => false,
}
}
}
pub(crate) struct ImplBlockDetails {
pub(crate) item: ImplItem,
pub(crate) ty: Ident,
}
#[derive(Clone)]
pub(crate) struct FuncToConvert {
pub(crate) item: ForeignItemFn,
pub(crate) virtual_this_type: Option<QualifiedName>,
pub(crate) self_ty: Option<QualifiedName>,
}
pub(crate) trait AnalysisPhase {
type TypedefAnalysis;
type StructAnalysis;
type FunAnalysis;
}
pub(crate) struct NullAnalysis;
impl AnalysisPhase for NullAnalysis {
type TypedefAnalysis = ();
type StructAnalysis = ();
type FunAnalysis = ();
}
#[derive(Clone)]
pub(crate) enum TypedefKind {
Use(ItemUse),
Type(ItemType),
}
pub(crate) struct ApiName {
pub(crate) name: QualifiedName,
pub(crate) cpp_name: Option<String>,
}
impl ApiName {
pub(crate) fn new(ns: &Namespace, id: Ident) -> Self {
Self {
name: QualifiedName::new(ns, id),
cpp_name: None,
}
}
pub(crate) fn new_in_root_namespace(id: Ident) -> Self {
Self::new(&Namespace::new(), id)
}
}
#[derive(strum_macros::Display)]
pub(crate) enum Api<T: AnalysisPhase> {
ForwardDeclaration { name: ApiName },
ConcreteType {
name: ApiName,
rs_definition: Box<Type>,
cpp_definition: String,
},
StringConstructor { name: ApiName },
Function {
name: ApiName,
fun: Box<FuncToConvert>,
analysis: T::FunAnalysis,
},
Const {
name: ApiName,
const_item: ItemConst,
},
Typedef {
name: ApiName,
item: TypedefKind,
old_tyname: Option<QualifiedName>,
analysis: T::TypedefAnalysis,
},
Enum { name: ApiName, item: ItemEnum },
Struct {
name: ApiName,
item: ItemStruct,
analysis: T::StructAnalysis,
},
CType {
name: ApiName,
typename: QualifiedName,
},
IgnoredItem {
name: ApiName,
err: ConvertError,
ctx: ErrorContext,
},
}
impl<T: AnalysisPhase> Api<T> {
fn name_info(&self) -> &ApiName {
match self {
Api::ForwardDeclaration { name } => name,
Api::ConcreteType { name, .. } => name,
Api::StringConstructor { name } => name,
Api::Function { name, .. } => name,
Api::Const { name, .. } => name,
Api::Typedef { name, .. } => name,
Api::Enum { name, .. } => name,
Api::Struct { name, .. } => name,
Api::CType { name, .. } => name,
Api::IgnoredItem { name, .. } => name,
}
}
pub(crate) fn name(&self) -> &QualifiedName {
&self.name_info().name
}
pub(crate) fn cpp_name(&self) -> &Option<String> {
&self.name_info().cpp_name
}
pub(crate) fn effective_cpp_name(&self) -> &str {
self.cpp_name()
.as_deref()
.unwrap_or_else(|| self.name().get_final_item())
}
}
impl<T: AnalysisPhase> std::fmt::Debug for Api<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} (kind={})", self.name().to_cpp_name(), self,)
}
}
pub(crate) type UnanalyzedApi = Api<NullAnalysis>;
impl<T: AnalysisPhase> Api<T> {
pub(crate) fn typedef_unchanged(
name: ApiName,
item: TypedefKind,
old_tyname: Option<QualifiedName>,
analysis: T::TypedefAnalysis,
) -> Result<Option<Api<T>>, ConvertErrorWithContext> {
Ok(Some(Api::Typedef {
name,
item,
old_tyname,
analysis,
}))
}
pub(crate) fn struct_unchanged(
name: ApiName,
item: ItemStruct,
analysis: T::StructAnalysis,
) -> Result<Option<Api<T>>, ConvertErrorWithContext> {
Ok(Some(Api::Struct {
name,
item,
analysis,
}))
}
pub(crate) fn fun_unchanged(
name: ApiName,
fun: Box<FuncToConvert>,
analysis: T::FunAnalysis,
) -> Result<Option<Api<T>>, ConvertErrorWithContext> {
Ok(Some(Api::Function {
name,
fun,
analysis,
}))
}
pub(crate) fn enum_unchanged(
name: ApiName,
item: ItemEnum,
) -> Result<Option<Api<T>>, ConvertErrorWithContext> {
Ok(Some(Api::Enum { name, item }))
}
}