summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/codegen/mod.rs47
-rw-r--r--tests/expectations/tests/libclang-9/objc_inheritance.rs45
-rw-r--r--tests/expectations/tests/objc_protocol_inheritance.rs70
-rw-r--r--tests/headers/objc_protocol_inheritance.h11
4 files changed, 167 insertions, 6 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index 7ae202bf..de4721f6 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -49,6 +49,7 @@ use crate::{Entry, HashMap, HashSet};
use std;
use std::borrow::Cow;
use std::cell::Cell;
+use std::collections::HashSet as CollectionHashSet;
use std::collections::VecDeque;
use std::fmt::Write;
use std::iter;
@@ -3921,11 +3922,13 @@ impl CodeGenerator for ObjCInterface {
}
};
result.push(struct_block);
+ let mut protocol_set : CollectionHashSet<ItemId> = CollectionHashSet::new();
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()
- .unwrap(),
+ .name()
+ .unwrap(),
);
let impl_trait = quote! {
impl #protocol_name for #class_name { }
@@ -3962,16 +3965,48 @@ impl CodeGenerator for ObjCInterface {
}
};
result.push(impl_trait);
+ for protocol_id in parent.conforms_to.iter() {
+ if !protocol_set.contains(protocol_id) {
+
+ 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 = ctx.rust_ident(parent.name());
+ 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_name {
- fn from(child: #class_name) -> #parent_struct_name {
- #parent_struct_name(child.0)
+ impl From<#class_name> for #parent_struct {
+ fn from(child: #class_name) -> #parent_struct {
+ #parent_struct(child.0)
}
}
};
result.push(from_block);
+
+ let try_into_block = quote! {
+ impl std::convert::TryFrom<#parent_struct> for #class_name {
+ type Error = String;
+ 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(format!("This {} is not an cannot be downcasted to {}", #parent_struct_name, #child_struct_name))
+ }
+ }
+ }
+ };
+ result.push(try_into_block);
}
parent.parent_class
} else {
diff --git a/tests/expectations/tests/libclang-9/objc_inheritance.rs b/tests/expectations/tests/libclang-9/objc_inheritance.rs
index ef16325e..a84f6f37 100644
--- a/tests/expectations/tests/libclang-9/objc_inheritance.rs
+++ b/tests/expectations/tests/libclang-9/objc_inheritance.rs
@@ -48,6 +48,21 @@ impl From<Bar> for Foo {
Foo(child.0)
}
}
+impl std::convert::TryFrom<Foo> for Bar {
+ type Error = String;
+ 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(format!(
+ "This {} is not an cannot be downcasted to {}",
+ "Foo", "Bar"
+ ))
+ }
+ }
+}
impl IBar for Bar {}
pub trait IBar: Sized + std::ops::Deref {}
#[repr(transparent)]
@@ -71,11 +86,41 @@ impl From<Baz> for Bar {
Bar(child.0)
}
}
+impl std::convert::TryFrom<Bar> for Baz {
+ type Error = String;
+ 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(format!(
+ "This {} is not an cannot be downcasted to {}",
+ "Bar", "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 = String;
+ 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(format!(
+ "This {} is not an cannot be downcasted to {}",
+ "Foo", "Baz"
+ ))
+ }
+ }
+}
impl IBaz for Baz {}
pub trait IBaz: Sized + std::ops::Deref {}
diff --git a/tests/expectations/tests/objc_protocol_inheritance.rs b/tests/expectations/tests/objc_protocol_inheritance.rs
new file mode 100644
index 00000000..14570e1e
--- /dev/null
+++ b/tests/expectations/tests/objc_protocol_inheritance.rs
@@ -0,0 +1,70 @@
+#![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;
+pub trait PFoo: Sized + std::ops::Deref {}
+#[repr(transparent)]
+#[derive(Clone)]
+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 PFoo for Foo {}
+impl IFoo for Foo {}
+pub trait IFoo: Sized + std::ops::Deref {}
+#[repr(transparent)]
+#[derive(Clone)]
+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 IFoo for Bar {}
+impl PFoo for Bar {}
+impl From<Bar> for Foo {
+ fn from(child: Bar) -> Foo {
+ Foo(child.0)
+ }
+}
+impl std::convert::TryFrom<Foo> for Bar {
+ type Error = String;
+ 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(format!(
+ "This {} is not an cannot be downcasted to {}",
+ "Foo", "Bar"
+ ))
+ }
+ }
+}
+impl IBar for Bar {}
+pub trait IBar: Sized + std::ops::Deref {}
diff --git a/tests/headers/objc_protocol_inheritance.h b/tests/headers/objc_protocol_inheritance.h
new file mode 100644
index 00000000..d5f3a490
--- /dev/null
+++ b/tests/headers/objc_protocol_inheritance.h
@@ -0,0 +1,11 @@
+// bindgen-flags: --objc-extern-crate -- -x objective-c
+// bindgen-osx-only
+
+@protocol Foo
+@end
+
+@interface Foo <Foo>
+@end
+
+@interface Bar : Foo
+@end