|
1 |
| -use core::mem::ManuallyDrop; |
2 | 1 | use core::ops::{Deref, DerefMut};
|
3 | 2 | use std::os::raw::c_char;
|
4 | 3 | use std::sync::Once;
|
5 | 4 |
|
6 | 5 | use crate::declare::{ClassBuilder, ProtocolBuilder};
|
7 |
| -use crate::runtime::{AnyClass, AnyObject, AnyProtocol, MessageReceiver, Sel}; |
8 |
| -use crate::{ffi, Encode, Encoding}; |
9 |
| -use crate::{msg_send, sel}; |
| 6 | +use crate::encode::{Encode, Encoding, RefEncode}; |
| 7 | +use crate::rc::Id; |
| 8 | +use crate::runtime::{AnyClass, AnyObject, AnyProtocol, Sel}; |
| 9 | +use crate::{ffi, msg_send, mutability, sel, ClassType, Message}; |
10 | 10 |
|
11 | 11 | #[derive(Debug)]
|
12 |
| -pub(crate) struct CustomObject { |
13 |
| - obj: *mut AnyObject, |
14 |
| -} |
| 12 | +#[repr(C)] |
| 13 | +pub(crate) struct CustomObject(AnyObject); |
15 | 14 |
|
16 |
| -impl CustomObject { |
17 |
| - fn new(class: &AnyClass) -> Self { |
18 |
| - let ptr: *const AnyClass = class; |
19 |
| - let obj = unsafe { ffi::class_createInstance(ptr.cast(), 0) }.cast(); |
20 |
| - CustomObject { obj } |
21 |
| - } |
| 15 | +unsafe impl RefEncode for CustomObject { |
| 16 | + const ENCODING_REF: Encoding = Encoding::Object; |
22 | 17 | }
|
23 | 18 |
|
24 |
| -unsafe impl MessageReceiver for &CustomObject { |
25 |
| - type __Inner = AnyObject; |
| 19 | +unsafe impl Message for CustomObject {} |
26 | 20 |
|
27 |
| - #[inline] |
28 |
| - fn __as_raw_receiver(self) -> *mut AnyObject { |
29 |
| - self.obj |
30 |
| - } |
31 |
| -} |
| 21 | +unsafe impl ClassType for CustomObject { |
| 22 | + type Super = AnyObject; |
| 23 | + |
| 24 | + type Mutability = mutability::Mutable; |
32 | 25 |
|
33 |
| -unsafe impl MessageReceiver for &mut CustomObject { |
34 |
| - type __Inner = AnyObject; |
| 26 | + const NAME: &'static str = "CustomObject"; |
35 | 27 |
|
36 |
| - #[inline] |
37 |
| - fn __as_raw_receiver(self) -> *mut AnyObject { |
38 |
| - self.obj |
| 28 | + fn class() -> &'static AnyClass { |
| 29 | + custom_class() |
39 | 30 | }
|
40 |
| -} |
41 | 31 |
|
42 |
| -unsafe impl MessageReceiver for ManuallyDrop<CustomObject> { |
43 |
| - type __Inner = AnyObject; |
| 32 | + fn as_super(&self) -> &Self::Super { |
| 33 | + &self.0 |
| 34 | + } |
44 | 35 |
|
45 |
| - #[inline] |
46 |
| - fn __as_raw_receiver(self) -> *mut AnyObject { |
47 |
| - self.obj |
| 36 | + fn as_super_mut(&mut self) -> &mut Self::Super { |
| 37 | + &mut self.0 |
48 | 38 | }
|
49 | 39 | }
|
50 | 40 |
|
51 | 41 | impl Deref for CustomObject {
|
52 | 42 | type Target = AnyObject;
|
53 | 43 |
|
54 | 44 | fn deref(&self) -> &AnyObject {
|
55 |
| - unsafe { self.obj.as_ref().unwrap_unchecked() } |
| 45 | + &self.0 |
56 | 46 | }
|
57 | 47 | }
|
58 | 48 |
|
59 | 49 | impl DerefMut for CustomObject {
|
60 | 50 | fn deref_mut(&mut self) -> &mut AnyObject {
|
61 |
| - unsafe { self.obj.as_mut().unwrap_unchecked() } |
62 |
| - } |
63 |
| -} |
64 |
| - |
65 |
| -impl Drop for CustomObject { |
66 |
| - fn drop(&mut self) { |
67 |
| - unsafe { |
68 |
| - #[allow(deprecated)] |
69 |
| - ffi::object_dispose(self.obj.cast()); |
70 |
| - } |
| 51 | + &mut self.0 |
71 | 52 | }
|
72 | 53 | }
|
73 | 54 |
|
@@ -105,8 +86,10 @@ pub(crate) fn custom_class() -> &'static AnyClass {
|
105 | 86 | builder.add_ivar::<u32>("_foo");
|
106 | 87 |
|
107 | 88 | unsafe extern "C" fn custom_obj_release(this: *mut AnyObject, _cmd: Sel) {
|
108 |
| - // Drop the value |
109 |
| - let _ = CustomObject { obj: this }; |
| 89 | + unsafe { |
| 90 | + #[allow(deprecated)] |
| 91 | + ffi::object_dispose(this.cast()); |
| 92 | + } |
110 | 93 | }
|
111 | 94 |
|
112 | 95 | extern "C" fn custom_obj_set_foo(this: &mut AnyObject, _cmd: Sel, foo: u32) {
|
@@ -172,8 +155,21 @@ pub(crate) fn custom_class() -> &'static AnyClass {
|
172 | 155 | }
|
173 | 156 |
|
174 | 157 | unsafe {
|
175 |
| - let release: unsafe extern "C" fn(_, _) = custom_obj_release; |
176 |
| - builder.add_method(sel!(release), release); |
| 158 | + // On GNUStep 2.0, it is required to have `dealloc` methods for some reason |
| 159 | + if cfg!(all(feature = "gnustep-2-0", not(feature = "gnustep-2-1"))) { |
| 160 | + unsafe extern "C" fn forward_to_dealloc(this: *mut AnyObject, _cmd: Sel) { |
| 161 | + unsafe { msg_send![this, dealloc] } |
| 162 | + } |
| 163 | + |
| 164 | + let release: unsafe extern "C" fn(_, _) = forward_to_dealloc; |
| 165 | + builder.add_method(sel!(release), release); |
| 166 | + |
| 167 | + let release: unsafe extern "C" fn(_, _) = custom_obj_release; |
| 168 | + builder.add_method(sel!(dealloc), release); |
| 169 | + } else { |
| 170 | + let release: unsafe extern "C" fn(_, _) = custom_obj_release; |
| 171 | + builder.add_method(sel!(release), release); |
| 172 | + } |
177 | 173 |
|
178 | 174 | let set_foo: extern "C" fn(_, _, _) = custom_obj_set_foo;
|
179 | 175 | builder.add_method(sel!(setFoo:), set_foo);
|
@@ -237,8 +233,9 @@ pub(crate) fn custom_subprotocol() -> &'static AnyProtocol {
|
237 | 233 | AnyProtocol::get("CustomSubProtocol").unwrap()
|
238 | 234 | }
|
239 | 235 |
|
240 |
| -pub(crate) fn custom_object() -> CustomObject { |
241 |
| - CustomObject::new(custom_class()) |
| 236 | +pub(crate) fn custom_object() -> Id<CustomObject> { |
| 237 | + let ptr: *const AnyClass = custom_class(); |
| 238 | + unsafe { Id::new(ffi::class_createInstance(ptr.cast(), 0).cast()) }.unwrap() |
242 | 239 | }
|
243 | 240 |
|
244 | 241 | pub(crate) fn custom_subclass() -> &'static AnyClass {
|
@@ -270,6 +267,7 @@ pub(crate) fn custom_subclass() -> &'static AnyClass {
|
270 | 267 | AnyClass::get("CustomSubclassObject").unwrap()
|
271 | 268 | }
|
272 | 269 |
|
273 |
| -pub(crate) fn custom_subclass_object() -> CustomObject { |
274 |
| - CustomObject::new(custom_subclass()) |
| 270 | +pub(crate) fn custom_subclass_object() -> Id<CustomObject> { |
| 271 | + let ptr: *const AnyClass = custom_subclass(); |
| 272 | + unsafe { Id::new(ffi::class_createInstance(ptr.cast(), 0).cast()) }.unwrap() |
275 | 273 | }
|
0 commit comments