1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
use std::os::raw::{c_char, c_int, c_uint};

#[cfg(any(doc, not(objfw)))]
use crate::{objc_ivar, objc_method, objc_object, objc_property, objc_property_attribute_t};
use crate::{objc_protocol, objc_selector, OpaqueData, BOOL, IMP};

/// An opaque type that represents an Objective-C class.
#[repr(C)]
pub struct objc_class {
    // `isa` field is deprecated and not available on GNUStep, so we don't
    // expose it here. Use `class_getSuperclass` instead.
    _priv: [u8; 0],
    _p: OpaqueData,
}

#[cfg(any(doc, not(objfw)))]
/// This is `c_char` in GNUStep's libobjc2 and `uint8_t` in Apple's objc4.
///
/// The pointer represents opaque data, and is definitely not just an integer,
/// so its signedness (i8 vs. u8) is not applicable.
///
/// So we just assign it here as a private alias to u8, to not document the
/// difference.
type ivar_layout_type = u8;

// May call `resolveClassMethod:` or `resolveInstanceMethod:`.
extern_c_unwind! {
    #[cfg(any(doc, not(objfw)))]
    pub fn class_getClassMethod(
        cls: *const objc_class,
        name: *const objc_selector,
    ) -> *const objc_method;
    #[cfg(any(doc, not(objfw)))] // Available in newer versions
    pub fn class_getInstanceMethod(
        cls: *const objc_class,
        name: *const objc_selector,
    ) -> *const objc_method;

    pub fn class_respondsToSelector(cls: *const objc_class, sel: *const objc_selector) -> BOOL;

    // #[deprecated = "use class_getMethodImplementation instead"]
    // #[cfg(any(doc, apple))]
    // pub fn class_lookupMethod
    // #[deprecated = "use class_respondsToSelector instead"]
    // #[cfg(any(doc, apple))]
    // pub fn class_respondsToMethod
}

// TODO: Hooks registered with objc_setHook_getClass may be allowed to unwind?
extern_c! {
    pub fn objc_getClass(name: *const c_char) -> *const objc_class;
    pub fn objc_getRequiredClass(name: *const c_char) -> *const objc_class;
    pub fn objc_lookUpClass(name: *const c_char) -> *const objc_class;
    #[cfg(any(doc, not(objfw)))]
    pub fn objc_getMetaClass(name: *const c_char) -> *const objc_class;
    pub fn objc_copyClassList(out_len: *mut c_uint) -> *mut *const objc_class;
    pub fn objc_getClassList(buffer: *mut *const objc_class, buffer_len: c_int) -> c_int;

    pub fn objc_allocateClassPair(
        superclass: *const objc_class,
        name: *const c_char,
        extra_bytes: usize,
    ) -> *mut objc_class;
    #[cfg(any(doc, apple))]
    pub fn objc_duplicateClass(
        original: *const objc_class,
        name: *const c_char,
        extra_bytes: usize,
    ) -> *mut objc_class;
    #[cfg(any(doc, not(objfw)))]
    pub fn objc_disposeClassPair(cls: *mut objc_class);
    pub fn objc_registerClassPair(cls: *mut objc_class);

    #[cfg(any(doc, not(objfw)))]
    pub fn class_addIvar(
        cls: *mut objc_class,
        name: *const c_char,
        size: usize,
        alignment: u8,
        types: *const c_char,
    ) -> BOOL;
    pub fn class_addMethod(
        cls: *mut objc_class,
        name: *const objc_selector,
        imp: IMP,
        types: *const c_char,
    ) -> BOOL;
    #[cfg(any(doc, not(objfw)))]
    pub fn class_addProperty(
        cls: *mut objc_class,
        name: *const c_char,
        attributes: *const objc_property_attribute_t,
        attributes_count: c_uint,
    ) -> BOOL;
    #[cfg(any(doc, not(objfw)))]
    pub fn class_addProtocol(cls: *mut objc_class, protocol: *const objc_protocol) -> BOOL;
    pub fn class_conformsToProtocol(cls: *const objc_class, protocol: *const objc_protocol)
        -> BOOL;

    #[cfg(any(doc, not(objfw)))] // Available in newer versions
    pub fn class_copyIvarList(
        cls: *const objc_class,
        out_len: *mut c_uint,
    ) -> *mut *const objc_ivar;
    #[cfg(any(doc, not(objfw)))] // Available in newer versions
    pub fn class_copyMethodList(
        cls: *const objc_class,
        out_len: *mut c_uint,
    ) -> *mut *const objc_method;
    #[cfg(any(doc, not(objfw)))] // Available in newer versions
    pub fn class_copyPropertyList(
        cls: *const objc_class,
        out_len: *mut c_uint,
    ) -> *mut *const objc_property;
    #[cfg(any(doc, not(objfw)))]
    pub fn class_copyProtocolList(
        cls: *const objc_class,
        out_len: *mut c_uint,
    ) -> *mut *const objc_protocol;

    #[cfg(any(doc, not(objfw)))]
    pub fn class_createInstance(cls: *const objc_class, extra_bytes: usize) -> *mut objc_object;
    #[cfg(any(doc, not(objfw)))]
    pub fn class_getClassVariable(cls: *const objc_class, name: *const c_char) -> *const objc_ivar;
    #[cfg(any(doc, apple))]
    pub fn class_getImageName(cls: *const objc_class) -> *const c_char;
    pub fn class_getInstanceSize(cls: *const objc_class) -> usize;
    #[cfg(any(doc, not(objfw)))]
    pub fn class_getInstanceVariable(
        cls: *const objc_class,
        name: *const c_char,
    ) -> *const objc_ivar;
    #[cfg(any(doc, not(objfw)))]
    pub fn class_getIvarLayout(cls: *const objc_class) -> *const ivar_layout_type;
    pub fn class_getName(cls: *const objc_class) -> *const c_char;
    #[cfg(any(doc, not(objfw)))]
    pub fn class_getProperty(cls: *const objc_class, name: *const c_char) -> *const objc_property;
    pub fn class_getSuperclass(cls: *const objc_class) -> *const objc_class;
    #[cfg(any(doc, not(objfw)))]
    pub fn class_getVersion(cls: *const objc_class) -> c_int;
    #[cfg(any(doc, apple))]
    pub fn class_getWeakIvarLayout(cls: *const objc_class) -> *const ivar_layout_type;
    pub fn class_isMetaClass(cls: *const objc_class) -> BOOL;
    pub fn class_replaceMethod(
        cls: *mut objc_class,
        name: *const objc_selector,
        imp: IMP,
        types: *const c_char,
    ) -> IMP;
    #[cfg(any(doc, not(objfw)))]
    pub fn class_replaceProperty(
        cls: *mut objc_class,
        name: *const c_char,
        attributes: *const objc_property_attribute_t,
        attributes_len: c_uint,
    );
    #[cfg(any(doc, not(objfw)))]
    pub fn class_setIvarLayout(cls: *mut objc_class, layout: *const ivar_layout_type);
    #[cfg(any(doc, not(objfw)))]
    pub fn class_setVersion(cls: *mut objc_class, version: c_int);
    #[cfg(any(doc, apple))]
    pub fn class_setWeakIvarLayout(cls: *mut objc_class, layout: *const ivar_layout_type);

    // #[deprecated = "not recommended"]
    // pub fn class_setSuperclass
}