Skip to content

Commit

Permalink
Clean up how return types work
Browse files Browse the repository at this point in the history
  • Loading branch information
madsmtm committed Oct 7, 2022
1 parent 9ca84bf commit 8f1a9ed
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 69 deletions.
29 changes: 10 additions & 19 deletions header-translator/src/method.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use clang::{Entity, EntityKind, EntityVisitResult, ObjCQualifiers, TypeKind};
use clang::{Entity, EntityKind, EntityVisitResult, ObjCQualifiers};
use proc_macro2::TokenStream;
use quote::{format_ident, quote, ToTokens, TokenStreamExt};

use crate::availability::Availability;
use crate::config::ClassData;
use crate::objc2_utils::in_selector_family;
use crate::rust_type::RustType;
use crate::rust_type::{RustType, RustTypeReturn};

#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
enum Qualifier {
Expand Down Expand Up @@ -120,7 +120,7 @@ pub struct Method {
memory_management: MemoryManagement,
designated_initializer: bool,
arguments: Vec<(String, Option<Qualifier>, RustType)>,
result_type: Option<RustType>,
result_type: RustTypeReturn,
safe: bool,
}

Expand Down Expand Up @@ -201,19 +201,16 @@ impl Method {
})
.collect();

let result_type = entity.get_result_type().expect("method return type");
if let Some(qualifiers) = entity.get_objc_qualifiers() {
let qualifier = Qualifier::parse(qualifiers);
panic!(
"unexpected qualifier `{:?}` on return type: {:?}",
qualifier, entity
);
}
let result_type = if result_type.get_kind() != TypeKind::Void {
Some(RustType::parse_return(result_type))
} else {
None
};

let result_type = entity.get_result_type().expect("method return type");
let result_type = RustTypeReturn::parse(result_type);

let mut designated_initializer = false;
let mut consumes_self = false;
Expand Down Expand Up @@ -273,10 +270,8 @@ impl Method {
}

// Verify that memory management is as expected
if let Some(type_) = &result_type {
if type_.is_id() {
memory_management.verify_sel(&selector);
}
if result_type.is_id() {
memory_management.verify_sel(&selector);
}

Some(Self {
Expand Down Expand Up @@ -333,13 +328,9 @@ impl ToTokens for Method {
quote!(#sel)
};

let (ret, is_id) = if let Some(type_) = &self.result_type {
(quote!(-> #type_), type_.is_id())
} else {
(quote!(), false)
};
let ret = &self.result_type;

let macro_name = if is_id {
let macro_name = if self.result_type.is_id() {
format_ident!("msg_send_id")
} else {
format_ident!("msg_send")
Expand Down
116 changes: 66 additions & 50 deletions header-translator/src/rust_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,9 @@ impl GenericType {
.get_objc_type_arguments()
.into_iter()
.map(|param| {
match RustType::parse(param, false, false) {
match RustType::parse(param, false) {
RustType::Id {
type_,
is_return: _,
is_const: _,
lifetime: _,
nullability: _,
Expand Down Expand Up @@ -267,7 +266,6 @@ pub enum RustType {
// Objective-C
Id {
type_: GenericType,
is_return: bool,
is_const: bool,
lifetime: Lifetime,
nullability: Nullability,
Expand Down Expand Up @@ -297,11 +295,7 @@ pub enum RustType {
}

impl RustType {
pub fn is_id(&self) -> bool {
matches!(self, Self::Id { .. })
}

fn parse(ty: Type<'_>, is_return: bool, is_consumed: bool) -> Self {
fn parse(ty: Type<'_>, is_consumed: bool) -> Self {
use TypeKind::*;

// println!("{:?}, {:?}", ty, ty.get_class_type());
Expand Down Expand Up @@ -333,7 +327,6 @@ impl RustType {
name: "Object".to_string(),
generics: Vec::new(),
},
is_return,
is_const: ty.is_const_qualified(),
lifetime,
nullability,
Expand All @@ -345,7 +338,7 @@ impl RustType {
let ty = ty.get_pointee_type().expect("pointer type to have pointee");
// Note: Can't handle const id pointers
// assert!(!ty.is_const_qualified(), "expected pointee to not be const");
let pointee = Self::parse(ty, false, is_consumed);
let pointee = Self::parse(ty, is_consumed);
Self::Pointer {
nullability,
is_const,
Expand All @@ -360,7 +353,6 @@ impl RustType {

Self::Id {
type_,
is_return,
is_const: ty.is_const_qualified(),
lifetime,
nullability,
Expand All @@ -378,21 +370,15 @@ impl RustType {
"uint32_t" => Self::U32,
"int164_t" => Self::I64,
"uint64_t" => Self::U64,
"instancetype" => {
if !is_return {
panic!("instancetype in non-return position")
}
Self::Id {
type_: GenericType {
name: "Self".to_string(),
generics: Vec::new(),
},
is_return,
is_const: ty.is_const_qualified(),
lifetime,
nullability,
}
}
"instancetype" => Self::Id {
type_: GenericType {
name: "Self".to_string(),
generics: Vec::new(),
},
is_const: ty.is_const_qualified(),
lifetime,
nullability,
},
_ => {
let ty = ty.get_canonical_type();
match ty.get_kind() {
Expand All @@ -409,7 +395,6 @@ impl RustType {
name: typedef_name,
generics: Vec::new(),
},
is_return,
is_const: ty.is_const_qualified(),
lifetime,
nullability,
Expand All @@ -432,7 +417,6 @@ impl RustType {
ConstantArray => {
let element_type = Self::parse(
ty.get_element_type().expect("array to have element type"),
false,
is_consumed,
);
let num_elements = ty
Expand Down Expand Up @@ -460,20 +444,8 @@ impl RustType {
}
}

pub fn parse_return(ty: Type<'_>) -> Self {
let this = Self::parse(ty, true, false);

this.visit_lifetime(|lifetime| {
if lifetime != Lifetime::Unspecified {
panic!("unexpected lifetime in return {this:?}");
}
});

this
}

pub fn parse_argument(ty: Type<'_>, is_consumed: bool) -> Self {
let this = Self::parse(ty, false, is_consumed);
let this = Self::parse(ty, is_consumed);

match &this {
Self::Pointer { pointee, .. } => pointee.visit_lifetime(|lifetime| {
Expand All @@ -492,7 +464,7 @@ impl RustType {
}

pub fn parse_typedef(ty: Type<'_>) -> Self {
let this = Self::parse(ty, false, false);
let this = Self::parse(ty, false);

this.visit_lifetime(|lifetime| {
if lifetime != Lifetime::Unspecified {
Expand Down Expand Up @@ -536,18 +508,13 @@ impl ToTokens for RustType {
// Objective-C
Id {
type_,
is_return,
// Ignore
is_const: _,
// Ignore
lifetime: _,
nullability,
} => {
let tokens = if *is_return {
quote!(Id<#type_, Shared>)
} else {
quote!(&#type_)
};
let tokens = quote!(&#type_);
if *nullability == Nullability::NonNull {
tokens
} else {
Expand Down Expand Up @@ -578,7 +545,6 @@ impl ToTokens for RustType {
} => match &**pointee {
Self::Id {
type_: tokens,
is_return: false,
is_const: false,
lifetime: Lifetime::Autoreleasing,
nullability: inner_nullability,
Expand All @@ -603,7 +569,6 @@ impl ToTokens for RustType {
}
Self::Id {
type_: tokens,
is_return: false,
is_const: false,
lifetime: Lifetime::Unspecified,
nullability: inner_nullability,
Expand Down Expand Up @@ -649,3 +614,54 @@ impl ToTokens for RustType {
tokens.append_all(result);
}
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct RustTypeReturn {
inner: RustType,
}

impl RustTypeReturn {
pub fn is_id(&self) -> bool {
matches!(self.inner, RustType::Id { .. })
}

pub fn new(inner: RustType) -> Self {
Self { inner }
}

pub fn parse(ty: Type<'_>) -> Self {
let inner = RustType::parse(ty, false);

inner.visit_lifetime(|lifetime| {
if lifetime != Lifetime::Unspecified {
panic!("unexpected lifetime in return {inner:?}");
}
});

Self::new(inner)
}
}

impl ToTokens for RustTypeReturn {
fn to_tokens(&self, tokens: &mut TokenStream) {
let result = match &self.inner {
RustType::Void => return,
RustType::Id {
type_,
// Ignore
is_const: _,
// Ignore
lifetime: _,
nullability,
} => {
if *nullability == Nullability::NonNull {
quote!(Id<#type_, Shared>)
} else {
quote!(Option<Id<#type_, Shared>>)
}
}
type_ => quote!(#type_),
};
tokens.append_all(quote!(-> #result));
}
}

0 comments on commit 8f1a9ed

Please sign in to comment.