summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--book/src/objc.md9
-rw-r--r--src/codegen/mod.rs25
-rw-r--r--tests/expectations/tests/objc_class.rs2
-rw-r--r--tests/expectations/tests/objc_class_method.rs4
-rw-r--r--tests/expectations/tests/objc_interface_type.rs6
-rw-r--r--tests/expectations/tests/objc_method.rs4
-rw-r--r--tests/expectations/tests/objc_pointer_return_types.rs59
-rw-r--r--tests/headers/objc_pointer_return_types.h10
8 files changed, 105 insertions, 14 deletions
diff --git a/book/src/objc.md b/book/src/objc.md
index 7c2892aa..c7c97811 100644
--- a/book/src/objc.md
+++ b/book/src/objc.md
@@ -17,6 +17,15 @@ The objective-c classes will be represented as a `struct Foo(id)` and a trait
objc::runtime::Object` (the pointer to the objective-c instance). The trait
`IFoo` is needed to allow for the generated inheritance.
+Functions that use or return objective-c pointers of instance `Foo` will return
+`Foo`. The reason this works is beacuse `Foo` represented as `transparent`.
+This will be helpful for a lot of objective-c frameworks however there are some
+cases where functions return `instancetype` which is a type alias for `id` so
+an occasional `foo.0` may be required. An example of this would in the UIKit
+framework should you want to add a `UILabel` to a
+[UIStackView](https://developer.apple.com/documentation/uikit/uistackview/1616227-addarrangedsubview?language=objc)
+you will need to convert the `UILabel` to a `UIView` via `UIView(label.0)`.
+
Each class (struct) has an `alloc` and a `dealloc` to match that of some of the alloc
methods found in `NSObject`.
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index de46bb22..ccfa622c 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -3512,6 +3512,14 @@ impl TryToRustTy for Type {
inner.into_resolver().through_type_refs().resolve(ctx);
let inner_ty = inner.expect_type();
+ let is_objc_pointer =
+ inner.kind().as_type().map_or(false, |ty| {
+ match ty.kind() {
+ TypeKind::ObjCInterface(..) => true,
+ _ => false,
+ }
+ });
+
// Regardless if we can properly represent the inner type, we
// should always generate a proper pointer here, so use
// infallible conversion of the inner type.
@@ -3520,7 +3528,8 @@ impl TryToRustTy for Type {
// Avoid the first function pointer level, since it's already
// represented in Rust.
- if inner_ty.canonical_type(ctx).is_function() {
+ if inner_ty.canonical_type(ctx).is_function() || is_objc_pointer
+ {
Ok(ty)
} else {
Ok(ty.to_ptr(is_const))
@@ -3539,9 +3548,12 @@ impl TryToRustTy for Type {
TypeKind::ObjCId => Ok(quote! {
id
}),
- TypeKind::ObjCInterface(..) => Ok(quote! {
- objc::runtime::Object
- }),
+ TypeKind::ObjCInterface(ref interface) => {
+ let name = ctx.rust_ident(interface.name());
+ Ok(quote! {
+ #name
+ })
+ }
ref u @ TypeKind::UnresolvedTypeRef(..) => {
unreachable!("Should have been resolved after parsing {:?}!", u)
}
@@ -4395,11 +4407,12 @@ mod utils {
TypeKind::Pointer(inner) => {
let inner = ctx.resolve_item(inner);
let inner_ty = inner.expect_type();
- if let TypeKind::ObjCInterface(_) =
+ if let TypeKind::ObjCInterface(ref interface) =
*inner_ty.canonical_type(ctx).kind()
{
+ let name = ctx.rust_ident(interface.name());
quote! {
- id
+ #name
}
} else {
arg_item.to_rust_ty_or_opaque(ctx, &())
diff --git a/tests/expectations/tests/objc_class.rs b/tests/expectations/tests/objc_class.rs
index 237b86b4..a1de91fb 100644
--- a/tests/expectations/tests/objc_class.rs
+++ b/tests/expectations/tests/objc_class.rs
@@ -11,7 +11,7 @@ extern crate objc;
#[allow(non_camel_case_types)]
pub type id = *mut objc::runtime::Object;
extern "C" {
- pub static mut fooVar: *mut objc::runtime::Object;
+ pub static mut fooVar: Foo;
}
#[repr(transparent)]
#[derive(Clone, Copy)]
diff --git a/tests/expectations/tests/objc_class_method.rs b/tests/expectations/tests/objc_class_method.rs
index e0a3803c..d28a233d 100644
--- a/tests/expectations/tests/objc_class_method.rs
+++ b/tests/expectations/tests/objc_class_method.rs
@@ -39,7 +39,7 @@ pub trait IFoo: Sized + std::ops::Deref {
{
msg_send!(class!(Foo), methodWithInt: foo)
}
- unsafe fn methodWithFoo_(foo: id)
+ unsafe fn methodWithFoo_(foo: Foo)
where
<Self as std::ops::Deref>::Target: objc::Message + Sized,
{
@@ -51,7 +51,7 @@ pub trait IFoo: Sized + std::ops::Deref {
{
msg_send!(class!(Foo), methodReturningInt)
}
- unsafe fn methodReturningFoo() -> *mut objc::runtime::Object
+ unsafe fn methodReturningFoo() -> Foo
where
<Self as std::ops::Deref>::Target: objc::Message + Sized,
{
diff --git a/tests/expectations/tests/objc_interface_type.rs b/tests/expectations/tests/objc_interface_type.rs
index edbf412c..e8a15963 100644
--- a/tests/expectations/tests/objc_interface_type.rs
+++ b/tests/expectations/tests/objc_interface_type.rs
@@ -30,7 +30,7 @@ pub trait IFoo: Sized + std::ops::Deref {}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct FooStruct {
- pub foo: *mut objc::runtime::Object,
+ pub foo: Foo,
}
#[test]
fn bindgen_test_layout_FooStruct() {
@@ -63,8 +63,8 @@ impl Default for FooStruct {
}
}
extern "C" {
- pub fn fooFunc(foo: id);
+ pub fn fooFunc(foo: Foo);
}
extern "C" {
- pub static mut kFoo: *const objc::runtime::Object;
+ pub static mut kFoo: Foo;
}
diff --git a/tests/expectations/tests/objc_method.rs b/tests/expectations/tests/objc_method.rs
index 13e4d9f8..e24768d2 100644
--- a/tests/expectations/tests/objc_method.rs
+++ b/tests/expectations/tests/objc_method.rs
@@ -39,7 +39,7 @@ pub trait IFoo: Sized + std::ops::Deref {
{
msg_send!(self, methodWithInt: foo)
}
- unsafe fn methodWithFoo_(self, foo: id)
+ unsafe fn methodWithFoo_(self, foo: Foo)
where
<Self as std::ops::Deref>::Target: objc::Message + Sized,
{
@@ -51,7 +51,7 @@ pub trait IFoo: Sized + std::ops::Deref {
{
msg_send!(self, methodReturningInt)
}
- unsafe fn methodReturningFoo(self) -> *mut objc::runtime::Object
+ unsafe fn methodReturningFoo(self) -> Foo
where
<Self as std::ops::Deref>::Target: objc::Message + Sized,
{
diff --git a/tests/expectations/tests/objc_pointer_return_types.rs b/tests/expectations/tests/objc_pointer_return_types.rs
new file mode 100644
index 00000000..0f222c8b
--- /dev/null
+++ b/tests/expectations/tests/objc_pointer_return_types.rs
@@ -0,0 +1,59 @@
+#![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;
+#[repr(transparent)]
+#[derive(Clone, Copy)]
+pub struct Bar(pub id);
+impl std::ops::Deref for Bar {
+ type Target = objc::runtime::Object;
+ fn deref(&self) -> &Self::Target {
+ unsafe { &*self.0 }
+ }
+}
+unsafe impl objc::Message for Bar {}
+impl Bar {
+ pub fn alloc() -> Self {
+ Self(unsafe { msg_send!(objc::class!(Bar), alloc) })
+ }
+}
+impl IBar for Bar {}
+pub trait IBar: Sized + std::ops::Deref {}
+#[repr(transparent)]
+#[derive(Clone, Copy)]
+pub struct Foo(pub id);
+impl std::ops::Deref for Foo {
+ type Target = objc::runtime::Object;
+ fn deref(&self) -> &Self::Target {
+ unsafe { &*self.0 }
+ }
+}
+unsafe impl objc::Message for Foo {}
+impl Foo {
+ pub fn alloc() -> Self {
+ Self(unsafe { msg_send!(objc::class!(Foo), alloc) })
+ }
+}
+impl IFoo for Foo {}
+pub trait IFoo: Sized + std::ops::Deref {
+ unsafe fn methodUsingBar_(self, my_bar: Bar)
+ where
+ <Self as std::ops::Deref>::Target: objc::Message + Sized,
+ {
+ msg_send!(self, methodUsingBar: my_bar)
+ }
+ unsafe fn methodReturningBar() -> Bar
+ where
+ <Self as std::ops::Deref>::Target: objc::Message + Sized,
+ {
+ msg_send!(class!(Foo), methodReturningBar)
+ }
+}
diff --git a/tests/headers/objc_pointer_return_types.h b/tests/headers/objc_pointer_return_types.h
new file mode 100644
index 00000000..e289a8a5
--- /dev/null
+++ b/tests/headers/objc_pointer_return_types.h
@@ -0,0 +1,10 @@
+// bindgen-flags: --objc-extern-crate -- -x objective-c
+// bindgen-osx-only
+
+@interface Bar
+@end
+
+@interface Foo
++ (Bar*)methodReturningBar;
+- (void)methodUsingBar:(Bar *)my_bar;
+@end