diff options
author | Sebastian Imlay <sebastian.imlay@gmail.com> | 2020-08-28 16:30:47 -0700 |
---|---|---|
committer | Emilio Cobos Álvarez <emilio@crisal.io> | 2020-09-16 12:26:24 +0200 |
commit | 81d323d8b1f81f298e59cd72eff5e57e381f55ac (patch) | |
tree | 785d708341b2513eb0e4091ca95e16adec98d489 | |
parent | 840b738ecfeefbd31d8676c60e2eca7ad6d0f424 (diff) |
Updates base on comments
* Added TryInto trait implementation from parent to child interfaces.
* Added HashSet for protocols so that the protocol inheritance works as
well.
-rw-r--r-- | src/codegen/mod.rs | 47 | ||||
-rw-r--r-- | tests/expectations/tests/libclang-9/objc_inheritance.rs | 45 | ||||
-rw-r--r-- | tests/expectations/tests/objc_protocol_inheritance.rs | 70 | ||||
-rw-r--r-- | tests/headers/objc_protocol_inheritance.h | 11 |
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 |