Skip to content

Commit 0bedb67

Browse files
committed
Added Categories to objective-c inheritance.
* Added items_mut to BindgenContext * Added Clone to ObjCInterface, ObjCMethod and FunctionSig :/ * Added references to the ObjCInterfaces for categories that extend a given ObjCInterface
1 parent b1a1ebc commit 0bedb67

File tree

7 files changed

+154
-5
lines changed

7 files changed

+154
-5
lines changed

src/codegen/mod.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3821,6 +3821,26 @@ impl CodeGenerator for ObjCInterface {
38213821
}
38223822
};
38233823
result.push(impl_trait);
3824+
for category in &parent.categories {
3825+
let category_name =
3826+
ctx.rust_ident(category.rust_name());
3827+
let impl_trait = if category.is_template() {
3828+
let template_names: Vec<Ident> = parent
3829+
.template_names
3830+
.iter()
3831+
.map(|g| ctx.rust_ident(g))
3832+
.collect();
3833+
quote! {
3834+
impl <#(#template_names :'static),*> #category_name <#(#template_names),*> for #class_name {
3835+
}
3836+
}
3837+
} else {
3838+
quote! {
3839+
impl #category_name for #class_name { }
3840+
}
3841+
};
3842+
result.push(impl_trait);
3843+
}
38243844
parent.parent_class
38253845
} else {
38263846
None

src/ir/context.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,17 @@ If you encounter an error missing from this list, please file an issue or a PR!"
902902
})
903903
}
904904

905+
/// IterMut over all items that have been defined.
906+
pub fn items_mut(&mut self) -> impl Iterator<Item = (ItemId, &mut Item)> {
907+
self.items
908+
.iter_mut()
909+
.enumerate()
910+
.filter_map(|(index, item)| {
911+
let item = item.as_mut()?;
912+
Some((ItemId(index), item))
913+
})
914+
}
915+
905916
/// Have we collected all unresolved type references yet?
906917
pub fn collected_typerefs(&self) -> bool {
907918
self.collected_typerefs

src/ir/function.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ impl quote::ToTokens for Abi {
210210
}
211211

212212
/// A function signature.
213-
#[derive(Debug)]
213+
#[derive(Debug, Clone)]
214214
pub struct FunctionSig {
215215
/// The return type of the function.
216216
return_type: TypeId,

src/ir/objc.rs

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use proc_macro2::{Ident, Span, TokenStream};
2121
/// Objective C interface as used in TypeKind
2222
///
2323
/// Also protocols and categories are parsed as this type
24-
#[derive(Debug)]
24+
#[derive(Debug, Clone)]
2525
pub struct ObjCInterface {
2626
/// The name
2727
/// like, NSObject
@@ -37,6 +37,9 @@ pub struct ObjCInterface {
3737
/// The list of protocols that this interface conforms to.
3838
pub conforms_to: Vec<ItemId>,
3939

40+
/// The list of categories that this interface is extended by.
41+
pub categories: Vec<ObjCInterface>,
42+
4043
/// The direct parent for this interface.
4144
pub parent_class: Option<ItemId>,
4245

@@ -47,7 +50,7 @@ pub struct ObjCInterface {
4750
}
4851

4952
/// The objective c methods
50-
#[derive(Debug)]
53+
#[derive(Debug, Clone)]
5154
pub struct ObjCMethod {
5255
/// The original method selector name
5356
/// like, dataWithBytes:length:
@@ -68,6 +71,7 @@ impl ObjCInterface {
6871
ObjCInterface {
6972
name: name.to_owned(),
7073
category: None,
74+
categories: Vec::new(),
7175
is_protocol: false,
7276
template_names: Vec::new(),
7377
parent_class: None,
@@ -140,9 +144,11 @@ impl ObjCInterface {
140144
CXCursor_ObjCClassRef => {
141145
if cursor.kind() == CXCursor_ObjCCategoryDecl {
142146
// We are actually a category extension, and we found the reference
143-
// to the original interface, so name this interface approriately
147+
// to the original interface, so name this interface approriately.
148+
144149
interface.name = c.spelling();
145150
interface.category = Some(cursor.spelling());
151+
146152
}
147153
}
148154
CXCursor_ObjCProtocolRef => {
@@ -194,6 +200,39 @@ impl ObjCInterface {
194200
}
195201
CXChildVisit_Continue
196202
});
203+
204+
if interface.is_category() {
205+
// If this interface is a category, we need to find the interface that this category
206+
// extends.
207+
let needle = format!("{}", interface.name());
208+
debug!(
209+
"Category {} belongs to {}, find the item",
210+
interface.rust_name(),
211+
needle
212+
);
213+
for (_, item) in ctx.items_mut() {
214+
if let Some(ref mut ty) = item.kind_mut().as_type_mut() {
215+
match ty.kind_mut() {
216+
TypeKind::ObjCInterface(ref mut real_interface) => {
217+
if !real_interface.is_category() {
218+
debug!("Checking interface {}, against needle {:?}", real_interface.name, needle);
219+
if needle == real_interface.name() {
220+
debug!(
221+
"Found real interface {:?}",
222+
real_interface
223+
);
224+
real_interface
225+
.categories
226+
.push(interface.clone());
227+
break;
228+
}
229+
}
230+
}
231+
_ => {}
232+
}
233+
}
234+
}
235+
}
197236
Some(interface)
198237
}
199238

src/ir/ty.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,7 @@ pub enum TypeKind {
627627
/// A compound type, that is, a class, struct, or union.
628628
Comp(CompInfo),
629629

630-
/// An opaque type that we just don't understand. All usage of this shoulf
630+
/// An opaque type that we just don't understand. All usage of this should
631631
/// result in an opaque blob of bytes generated from the containing type's
632632
/// layout.
633633
Opaque,
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
#![allow(
4+
dead_code,
5+
non_snake_case,
6+
non_camel_case_types,
7+
non_upper_case_globals
8+
)]
9+
#![cfg(target_os = "macos")]
10+
11+
#[macro_use]
12+
extern crate objc;
13+
#[allow(non_camel_case_types)]
14+
pub type id = *mut objc::runtime::Object;
15+
#[repr(transparent)]
16+
#[derive(Clone, Copy)]
17+
pub struct Foo(pub id);
18+
impl std::ops::Deref for Foo {
19+
type Target = objc::runtime::Object;
20+
fn deref(&self) -> &Self::Target {
21+
unsafe { &*self.0 }
22+
}
23+
}
24+
unsafe impl objc::Message for Foo {}
25+
impl Foo {
26+
pub fn alloc() -> Self {
27+
Self(unsafe { msg_send!(objc::class!(Foo), alloc) })
28+
}
29+
}
30+
impl IFoo for Foo {}
31+
pub trait IFoo: Sized + std::ops::Deref {
32+
unsafe fn method(self)
33+
where
34+
<Self as std::ops::Deref>::Target: objc::Message + Sized,
35+
{
36+
msg_send!(self, method)
37+
}
38+
}
39+
impl Foo_BarCategory for Foo {}
40+
pub trait Foo_BarCategory: Sized + std::ops::Deref {
41+
unsafe fn categoryMethod(self)
42+
where
43+
<Self as std::ops::Deref>::Target: objc::Message + Sized,
44+
{
45+
msg_send!(self, categoryMethod)
46+
}
47+
}
48+
#[repr(transparent)]
49+
#[derive(Clone, Copy)]
50+
pub struct Bar(pub id);
51+
impl std::ops::Deref for Bar {
52+
type Target = objc::runtime::Object;
53+
fn deref(&self) -> &Self::Target {
54+
unsafe { &*self.0 }
55+
}
56+
}
57+
unsafe impl objc::Message for Bar {}
58+
impl Bar {
59+
pub fn alloc() -> Self {
60+
Self(unsafe { msg_send!(objc::class!(Bar), alloc) })
61+
}
62+
}
63+
impl IFoo for Bar {}
64+
impl Foo_BarCategory for Bar {}
65+
impl IBar for Bar {}
66+
pub trait IBar: Sized + std::ops::Deref {}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// bindgen-flags: --objc-extern-crate -- -x objective-c
2+
// bindgen-osx-only
3+
4+
@interface Foo
5+
-(void)method;
6+
@end
7+
8+
@interface Foo (BarCategory)
9+
-(void)categoryMethod;
10+
@end
11+
12+
@interface Bar: Foo
13+
@end

0 commit comments

Comments
 (0)