Skip to content

Commit 4299255

Browse files
simlayemilio
authored andcommitted
Added Bindgen names to objective-c pointer return types
* Took advantage of the repr transparent to use Bindgen return type names. * Updated unit tests and book
1 parent 802561e commit 4299255

File tree

8 files changed

+105
-14
lines changed

8 files changed

+105
-14
lines changed

book/src/objc.md

+9
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@ The objective-c classes will be represented as a `struct Foo(id)` and a trait
1717
objc::runtime::Object` (the pointer to the objective-c instance). The trait
1818
`IFoo` is needed to allow for the generated inheritance.
1919

20+
Functions that use or return objective-c pointers of instance `Foo` will return
21+
`Foo`. The reason this works is beacuse `Foo` represented as `transparent`.
22+
This will be helpful for a lot of objective-c frameworks however there are some
23+
cases where functions return `instancetype` which is a type alias for `id` so
24+
an occasional `foo.0` may be required. An example of this would in the UIKit
25+
framework should you want to add a `UILabel` to a
26+
[UIStackView](https://developer.apple.com/documentation/uikit/uistackview/1616227-addarrangedsubview?language=objc)
27+
you will need to convert the `UILabel` to a `UIView` via `UIView(label.0)`.
28+
2029
Each class (struct) has an `alloc` and a `dealloc` to match that of some of the alloc
2130
methods found in `NSObject`.
2231

src/codegen/mod.rs

+19-6
Original file line numberDiff line numberDiff line change
@@ -3512,6 +3512,14 @@ impl TryToRustTy for Type {
35123512
inner.into_resolver().through_type_refs().resolve(ctx);
35133513
let inner_ty = inner.expect_type();
35143514

3515+
let is_objc_pointer =
3516+
inner.kind().as_type().map_or(false, |ty| {
3517+
match ty.kind() {
3518+
TypeKind::ObjCInterface(..) => true,
3519+
_ => false,
3520+
}
3521+
});
3522+
35153523
// Regardless if we can properly represent the inner type, we
35163524
// should always generate a proper pointer here, so use
35173525
// infallible conversion of the inner type.
@@ -3520,7 +3528,8 @@ impl TryToRustTy for Type {
35203528

35213529
// Avoid the first function pointer level, since it's already
35223530
// represented in Rust.
3523-
if inner_ty.canonical_type(ctx).is_function() {
3531+
if inner_ty.canonical_type(ctx).is_function() || is_objc_pointer
3532+
{
35243533
Ok(ty)
35253534
} else {
35263535
Ok(ty.to_ptr(is_const))
@@ -3539,9 +3548,12 @@ impl TryToRustTy for Type {
35393548
TypeKind::ObjCId => Ok(quote! {
35403549
id
35413550
}),
3542-
TypeKind::ObjCInterface(..) => Ok(quote! {
3543-
objc::runtime::Object
3544-
}),
3551+
TypeKind::ObjCInterface(ref interface) => {
3552+
let name = ctx.rust_ident(interface.name());
3553+
Ok(quote! {
3554+
#name
3555+
})
3556+
}
35453557
ref u @ TypeKind::UnresolvedTypeRef(..) => {
35463558
unreachable!("Should have been resolved after parsing {:?}!", u)
35473559
}
@@ -4395,11 +4407,12 @@ mod utils {
43954407
TypeKind::Pointer(inner) => {
43964408
let inner = ctx.resolve_item(inner);
43974409
let inner_ty = inner.expect_type();
4398-
if let TypeKind::ObjCInterface(_) =
4410+
if let TypeKind::ObjCInterface(ref interface) =
43994411
*inner_ty.canonical_type(ctx).kind()
44004412
{
4413+
let name = ctx.rust_ident(interface.name());
44014414
quote! {
4402-
id
4415+
#name
44034416
}
44044417
} else {
44054418
arg_item.to_rust_ty_or_opaque(ctx, &())

tests/expectations/tests/objc_class.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ extern crate objc;
1111
#[allow(non_camel_case_types)]
1212
pub type id = *mut objc::runtime::Object;
1313
extern "C" {
14-
pub static mut fooVar: *mut objc::runtime::Object;
14+
pub static mut fooVar: Foo;
1515
}
1616
#[repr(transparent)]
1717
#[derive(Clone, Copy)]

tests/expectations/tests/objc_class_method.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ pub trait IFoo: Sized + std::ops::Deref {
3939
{
4040
msg_send!(class!(Foo), methodWithInt: foo)
4141
}
42-
unsafe fn methodWithFoo_(foo: id)
42+
unsafe fn methodWithFoo_(foo: Foo)
4343
where
4444
<Self as std::ops::Deref>::Target: objc::Message + Sized,
4545
{
@@ -51,7 +51,7 @@ pub trait IFoo: Sized + std::ops::Deref {
5151
{
5252
msg_send!(class!(Foo), methodReturningInt)
5353
}
54-
unsafe fn methodReturningFoo() -> *mut objc::runtime::Object
54+
unsafe fn methodReturningFoo() -> Foo
5555
where
5656
<Self as std::ops::Deref>::Target: objc::Message + Sized,
5757
{

tests/expectations/tests/objc_interface_type.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ pub trait IFoo: Sized + std::ops::Deref {}
3030
#[repr(C)]
3131
#[derive(Debug, Copy, Clone)]
3232
pub struct FooStruct {
33-
pub foo: *mut objc::runtime::Object,
33+
pub foo: Foo,
3434
}
3535
#[test]
3636
fn bindgen_test_layout_FooStruct() {
@@ -63,8 +63,8 @@ impl Default for FooStruct {
6363
}
6464
}
6565
extern "C" {
66-
pub fn fooFunc(foo: id);
66+
pub fn fooFunc(foo: Foo);
6767
}
6868
extern "C" {
69-
pub static mut kFoo: *const objc::runtime::Object;
69+
pub static mut kFoo: Foo;
7070
}

tests/expectations/tests/objc_method.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ pub trait IFoo: Sized + std::ops::Deref {
3939
{
4040
msg_send!(self, methodWithInt: foo)
4141
}
42-
unsafe fn methodWithFoo_(self, foo: id)
42+
unsafe fn methodWithFoo_(self, foo: Foo)
4343
where
4444
<Self as std::ops::Deref>::Target: objc::Message + Sized,
4545
{
@@ -51,7 +51,7 @@ pub trait IFoo: Sized + std::ops::Deref {
5151
{
5252
msg_send!(self, methodReturningInt)
5353
}
54-
unsafe fn methodReturningFoo(self) -> *mut objc::runtime::Object
54+
unsafe fn methodReturningFoo(self) -> Foo
5555
where
5656
<Self as std::ops::Deref>::Target: objc::Message + Sized,
5757
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#![allow(
2+
dead_code,
3+
non_snake_case,
4+
non_camel_case_types,
5+
non_upper_case_globals
6+
)]
7+
#![cfg(target_os = "macos")]
8+
9+
#[macro_use]
10+
extern crate objc;
11+
#[allow(non_camel_case_types)]
12+
pub type id = *mut objc::runtime::Object;
13+
#[repr(transparent)]
14+
#[derive(Clone, Copy)]
15+
pub struct Bar(pub id);
16+
impl std::ops::Deref for Bar {
17+
type Target = objc::runtime::Object;
18+
fn deref(&self) -> &Self::Target {
19+
unsafe { &*self.0 }
20+
}
21+
}
22+
unsafe impl objc::Message for Bar {}
23+
impl Bar {
24+
pub fn alloc() -> Self {
25+
Self(unsafe { msg_send!(objc::class!(Bar), alloc) })
26+
}
27+
}
28+
impl IBar for Bar {}
29+
pub trait IBar: Sized + std::ops::Deref {}
30+
#[repr(transparent)]
31+
#[derive(Clone, Copy)]
32+
pub struct Foo(pub id);
33+
impl std::ops::Deref for Foo {
34+
type Target = objc::runtime::Object;
35+
fn deref(&self) -> &Self::Target {
36+
unsafe { &*self.0 }
37+
}
38+
}
39+
unsafe impl objc::Message for Foo {}
40+
impl Foo {
41+
pub fn alloc() -> Self {
42+
Self(unsafe { msg_send!(objc::class!(Foo), alloc) })
43+
}
44+
}
45+
impl IFoo for Foo {}
46+
pub trait IFoo: Sized + std::ops::Deref {
47+
unsafe fn methodUsingBar_(self, my_bar: Bar)
48+
where
49+
<Self as std::ops::Deref>::Target: objc::Message + Sized,
50+
{
51+
msg_send!(self, methodUsingBar: my_bar)
52+
}
53+
unsafe fn methodReturningBar() -> Bar
54+
where
55+
<Self as std::ops::Deref>::Target: objc::Message + Sized,
56+
{
57+
msg_send!(class!(Foo), methodReturningBar)
58+
}
59+
}
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// bindgen-flags: --objc-extern-crate -- -x objective-c
2+
// bindgen-osx-only
3+
4+
@interface Bar
5+
@end
6+
7+
@interface Foo
8+
+ (Bar*)methodReturningBar;
9+
- (void)methodUsingBar:(Bar *)my_bar;
10+
@end

0 commit comments

Comments
 (0)