use crate::types::{make_ident, Namespace, QualifiedName};
use syn::{
punctuated::Punctuated, token::Comma, FnArg, ForeignItemFn, Ident, ImplItem, ItemConst,
ItemEnum, ItemStruct, ItemType, ItemUse, ReturnType, Type,
};
use super::{
analysis::fun::{function_wrapper::CppFunction, ReceiverMutability},
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 NullPhase;
impl AnalysisPhase for NullPhase {
type TypedefAnalysis = ();
type StructAnalysis = ();
type FunAnalysis = ();
}
#[derive(Clone)]
pub(crate) enum TypedefKind {
Use(ItemUse),
Type(ItemType),
}
#[derive(Clone, Hash, PartialEq, Eq, Debug)]
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(Clone, Hash, PartialEq, Eq)]
pub(crate) struct SubclassName(pub(crate) ApiName);
impl SubclassName {
pub(crate) fn new(id: Ident) -> Self {
Self(ApiName::new_in_root_namespace(id))
}
pub(crate) fn id(&self) -> Ident {
self.0.name.get_final_ident()
}
pub(crate) fn holder(&self) -> Ident {
self.with_suffix("Holder")
}
pub(crate) fn cpp(&self) -> Ident {
self.with_suffix("Cpp")
}
pub(crate) fn cpp_remove_ownership(&self) -> Ident {
self.with_suffix("Cpp_remove_ownership")
}
pub(crate) fn remove_ownership(&self) -> Ident {
self.with_suffix("_remove_ownership")
}
fn with_suffix(&self, suffix: &str) -> Ident {
make_ident(format!("{}{}", self.0.name.get_final_item(), suffix))
}
pub(crate) fn get_super_fn_name(id: &str) -> Ident {
make_ident(format!("{}_super", 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,
name_for_gc: Option<QualifiedName>,
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,
},
RustType { name: ApiName },
RustSubclassFn {
name: ApiName,
subclass: SubclassName,
details: Box<RustSubclassFnDetails>,
},
RustSubclassConstructor {
name: ApiName,
subclass: SubclassName,
cpp_impl: Box<CppFunction>,
is_trivial: bool,
},
Subclass {
name: SubclassName,
superclass: QualifiedName,
},
}
pub(crate) struct RustSubclassFnDetails {
pub(crate) params: Punctuated<FnArg, Comma>,
pub(crate) ret: ReturnType,
pub(crate) cpp_impl: CppFunction,
pub(crate) method_name: Ident,
pub(crate) superclass: QualifiedName,
pub(crate) receiver_mutability: ReceiverMutability,
pub(crate) super_fn_api_name: QualifiedName,
}
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,
Api::RustType { name, .. } => name,
Api::RustSubclassFn { name, .. } => name,
Api::RustSubclassConstructor { name, .. } => name,
Api::Subclass { name, .. } => &name.0,
}
}
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<NullPhase>;
impl<T: AnalysisPhase> Api<T> {
pub(crate) fn typedef_unchanged(
name: ApiName,
item: TypedefKind,
old_tyname: Option<QualifiedName>,
analysis: T::TypedefAnalysis,
) -> Result<Box<dyn Iterator<Item = Api<T>>>, ConvertErrorWithContext>
where
T: 'static,
{
Ok(Box::new(std::iter::once(Api::Typedef {
name,
item,
old_tyname,
analysis,
})))
}
pub(crate) fn struct_unchanged(
name: ApiName,
item: ItemStruct,
analysis: T::StructAnalysis,
) -> Result<Box<dyn Iterator<Item = Api<T>>>, ConvertErrorWithContext>
where
T: 'static,
{
Ok(Box::new(std::iter::once(Api::Struct {
name,
item,
analysis,
})))
}
pub(crate) fn fun_unchanged(
name: ApiName,
fun: Box<FuncToConvert>,
analysis: T::FunAnalysis,
name_for_gc: Option<QualifiedName>,
) -> Result<Box<dyn Iterator<Item = Api<T>>>, ConvertErrorWithContext>
where
T: 'static,
{
Ok(Box::new(std::iter::once(Api::Function {
name,
fun,
analysis,
name_for_gc,
})))
}
pub(crate) fn enum_unchanged(
name: ApiName,
item: ItemEnum,
) -> Result<Box<dyn Iterator<Item = Api<T>>>, ConvertErrorWithContext>
where
T: 'static,
{
Ok(Box::new(std::iter::once(Api::Enum { name, item })))
}
}