Skip to content

Commit 7ee6eb6

Browse files
committed
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 f56fbce commit 7ee6eb6

File tree

8 files changed

+108
-14
lines changed

8 files changed

+108
-14
lines changed

book/src/objc.md

Lines changed: 9 additions & 0 deletions
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

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3466,6 +3466,17 @@ impl TryToRustTy for Type {
34663466
inner.into_resolver().through_type_refs().resolve(ctx);
34673467
let inner_ty = inner.expect_type();
34683468

3469+
let is_objc_pointer = inner.kind().as_type().map_or(false, |ty| {
3470+
match ty.kind() {
3471+
TypeKind::ObjCInterface(..) => {
3472+
true
3473+
},
3474+
_ => {
3475+
false
3476+
}
3477+
}
3478+
});
3479+
34693480
// Regardless if we can properly represent the inner type, we
34703481
// should always generate a proper pointer here, so use
34713482
// infallible conversion of the inner type.
@@ -3474,7 +3485,8 @@ impl TryToRustTy for Type {
34743485

34753486
// Avoid the first function pointer level, since it's already
34763487
// represented in Rust.
3477-
if inner_ty.canonical_type(ctx).is_function() {
3488+
if inner_ty.canonical_type(ctx).is_function() || is_objc_pointer
3489+
{
34783490
Ok(ty)
34793491
} else {
34803492
Ok(ty.to_ptr(is_const))
@@ -3493,9 +3505,12 @@ impl TryToRustTy for Type {
34933505
TypeKind::ObjCId => Ok(quote! {
34943506
id
34953507
}),
3496-
TypeKind::ObjCInterface(..) => Ok(quote! {
3497-
objc::runtime::Object
3498-
}),
3508+
TypeKind::ObjCInterface(ref interface) => {
3509+
let name = ctx.rust_ident(interface.name());
3510+
Ok(quote! {
3511+
#name
3512+
})
3513+
}
34993514
ref u @ TypeKind::UnresolvedTypeRef(..) => {
35003515
unreachable!("Should have been resolved after parsing {:?}!", u)
35013516
}
@@ -4349,11 +4364,12 @@ mod utils {
43494364
TypeKind::Pointer(inner) => {
43504365
let inner = ctx.resolve_item(inner);
43514366
let inner_ty = inner.expect_type();
4352-
if let TypeKind::ObjCInterface(_) =
4367+
if let TypeKind::ObjCInterface(ref interface) =
43534368
*inner_ty.canonical_type(ctx).kind()
43544369
{
4370+
let name = ctx.rust_ident(interface.name());
43554371
quote! {
4356-
id
4372+
#name
43574373
}
43584374
} else {
43594375
arg_item.to_rust_ty_or_opaque(ctx, &())

tests/expectations/tests/objc_class.rs

Lines changed: 1 addition & 1 deletion
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 3 additions & 3 deletions
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

Lines changed: 2 additions & 2 deletions
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
{
Lines changed: 59 additions & 0 deletions
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+
}
Lines changed: 10 additions & 0 deletions
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)