Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

An initial implementation of objective-c generics for #1259 #1702

Merged
merged 2 commits into from
Jan 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 32 additions & 6 deletions src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3728,18 +3728,44 @@ impl CodeGenerator for ObjCInterface {

let trait_name = ctx.rust_ident(self.rust_name());

let trait_block = quote! {
pub trait #trait_name {
#( #trait_items )*
let trait_block = if self.is_template() {
let template_names: Vec<Ident> = self
.template_names
.iter()
.map(|g| ctx.rust_ident(g))
.collect();
quote! {
pub trait #trait_name <#(#template_names),*>{
#( #trait_items )*
}
}
} else {
quote! {
pub trait #trait_name {
#( #trait_items )*
}
}
};

let ty_for_impl = quote! {
id
};
let impl_block = quote! {
impl #trait_name for #ty_for_impl {
#( #impl_items )*
let impl_block = if self.is_template() {
let template_names: Vec<Ident> = self
.template_names
.iter()
.map(|g| ctx.rust_ident(g))
.collect();
quote! {
impl <#(#template_names :'static),*> #trait_name <#(#template_names),*> for #ty_for_impl {
#( #impl_items )*
}
}
} else {
quote! {
impl #trait_name for #ty_for_impl {
#( #impl_items )*
}
}
};

Expand Down
18 changes: 16 additions & 2 deletions src/ir/objc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use clang_sys::CXCursor_ObjCClassRef;
use clang_sys::CXCursor_ObjCInstanceMethodDecl;
use clang_sys::CXCursor_ObjCProtocolDecl;
use clang_sys::CXCursor_ObjCProtocolRef;
use clang_sys::CXCursor_TemplateTypeParameter;
use proc_macro2::{Ident, Span, TokenStream};

/// Objective C interface as used in TypeKind
Expand All @@ -27,6 +28,9 @@ pub struct ObjCInterface {

is_protocol: bool,

/// The list of template names almost always, ObjectType or KeyType
pub template_names: Vec<String>,

conforms_to: Vec<ItemId>,

/// List of the methods defined in this interfae
Expand Down Expand Up @@ -58,6 +62,7 @@ impl ObjCInterface {
name: name.to_owned(),
category: None,
is_protocol: false,
template_names: Vec::new(),
conforms_to: Vec::new(),
methods: Vec::new(),
class_methods: Vec::new(),
Expand Down Expand Up @@ -85,6 +90,11 @@ impl ObjCInterface {
}
}

/// Is this a template interface?
pub fn is_template(&self) -> bool {
!self.template_names.is_empty()
}

/// List of the methods defined in this interface
pub fn methods(&self) -> &Vec<ObjCMethod> {
&self.methods
Expand Down Expand Up @@ -154,6 +164,10 @@ impl ObjCInterface {
let method = ObjCMethod::new(&name, signature, is_class_method);
interface.add_method(method);
}
CXCursor_TemplateTypeParameter => {
let name = c.spelling();
interface.template_names.push(name);
}
_ => {}
}
CXChildVisit_Continue
Expand Down Expand Up @@ -183,8 +197,8 @@ impl ObjCMethod {
ObjCMethod {
name: name.to_owned(),
rust_name: rust_name.to_owned(),
signature: signature,
is_class_method: is_class_method,
signature,
is_class_method,
}
}

Expand Down
14 changes: 12 additions & 2 deletions tests/expectations/tests/libclang-3.8/objc_template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,21 @@
extern crate objc;
#[allow(non_camel_case_types)]
pub type id = *mut objc::runtime::Object;
pub trait Foo {
pub trait Foo<ObjectType> {
unsafe fn get(self) -> id;
}
impl Foo for id {
impl<ObjectType: 'static> Foo<ObjectType> for id {
unsafe fn get(self) -> id {
msg_send!(self, get)
}
}
pub trait FooMultiGeneric<KeyType, ObjectType> {
unsafe fn objectForKey_(self, key: id) -> id;
}
impl<KeyType: 'static, ObjectType: 'static> FooMultiGeneric<KeyType, ObjectType>
for id
{
unsafe fn objectForKey_(self, key: id) -> id {
msg_send!(self, objectForKey: key)
}
}
14 changes: 12 additions & 2 deletions tests/expectations/tests/libclang-3.9/objc_template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,21 @@
extern crate objc;
#[allow(non_camel_case_types)]
pub type id = *mut objc::runtime::Object;
pub trait Foo {
pub trait Foo<ObjectType> {
unsafe fn get(self) -> id;
}
impl Foo for id {
impl<ObjectType: 'static> Foo<ObjectType> for id {
unsafe fn get(self) -> id {
msg_send!(self, get)
}
}
pub trait FooMultiGeneric<KeyType, ObjectType> {
unsafe fn objectForKey_(self, key: id) -> id;
}
impl<KeyType: 'static, ObjectType: 'static> FooMultiGeneric<KeyType, ObjectType>
for id
{
unsafe fn objectForKey_(self, key: id) -> id {
msg_send!(self, objectForKey: key)
}
}
14 changes: 12 additions & 2 deletions tests/expectations/tests/libclang-4/objc_template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,20 @@
extern crate objc;
#[allow(non_camel_case_types)]
pub type id = *mut objc::runtime::Object;
pub trait Foo {
pub trait Foo<ObjectType> {
unsafe fn get(self)
-> *mut ObjectType;
}
impl Foo for id {
impl<ObjectType: 'static> Foo<ObjectType> for id {
unsafe fn get(self) -> *mut ObjectType { msg_send!(self , get) }
}
pub trait FooMultiGeneric<KeyType, ObjectType> {
unsafe fn objectForKey_(self, key: *mut KeyType) -> *mut ObjectType;
}
impl<KeyType: 'static, ObjectType: 'static> FooMultiGeneric<KeyType, ObjectType>
for id
{
unsafe fn objectForKey_(self, key: *mut KeyType) -> *mut ObjectType {
msg_send!(self, objectForKey: key)
}
}
32 changes: 23 additions & 9 deletions tests/expectations/tests/libclang-5/objc_template.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,32 @@
/* automatically generated by rust-bindgen */


#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]

#![cfg(target_os="macos")]
#![allow(
dead_code,
non_snake_case,
non_camel_case_types,
non_upper_case_globals
)]
#![cfg(target_os = "macos")]

#[macro_use]
extern crate objc;
#[allow(non_camel_case_types)]
pub type id = *mut objc::runtime::Object;
pub trait Foo {
unsafe fn get(self)
-> *mut ObjectType;
pub trait Foo<ObjectType> {
unsafe fn get(self) -> *mut ObjectType;
}
impl<ObjectType: 'static> Foo<ObjectType> for id {
unsafe fn get(self) -> *mut ObjectType {
msg_send!(self, get)
}
}
pub trait FooMultiGeneric<KeyType, ObjectType> {
unsafe fn objectForKey_(self, key: *mut KeyType) -> *mut ObjectType;
}
impl Foo for id {
unsafe fn get(self) -> *mut ObjectType { msg_send!(self , get) }
impl<KeyType: 'static, ObjectType: 'static> FooMultiGeneric<KeyType, ObjectType>
for id
{
unsafe fn objectForKey_(self, key: *mut KeyType) -> *mut ObjectType {
msg_send!(self, objectForKey: key)
}
}
14 changes: 12 additions & 2 deletions tests/expectations/tests/libclang-9/objc_template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,21 @@
extern crate objc;
#[allow(non_camel_case_types)]
pub type id = *mut objc::runtime::Object;
pub trait Foo {
pub trait Foo<ObjectType> {
unsafe fn get(self) -> u64;
}
impl Foo for id {
impl<ObjectType: 'static> Foo<ObjectType> for id {
unsafe fn get(self) -> u64 {
msg_send!(self, get)
}
}
pub trait FooMultiGeneric<KeyType, ObjectType> {
unsafe fn objectForKey_(self, key: u64) -> u64;
}
impl<KeyType: 'static, ObjectType: 'static> FooMultiGeneric<KeyType, ObjectType>
for id
{
unsafe fn objectForKey_(self, key: u64) -> u64 {
msg_send!(self, objectForKey: key)
}
}
4 changes: 4 additions & 0 deletions tests/headers/objc_template.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@
@interface Foo<__covariant ObjectType>
- (ObjectType)get;
@end

@interface FooMultiGeneric<__covariant KeyType, __covariant ObjectType>
- (nullable ObjectType)objectForKey:(KeyType)key;
@end