Skip to content

Commit 4562ef9

Browse files
simlayemilio
authored andcommitted
Added some initial constraints to the objective-c bindgen stuff
1 parent cfd3347 commit 4562ef9

17 files changed

+557
-255
lines changed

src/codegen/mod.rs

Lines changed: 78 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -3394,9 +3394,12 @@ impl TryToRustTy for Type {
33943394
TypeKind::ObjCSel => Ok(quote! {
33953395
objc::runtime::Sel
33963396
}),
3397-
TypeKind::ObjCId | TypeKind::ObjCInterface(..) => Ok(quote! {
3397+
TypeKind::ObjCId => Ok(quote! {
33983398
id
33993399
}),
3400+
TypeKind::ObjCInterface(..) => Ok(quote! {
3401+
objc::runtime::Object
3402+
}),
34003403
ref u @ TypeKind::UnresolvedTypeRef(..) => {
34013404
unreachable!("Should have been resolved after parsing {:?}!", u)
34023405
}
@@ -3644,7 +3647,7 @@ fn objc_method_codegen(
36443647
method: &ObjCMethod,
36453648
class_name: Option<&str>,
36463649
prefix: &str,
3647-
) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
3650+
) -> proc_macro2::TokenStream {
36483651
let signature = method.signature();
36493652
let fn_args = utils::fnsig_arguments(ctx, signature);
36503653
let fn_ret = utils::fnsig_return_ty(ctx, signature);
@@ -3665,15 +3668,13 @@ fn objc_method_codegen(
36653668
let methods_and_args = method.format_method_call(&fn_args);
36663669

36673670
let body = if method.is_class_method() {
3668-
let class_name = class_name
3669-
.expect("Generating a class method without class name?")
3670-
.to_owned();
3671-
let expect_msg = proc_macro2::Literal::string(&format!(
3672-
"Couldn't find {}",
3671+
let class_name = ctx.rust_ident(
36733672
class_name
3674-
));
3673+
.expect("Generating a class method without class name?")
3674+
.to_owned(),
3675+
);
36753676
quote! {
3676-
msg_send!(objc::runtime::Class::get(#class_name).expect(#expect_msg), #methods_and_args)
3677+
msg_send!(class!(#class_name), #methods_and_args)
36773678
}
36783679
} else {
36793680
quote! {
@@ -3684,16 +3685,11 @@ fn objc_method_codegen(
36843685
let method_name =
36853686
ctx.rust_ident(format!("{}{}", prefix, method.rust_name()));
36863687

3687-
(
3688-
quote! {
3689-
unsafe fn #method_name #sig {
3690-
#body
3691-
}
3692-
},
3693-
quote! {
3694-
unsafe fn #method_name #sig ;
3695-
},
3696-
)
3688+
quote! {
3689+
unsafe fn #method_name #sig where <Self as std::ops::Deref>::Target: objc::Message + Sized {
3690+
#body
3691+
}
3692+
}
36973693
}
36983694

36993695
impl CodeGenerator for ObjCInterface {
@@ -3708,13 +3704,10 @@ impl CodeGenerator for ObjCInterface {
37083704
debug_assert!(item.is_enabled_for_codegen(ctx));
37093705

37103706
let mut impl_items = vec![];
3711-
let mut trait_items = vec![];
37123707

37133708
for method in self.methods() {
3714-
let (impl_item, trait_item) =
3715-
objc_method_codegen(ctx, method, None, "");
3709+
let impl_item = objc_method_codegen(ctx, method, None, "");
37163710
impl_items.push(impl_item);
3717-
trait_items.push(trait_item)
37183711
}
37193712

37203713
let instance_method_names: Vec<_> =
@@ -3724,61 +3717,97 @@ impl CodeGenerator for ObjCInterface {
37243717
let ambiquity =
37253718
instance_method_names.contains(&class_method.rust_name());
37263719
let prefix = if ambiquity { "class_" } else { "" };
3727-
let (impl_item, trait_item) = objc_method_codegen(
3720+
let impl_item = objc_method_codegen(
37283721
ctx,
37293722
class_method,
37303723
Some(self.name()),
37313724
prefix,
37323725
);
37333726
impl_items.push(impl_item);
3734-
trait_items.push(trait_item)
37353727
}
37363728

37373729
let trait_name = ctx.rust_ident(self.rust_name());
3738-
3730+
let trait_constraints = quote! {
3731+
Sized + std::ops::Deref
3732+
};
37393733
let trait_block = if self.is_template() {
37403734
let template_names: Vec<Ident> = self
37413735
.template_names
37423736
.iter()
37433737
.map(|g| ctx.rust_ident(g))
37443738
.collect();
3739+
37453740
quote! {
3746-
pub trait #trait_name <#(#template_names),*>{
3747-
#( #trait_items )*
3741+
pub trait #trait_name <#(#template_names),*> : #trait_constraints {
3742+
#( #impl_items )*
37483743
}
37493744
}
37503745
} else {
37513746
quote! {
3752-
pub trait #trait_name {
3753-
#( #trait_items )*
3747+
pub trait #trait_name : #trait_constraints {
3748+
#( #impl_items )*
37543749
}
37553750
}
37563751
};
37573752

3758-
let ty_for_impl = quote! {
3759-
id
3760-
};
3761-
let impl_block = if self.is_template() {
3762-
let template_names: Vec<Ident> = self
3763-
.template_names
3764-
.iter()
3765-
.map(|g| ctx.rust_ident(g))
3766-
.collect();
3767-
quote! {
3768-
impl <#(#template_names :'static),*> #trait_name <#(#template_names),*> for #ty_for_impl {
3769-
#( #impl_items )*
3753+
let class_name = ctx.rust_ident(self.name());
3754+
if !self.is_category() && !self.is_protocol() {
3755+
let struct_block = quote! {
3756+
#[repr(transparent)]
3757+
#[derive(Clone, Copy)]
3758+
pub struct #class_name(pub id);
3759+
impl std::ops::Deref for #class_name {
3760+
type Target = objc::runtime::Object;
3761+
fn deref(&self) -> &Self::Target {
3762+
unsafe {
3763+
&*self.0
3764+
}
3765+
}
37703766
}
3771-
}
3772-
} else {
3773-
quote! {
3774-
impl #trait_name for #ty_for_impl {
3775-
#( #impl_items )*
3767+
unsafe impl objc::Message for #class_name { }
3768+
impl #class_name {
3769+
pub fn alloc() -> Self {
3770+
Self(unsafe {
3771+
msg_send!(objc::class!(#class_name), alloc)
3772+
})
3773+
}
37763774
}
3775+
};
3776+
result.push(struct_block);
3777+
for protocol_id in self.conforms_to.iter() {
3778+
let protocol_name = ctx.rust_ident(
3779+
ctx.resolve_type(protocol_id.expect_type_id(ctx))
3780+
.name()
3781+
.unwrap(),
3782+
);
3783+
let impl_trait = quote! {
3784+
impl #protocol_name for #class_name { }
3785+
};
3786+
result.push(impl_trait);
37773787
}
3778-
};
3788+
}
3789+
3790+
if !self.is_protocol() {
3791+
let impl_block = if self.is_template() {
3792+
let template_names: Vec<Ident> = self
3793+
.template_names
3794+
.iter()
3795+
.map(|g| ctx.rust_ident(g))
3796+
.collect();
3797+
quote! {
3798+
impl <#(#template_names :'static),*> #trait_name <#(#template_names),*> for #class_name {
3799+
}
3800+
}
3801+
} else {
3802+
quote! {
3803+
impl #trait_name for #class_name {
3804+
}
3805+
}
3806+
};
3807+
result.push(impl_block);
3808+
}
37793809

37803810
result.push(trait_block);
3781-
result.push(impl_block);
37823811
result.saw_objc();
37833812
}
37843813
}

src/ir/objc.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ pub struct ObjCInterface {
3131
/// The list of template names almost always, ObjectType or KeyType
3232
pub template_names: Vec<String>,
3333

34-
conforms_to: Vec<ItemId>,
34+
/// The list of protocols that this interface conforms to.
35+
pub conforms_to: Vec<ItemId>,
3536

3637
/// List of the methods defined in this interfae
3738
methods: Vec<ObjCMethod>,
@@ -77,15 +78,15 @@ impl ObjCInterface {
7778

7879
/// Formats the name for rust
7980
/// Can be like NSObject, but with categories might be like NSObject_NSCoderMethods
80-
/// and protocols are like protocol_NSObject
81+
/// and protocols are like PNSObject
8182
pub fn rust_name(&self) -> String {
8283
if let Some(ref cat) = self.category {
8384
format!("{}_{}", self.name(), cat)
8485
} else {
8586
if self.is_protocol {
86-
format!("protocol_{}", self.name())
87+
format!("P{}", self.name())
8788
} else {
88-
self.name().to_owned()
89+
format!("I{}", self.name().to_owned())
8990
}
9091
}
9192
}
@@ -100,6 +101,16 @@ impl ObjCInterface {
100101
&self.methods
101102
}
102103

104+
/// Is this a protocol?
105+
pub fn is_protocol(&self) -> bool {
106+
self.is_protocol
107+
}
108+
109+
/// Is this a category?
110+
pub fn is_category(&self) -> bool {
111+
self.category.is_some()
112+
}
113+
103114
/// List of the class methods defined in this interface
104115
pub fn class_methods(&self) -> &Vec<ObjCMethod> {
105116
&self.class_methods
@@ -129,7 +140,7 @@ impl ObjCInterface {
129140
}
130141
CXCursor_ObjCProtocolRef => {
131142
// Gather protocols this interface conforms to
132-
let needle = format!("protocol_{}", c.spelling());
143+
let needle = format!("P{}", c.spelling());
133144
let items_map = ctx.items();
134145
debug!("Interface {} conforms to {}, find the item", interface.name, needle);
135146

tests/expectations/tests/libclang-3.8/objc_template.rs

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,56 @@
88
extern crate objc;
99
#[allow(non_camel_case_types)]
1010
pub type id = *mut objc::runtime::Object;
11-
pub trait Foo<ObjectType> {
12-
unsafe fn get(self) -> id;
11+
#[repr(transparent)]
12+
#[derive(Clone, Copy)]
13+
pub struct Foo(pub id);
14+
impl std::ops::Deref for Foo {
15+
type Target = objc::runtime::Object;
16+
fn deref(&self) -> &Self::Target {
17+
unsafe { &*self.0 }
18+
}
19+
}
20+
unsafe impl objc::Message for Foo {}
21+
impl Foo {
22+
pub fn alloc() -> Self {
23+
Self(unsafe { msg_send!(objc::class!(Foo), alloc) })
24+
}
1325
}
14-
impl<ObjectType: 'static> Foo<ObjectType> for id {
15-
unsafe fn get(self) -> id {
26+
impl<ObjectType: 'static> IFoo<ObjectType> for Foo {}
27+
pub trait IFoo<ObjectType>: Sized + std::ops::Deref {
28+
unsafe fn get(self) -> id
29+
where
30+
<Self as std::ops::Deref>::Target: objc::Message + Sized,
31+
{
1632
msg_send!(self, get)
1733
}
1834
}
19-
pub trait FooMultiGeneric<KeyType, ObjectType> {
20-
unsafe fn objectForKey_(self, key: id) -> id;
35+
#[repr(transparent)]
36+
#[derive(Clone, Copy)]
37+
pub struct FooMultiGeneric(pub id);
38+
impl std::ops::Deref for FooMultiGeneric {
39+
type Target = objc::runtime::Object;
40+
fn deref(&self) -> &Self::Target {
41+
unsafe { &*self.0 }
42+
}
43+
}
44+
unsafe impl objc::Message for FooMultiGeneric {}
45+
impl FooMultiGeneric {
46+
pub fn alloc() -> Self {
47+
Self(unsafe { msg_send!(objc::class!(FooMultiGeneric), alloc) })
48+
}
49+
}
50+
impl<KeyType: 'static, ObjectType: 'static>
51+
IFooMultiGeneric<KeyType, ObjectType> for FooMultiGeneric
52+
{
2153
}
22-
impl<KeyType: 'static, ObjectType: 'static> FooMultiGeneric<KeyType, ObjectType>
23-
for id
54+
pub trait IFooMultiGeneric<KeyType, ObjectType>:
55+
Sized + std::ops::Deref
2456
{
25-
unsafe fn objectForKey_(self, key: id) -> id {
57+
unsafe fn objectForKey_(self, key: id) -> id
58+
where
59+
<Self as std::ops::Deref>::Target: objc::Message + Sized,
60+
{
2661
msg_send!(self, objectForKey: key)
2762
}
2863
}

tests/expectations/tests/libclang-3.9/objc_template.rs

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,56 @@
88
extern crate objc;
99
#[allow(non_camel_case_types)]
1010
pub type id = *mut objc::runtime::Object;
11-
pub trait Foo<ObjectType> {
12-
unsafe fn get(self) -> id;
11+
#[repr(transparent)]
12+
#[derive(Clone, Copy)]
13+
pub struct Foo(pub id);
14+
impl std::ops::Deref for Foo {
15+
type Target = objc::runtime::Object;
16+
fn deref(&self) -> &Self::Target {
17+
unsafe { &*self.0 }
18+
}
19+
}
20+
unsafe impl objc::Message for Foo {}
21+
impl Foo {
22+
pub fn alloc() -> Self {
23+
Self(unsafe { msg_send!(objc::class!(Foo), alloc) })
24+
}
1325
}
14-
impl<ObjectType: 'static> Foo<ObjectType> for id {
15-
unsafe fn get(self) -> id {
26+
impl<ObjectType: 'static> IFoo<ObjectType> for Foo {}
27+
pub trait IFoo<ObjectType>: Sized + std::ops::Deref {
28+
unsafe fn get(self) -> id
29+
where
30+
<Self as std::ops::Deref>::Target: objc::Message + Sized,
31+
{
1632
msg_send!(self, get)
1733
}
1834
}
19-
pub trait FooMultiGeneric<KeyType, ObjectType> {
20-
unsafe fn objectForKey_(self, key: id) -> id;
35+
#[repr(transparent)]
36+
#[derive(Clone, Copy)]
37+
pub struct FooMultiGeneric(pub id);
38+
impl std::ops::Deref for FooMultiGeneric {
39+
type Target = objc::runtime::Object;
40+
fn deref(&self) -> &Self::Target {
41+
unsafe { &*self.0 }
42+
}
43+
}
44+
unsafe impl objc::Message for FooMultiGeneric {}
45+
impl FooMultiGeneric {
46+
pub fn alloc() -> Self {
47+
Self(unsafe { msg_send!(objc::class!(FooMultiGeneric), alloc) })
48+
}
49+
}
50+
impl<KeyType: 'static, ObjectType: 'static>
51+
IFooMultiGeneric<KeyType, ObjectType> for FooMultiGeneric
52+
{
2153
}
22-
impl<KeyType: 'static, ObjectType: 'static> FooMultiGeneric<KeyType, ObjectType>
23-
for id
54+
pub trait IFooMultiGeneric<KeyType, ObjectType>:
55+
Sized + std::ops::Deref
2456
{
25-
unsafe fn objectForKey_(self, key: id) -> id {
57+
unsafe fn objectForKey_(self, key: id) -> id
58+
where
59+
<Self as std::ops::Deref>::Target: objc::Message + Sized,
60+
{
2661
msg_send!(self, objectForKey: key)
2762
}
2863
}

0 commit comments

Comments
 (0)