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

[Objc] Add From<ChildClass>, TryFrom<ParentClass>, function ownership updates and Protocol inheritance #1883

Merged
merged 11 commits into from Sep 16, 2020
9 changes: 6 additions & 3 deletions CHANGELOG.md
Expand Up @@ -120,11 +120,11 @@ Released YYYY/MM/DD

## Added

* TODO (or remove section if none)
* Objective-c bindings generate `From<ChildClass> for ParentClass` as well as `TryFrom<ParentClass> for ChildClass` ([#1883][]).

## Changed

* TODO (or remove section if none)
* Objective-c bindings borrow self rather than take ownership ([#1883][]).

## Deprecated

Expand All @@ -136,12 +136,15 @@ Released YYYY/MM/DD

## Fixed

* TODO (or remove section if none)
* Fixed objective-c protocol impl blocks for parent classes's protocols ([#1883][]).

## Security

* TODO (or remove section if none)


[#1883]: https://github.com/rust-lang/rust-bindgen/issues/1883

--------------------------------------------------------------------------------

# 0.55.1
Expand Down
55 changes: 52 additions & 3 deletions src/codegen/mod.rs
Expand Up @@ -3806,7 +3806,7 @@ fn objc_method_codegen(
}
} else {
let fn_args = fn_args.clone();
let args = iter::once(quote! { self }).chain(fn_args.into_iter());
let args = iter::once(quote! { &self }).chain(fn_args.into_iter());
quote! {
( #( #args ),* ) #fn_ret
}
Expand All @@ -3825,7 +3825,7 @@ fn objc_method_codegen(
}
} else {
quote! {
msg_send!(self, #methods_and_args)
msg_send!(*self, #methods_and_args)
}
};

Expand Down Expand Up @@ -3901,7 +3901,7 @@ impl CodeGenerator for ObjCInterface {
if !self.is_category() && !self.is_protocol() {
let struct_block = quote! {
#[repr(transparent)]
#[derive(Clone, Copy)]
#[derive(Clone)]
pub struct #class_name(pub id);
impl std::ops::Deref for #class_name {
type Target = objc::runtime::Object;
Expand All @@ -3921,7 +3921,9 @@ impl CodeGenerator for ObjCInterface {
}
};
result.push(struct_block);
let mut protocol_set: HashSet<ItemId> = Default::default();
for protocol_id in self.conforms_to.iter() {
protocol_set.insert(*protocol_id);
let protocol_name = ctx.rust_ident(
ctx.resolve_type(protocol_id.expect_type_id(ctx))
.name()
Expand Down Expand Up @@ -3962,6 +3964,53 @@ impl CodeGenerator for ObjCInterface {
}
};
result.push(impl_trait);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is getting kinda gnarly, it may be worth factoring this if let ... { .. } else { .. } to its own function. Follow-up is fine.

for protocol_id in parent.conforms_to.iter() {
if protocol_set.insert(*protocol_id) {
let protocol_name = ctx.rust_ident(
ctx.resolve_type(
protocol_id.expect_type_id(ctx),
)
.name()
.unwrap(),
);
let impl_trait = quote! {
impl #protocol_name for #class_name { }
};
result.push(impl_trait);
}
}
if !parent.is_template() {
let parent_struct_name = parent.name();
let child_struct_name = self.name();
let parent_struct = ctx.rust_ident(parent_struct_name);
let from_block = quote! {
impl From<#class_name> for #parent_struct {
fn from(child: #class_name) -> #parent_struct {
#parent_struct(child.0)
}
}
};
result.push(from_block);

let error_msg = format!(
"This {} cannot be downcasted to {}",
parent_struct_name, child_struct_name
);
let try_into_block = quote! {
impl std::convert::TryFrom<#parent_struct> for #class_name {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can't use std if the no_std flag is set, so this should use trait_prefix. Also, probably should use the old style root paths (::std::convert::TryFrom) for consistency with other code and to support Rust 2015.

type Error = &'static str;
fn try_from(parent: #parent_struct) -> Result<#class_name, Self::Error> {
let is_kind_of : bool = unsafe { msg_send!(parent, isKindOfClass:class!(#class_name))};
if is_kind_of {
Ok(#class_name(parent.0))
} else {
Err(#error_msg)
}
}
}
};
result.push(try_into_block);
}
parent.parent_class
} else {
None
Expand Down
57 changes: 54 additions & 3 deletions tests/expectations/tests/libclang-3.9/objc_inheritance.rs
Expand Up @@ -11,7 +11,7 @@ extern crate objc;
#[allow(non_camel_case_types)]
pub type id = *mut objc::runtime::Object;
#[repr(transparent)]
#[derive(Clone, Copy)]
#[derive(Clone)]
pub struct Foo(pub id);
impl std::ops::Deref for Foo {
type Target = objc::runtime::Object;
Expand All @@ -28,7 +28,7 @@ impl Foo {
impl IFoo for Foo {}
pub trait IFoo: Sized + std::ops::Deref {}
#[repr(transparent)]
#[derive(Clone, Copy)]
#[derive(Clone)]
pub struct Bar(pub id);
impl std::ops::Deref for Bar {
type Target = objc::runtime::Object;
Expand All @@ -43,10 +43,27 @@ impl Bar {
}
}
impl IFoo for Bar {}
impl From<Bar> for Foo {
fn from(child: Bar) -> Foo {
Foo(child.0)
}
}
impl std::convert::TryFrom<Foo> for Bar {
type Error = &'static str;
fn try_from(parent: Foo) -> Result<Bar, Self::Error> {
let is_kind_of: bool =
unsafe { msg_send!(parent, isKindOfClass: class!(Bar)) };
if is_kind_of {
Ok(Bar(parent.0))
} else {
Err("This Foo cannot be downcasted to Bar")
}
}
}
impl IBar for Bar {}
pub trait IBar: Sized + std::ops::Deref {}
#[repr(transparent)]
#[derive(Clone, Copy)]
#[derive(Clone)]
pub struct Baz(pub id);
impl std::ops::Deref for Baz {
type Target = objc::runtime::Object;
Expand All @@ -61,6 +78,40 @@ impl Baz {
}
}
impl IBar for Baz {}
impl From<Baz> for Bar {
fn from(child: Baz) -> Bar {
Bar(child.0)
}
}
impl std::convert::TryFrom<Bar> for Baz {
type Error = &'static str;
fn try_from(parent: Bar) -> Result<Baz, Self::Error> {
let is_kind_of: bool =
unsafe { msg_send!(parent, isKindOfClass: class!(Baz)) };
if is_kind_of {
Ok(Baz(parent.0))
} else {
Err("This Bar cannot be downcasted to Baz")
}
}
}
impl IFoo for Baz {}
impl From<Baz> for Foo {
fn from(child: Baz) -> Foo {
Foo(child.0)
}
}
impl std::convert::TryFrom<Foo> for Baz {
type Error = &'static str;
fn try_from(parent: Foo) -> Result<Baz, Self::Error> {
let is_kind_of: bool =
unsafe { msg_send!(parent, isKindOfClass: class!(Baz)) };
if is_kind_of {
Ok(Baz(parent.0))
} else {
Err("This Foo cannot be downcasted to Baz")
}
}
}
impl IBaz for Baz {}
pub trait IBaz: Sized + std::ops::Deref {}
12 changes: 6 additions & 6 deletions tests/expectations/tests/libclang-3.9/objc_template.rs
Expand Up @@ -11,7 +11,7 @@ extern crate objc;
#[allow(non_camel_case_types)]
pub type id = *mut objc::runtime::Object;
#[repr(transparent)]
#[derive(Clone, Copy)]
#[derive(Clone)]
pub struct Foo(pub id);
impl std::ops::Deref for Foo {
type Target = objc::runtime::Object;
Expand All @@ -27,15 +27,15 @@ impl Foo {
}
impl<ObjectType: 'static> IFoo<ObjectType> for Foo {}
pub trait IFoo<ObjectType>: Sized + std::ops::Deref {
unsafe fn get(self) -> id
unsafe fn get(&self) -> id
where
<Self as std::ops::Deref>::Target: objc::Message + Sized,
{
msg_send!(self, get)
msg_send!(*self, get)
}
}
#[repr(transparent)]
#[derive(Clone, Copy)]
#[derive(Clone)]
pub struct FooMultiGeneric(pub id);
impl std::ops::Deref for FooMultiGeneric {
type Target = objc::runtime::Object;
Expand All @@ -56,10 +56,10 @@ impl<KeyType: 'static, ObjectType: 'static>
pub trait IFooMultiGeneric<KeyType, ObjectType>:
Sized + std::ops::Deref
{
unsafe fn objectForKey_(self, key: id) -> id
unsafe fn objectForKey_(&self, key: id) -> id
where
<Self as std::ops::Deref>::Target: objc::Message + Sized,
{
msg_send!(self, objectForKey: key)
msg_send!(*self, objectForKey: key)
}
}
57 changes: 54 additions & 3 deletions tests/expectations/tests/libclang-4/objc_inheritance.rs
Expand Up @@ -11,7 +11,7 @@ extern crate objc;
#[allow(non_camel_case_types)]
pub type id = *mut objc::runtime::Object;
#[repr(transparent)]
#[derive(Clone, Copy)]
#[derive(Clone)]
pub struct Foo(pub id);
impl std::ops::Deref for Foo {
type Target = objc::runtime::Object;
Expand All @@ -28,7 +28,7 @@ impl Foo {
impl IFoo for Foo {}
pub trait IFoo: Sized + std::ops::Deref {}
#[repr(transparent)]
#[derive(Clone, Copy)]
#[derive(Clone)]
pub struct Bar(pub id);
impl std::ops::Deref for Bar {
type Target = objc::runtime::Object;
Expand All @@ -43,10 +43,27 @@ impl Bar {
}
}
impl IFoo for Bar {}
impl From<Bar> for Foo {
fn from(child: Bar) -> Foo {
Foo(child.0)
}
}
impl std::convert::TryFrom<Foo> for Bar {
type Error = &'static str;
fn try_from(parent: Foo) -> Result<Bar, Self::Error> {
let is_kind_of: bool =
unsafe { msg_send!(parent, isKindOfClass: class!(Bar)) };
if is_kind_of {
Ok(Bar(parent.0))
} else {
Err("This Foo cannot be downcasted to Bar")
}
}
}
impl IBar for Bar {}
pub trait IBar: Sized + std::ops::Deref {}
#[repr(transparent)]
#[derive(Clone, Copy)]
#[derive(Clone)]
pub struct Baz(pub id);
impl std::ops::Deref for Baz {
type Target = objc::runtime::Object;
Expand All @@ -61,6 +78,40 @@ impl Baz {
}
}
impl IBar for Baz {}
impl From<Baz> for Bar {
fn from(child: Baz) -> Bar {
Bar(child.0)
}
}
impl std::convert::TryFrom<Bar> for Baz {
type Error = &'static str;
fn try_from(parent: Bar) -> Result<Baz, Self::Error> {
let is_kind_of: bool =
unsafe { msg_send!(parent, isKindOfClass: class!(Baz)) };
if is_kind_of {
Ok(Baz(parent.0))
} else {
Err("This Bar cannot be downcasted to Baz")
}
}
}
impl IFoo for Baz {}
impl From<Baz> for Foo {
fn from(child: Baz) -> Foo {
Foo(child.0)
}
}
impl std::convert::TryFrom<Foo> for Baz {
type Error = &'static str;
fn try_from(parent: Foo) -> Result<Baz, Self::Error> {
let is_kind_of: bool =
unsafe { msg_send!(parent, isKindOfClass: class!(Baz)) };
if is_kind_of {
Ok(Baz(parent.0))
} else {
Err("This Foo cannot be downcasted to Baz")
}
}
}
impl IBaz for Baz {}
pub trait IBaz: Sized + std::ops::Deref {}
12 changes: 6 additions & 6 deletions tests/expectations/tests/libclang-4/objc_template.rs
Expand Up @@ -11,7 +11,7 @@ extern crate objc;
#[allow(non_camel_case_types)]
pub type id = *mut objc::runtime::Object;
#[repr(transparent)]
#[derive(Clone, Copy)]
#[derive(Clone)]
pub struct Foo(pub id);
impl std::ops::Deref for Foo {
type Target = objc::runtime::Object;
Expand All @@ -27,15 +27,15 @@ impl Foo {
}
impl<ObjectType: 'static> IFoo<ObjectType> for Foo {}
pub trait IFoo<ObjectType>: Sized + std::ops::Deref {
unsafe fn get(self) -> *mut ObjectType
unsafe fn get(&self) -> *mut ObjectType
where
<Self as std::ops::Deref>::Target: objc::Message + Sized,
{
msg_send!(self, get)
msg_send!(*self, get)
}
}
#[repr(transparent)]
#[derive(Clone, Copy)]
#[derive(Clone)]
pub struct FooMultiGeneric(pub id);
impl std::ops::Deref for FooMultiGeneric {
type Target = objc::runtime::Object;
Expand All @@ -56,10 +56,10 @@ impl<KeyType: 'static, ObjectType: 'static>
pub trait IFooMultiGeneric<KeyType, ObjectType>:
Sized + std::ops::Deref
{
unsafe fn objectForKey_(self, key: *mut KeyType) -> *mut ObjectType
unsafe fn objectForKey_(&self, key: *mut KeyType) -> *mut ObjectType
where
<Self as std::ops::Deref>::Target: objc::Message + Sized,
{
msg_send!(self, objectForKey: key)
msg_send!(*self, objectForKey: key)
}
}