use std::collections::HashSet;
use crate::types::{make_ident, Namespace, QualifiedName};
use autocxx_parser::RustPath;
use syn::{
punctuated::Punctuated, token::Comma, Attribute, FnArg, Ident, ImplItem, ItemConst, ItemEnum,
ItemStruct, ItemType, ItemUse, ReturnType, Signature, Type, Visibility,
};
use super::{
analysis::fun::{function_wrapper::CppFunction, ReceiverMutability},
convert_error::{ConvertErrorWithContext, ErrorContext},
ConvertError,
};
#[derive(Copy, Clone, Eq, PartialEq)]
pub(crate) enum TypeKind {
Pod, NonPod, NonPodNested, Abstract, }
pub(crate) struct ImplBlockDetails {
pub(crate) item: ImplItem,
pub(crate) ty: Ident,
}
#[derive(Clone, PartialEq, Eq, Copy)]
pub(crate) enum CppVisibility {
Public,
Protected,
Private,
}
#[derive(Clone)]
pub(crate) struct FuncToConvert {
pub(crate) ident: Ident,
pub(crate) doc_attr: Option<Attribute>,
pub(crate) inputs: Punctuated<FnArg, Comma>,
pub(crate) output: ReturnType,
pub(crate) vis: Visibility,
pub(crate) is_pure_virtual: bool,
pub(crate) cpp_vis: CppVisibility,
pub(crate) is_move_constructor: bool,
pub(crate) unused_template_param: bool,
pub(crate) return_type_is_reference: bool,
pub(crate) reference_args: HashSet<Ident>,
pub(crate) original_name: Option<String>,
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)]
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::new_from_qualified_name(QualifiedName::new(ns, id))
}
pub(crate) fn new_with_cpp_name(ns: &Namespace, id: Ident, cpp_name: Option<String>) -> Self {
Self {
name: QualifiedName::new(ns, id),
cpp_name,
}
}
pub(crate) fn new_from_qualified_name(name: QualifiedName) -> Self {
Self {
name,
cpp_name: None,
}
}
pub(crate) fn new_in_root_namespace(id: Ident) -> Self {
Self::new(&Namespace::new(), id)
}
pub(crate) fn is_nested_struct_or_class(&self) -> bool {
self.cpp_name
.as_ref()
.map(|n| n.contains("::"))
.unwrap_or_default()
}
pub(crate) fn cpp_name(&self) -> String {
self.cpp_name
.as_ref()
.cloned()
.unwrap_or_else(|| self.name.get_final_item().to_string())
}
}
impl std::fmt::Debug for ApiName {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.name)?;
if let Some(cpp_name) = &self.cpp_name {
write!(f, " (cpp={})", cpp_name)?;
}
Ok(())
}
}
#[derive(Clone, Hash, PartialEq, Eq, Debug)]
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 from_holder_name(id: &Ident) -> Self {
Self::new(make_ident(id.to_string().strip_suffix("Holder").unwrap()))
}
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) -> QualifiedName {
let id = self.with_suffix("Cpp");
QualifiedName::new(self.0.name.get_namespace(), id)
}
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(superclass_namespace: &Namespace, id: &str) -> QualifiedName {
let id = make_ident(format!("{}_super", id));
QualifiedName::new(superclass_namespace, id)
}
pub(crate) fn get_methods_trait_name(superclass_name: &QualifiedName) -> QualifiedName {
Self::with_qualified_name_suffix(superclass_name, "methods")
}
pub(crate) fn get_supers_trait_name(superclass_name: &QualifiedName) -> QualifiedName {
Self::with_qualified_name_suffix(superclass_name, "supers")
}
fn with_qualified_name_suffix(name: &QualifiedName, suffix: &str) -> QualifiedName {
let id = make_ident(format!("{}_{}", name.get_final_item(), suffix));
QualifiedName::new(name.get_namespace(), 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, path: RustPath },
RustFn {
name: ApiName,
sig: Signature,
path: RustPath,
},
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) dependency: Option<QualifiedName>,
pub(crate) requires_unsafe: bool,
pub(crate) is_pure_virtual: bool,
}
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::RustFn { 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())
}
pub(crate) fn valid_types(&self) -> Box<dyn Iterator<Item = QualifiedName>> {
match self {
Api::Subclass { name, .. } => Box::new(
vec![
self.name().clone(),
QualifiedName::new(&Namespace::new(), name.holder()),
]
.into_iter(),
),
_ => Box::new(std::iter::once(self.name().clone())),
}
}
}
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_info(), 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 })))
}
}