use crate::{
conversion::api::SubclassName,
types::{Namespace, QualifiedName},
};
use quote::ToTokens;
use syn::{parse_quote, Ident, Type, TypeReference};
#[derive(Clone, Debug)]
pub(crate) enum CppConversionType {
None,
Move,
FromUniquePtrToValue,
FromPtrToValue,
FromValueToUniquePtr,
FromPtrToMove,
IgnoredPlacementPtrParameter,
FromReturnValueToPlacementPtr,
FromPointerToReference, FromReferenceToPointer, }
impl CppConversionType {
fn inverse(&self) -> Self {
match self {
CppConversionType::None => CppConversionType::None,
CppConversionType::FromUniquePtrToValue | CppConversionType::FromPtrToValue => {
CppConversionType::FromValueToUniquePtr
}
CppConversionType::FromValueToUniquePtr => CppConversionType::FromUniquePtrToValue,
CppConversionType::FromPointerToReference => CppConversionType::FromReferenceToPointer,
CppConversionType::FromReferenceToPointer => CppConversionType::FromPointerToReference,
_ => panic!("Did not expect to have to invert this conversion"),
}
}
}
#[derive(Clone, Debug)]
pub(crate) enum RustConversionType {
None,
FromStr,
ToBoxedUpHolder(SubclassName),
FromPinMaybeUninitToPtr,
FromPinMoveRefToPtr,
FromTypeToPtr,
FromValueParamToPtr,
FromPlacementParamToNewReturn,
FromRValueParamToPtr,
FromReferenceWrapperToPointer, FromPointerToReferenceWrapper, }
impl RustConversionType {
pub(crate) fn requires_mutability(&self) -> Option<syn::token::Mut> {
match self {
Self::FromPinMoveRefToPtr => Some(parse_quote! { mut }),
_ => None,
}
}
}
#[derive(Clone)]
pub(crate) struct TypeConversionPolicy {
unwrapped_type: Type,
pub(crate) cpp_conversion: CppConversionType,
pub(crate) rust_conversion: RustConversionType,
}
impl TypeConversionPolicy {
pub(crate) fn new_unconverted(ty: Type) -> Self {
Self::new(ty, CppConversionType::None, RustConversionType::None)
}
pub(crate) fn new(
ty: Type,
cpp_conversion: CppConversionType,
rust_conversion: RustConversionType,
) -> Self {
Self {
unwrapped_type: ty,
cpp_conversion,
rust_conversion,
}
}
pub(crate) fn cxxbridge_type(&self) -> &Type {
&self.unwrapped_type
}
pub(crate) fn return_reference_into_wrapper(ty: Type) -> Self {
let (unwrapped_type, is_mut) = match ty {
Type::Reference(TypeReference {
elem, mutability, ..
}) => (*elem, mutability.is_some()),
_ => panic!("Not a ptr: {}", ty.to_token_stream()),
};
TypeConversionPolicy {
unwrapped_type: if is_mut {
parse_quote! { *mut #unwrapped_type }
} else {
parse_quote! { *const #unwrapped_type }
},
cpp_conversion: CppConversionType::FromReferenceToPointer,
rust_conversion: RustConversionType::FromPointerToReferenceWrapper,
}
}
pub(crate) fn new_to_unique_ptr(ty: Type) -> Self {
TypeConversionPolicy {
unwrapped_type: ty,
cpp_conversion: CppConversionType::FromValueToUniquePtr,
rust_conversion: RustConversionType::None,
}
}
pub(crate) fn new_for_placement_return(ty: Type) -> Self {
TypeConversionPolicy {
unwrapped_type: ty,
cpp_conversion: CppConversionType::FromReturnValueToPlacementPtr,
rust_conversion: RustConversionType::None,
}
}
pub(crate) fn cpp_work_needed(&self) -> bool {
!matches!(self.cpp_conversion, CppConversionType::None)
}
pub(crate) fn unconverted_rust_type(&self) -> Type {
match self.cpp_conversion {
CppConversionType::FromValueToUniquePtr => self.make_unique_ptr_type(),
_ => self.unwrapped_type.clone(),
}
}
pub(crate) fn converted_rust_type(&self) -> Type {
match self.cpp_conversion {
CppConversionType::FromUniquePtrToValue => self.make_unique_ptr_type(),
CppConversionType::FromPtrToValue => {
let innerty = &self.unwrapped_type;
parse_quote! {
*mut #innerty
}
}
_ => self.unwrapped_type.clone(),
}
}
fn make_unique_ptr_type(&self) -> Type {
let innerty = &self.unwrapped_type;
parse_quote! {
cxx::UniquePtr < #innerty >
}
}
pub(crate) fn rust_work_needed(&self) -> bool {
!matches!(self.rust_conversion, RustConversionType::None)
}
pub(crate) fn inverse(&self) -> Self {
Self {
unwrapped_type: self.unwrapped_type.clone(),
cpp_conversion: self.cpp_conversion.inverse(),
rust_conversion: self.rust_conversion.clone(),
}
}
pub(crate) fn bridge_unsafe_needed(&self) -> bool {
matches!(
self.rust_conversion,
RustConversionType::FromValueParamToPtr
| RustConversionType::FromRValueParamToPtr
| RustConversionType::FromPlacementParamToNewReturn
| RustConversionType::FromPointerToReferenceWrapper { .. }
| RustConversionType::FromReferenceWrapperToPointer { .. }
)
}
pub(crate) fn is_placement_parameter(&self) -> bool {
matches!(
self.cpp_conversion,
CppConversionType::IgnoredPlacementPtrParameter
)
}
pub(crate) fn populate_return_value(&self) -> bool {
!matches!(
self.cpp_conversion,
CppConversionType::FromReturnValueToPlacementPtr
)
}
}
#[derive(Clone)]
pub(crate) enum CppFunctionBody {
FunctionCall(Namespace, Ident),
StaticMethodCall(Namespace, Ident, Ident),
PlacementNew(Namespace, Ident),
ConstructSuperclass(String),
Cast,
Destructor(Namespace, Ident),
AllocUninitialized(QualifiedName),
FreeUninitialized(QualifiedName),
}
#[derive(Clone)]
pub(crate) enum CppFunctionKind {
Function,
Method,
Constructor,
ConstMethod,
SynthesizedConstructor,
}
#[derive(Clone)]
pub(crate) struct CppFunction {
pub(crate) payload: CppFunctionBody,
pub(crate) wrapper_function_name: Ident,
pub(crate) original_cpp_name: String,
pub(crate) return_conversion: Option<TypeConversionPolicy>,
pub(crate) argument_conversion: Vec<TypeConversionPolicy>,
pub(crate) kind: CppFunctionKind,
pub(crate) pass_obs_field: bool,
pub(crate) qualification: Option<QualifiedName>,
}