@@ -2,11 +2,79 @@ use core::fmt;
2
2
use core:: marker:: PhantomData ;
3
3
use core:: mem:: MaybeUninit ;
4
4
use core:: ops:: { Deref , DerefMut } ;
5
- use core:: ptr:: NonNull ;
5
+ use core:: ptr:: { self , NonNull } ;
6
6
7
- use crate :: encode:: EncodeConvert ;
7
+ use crate :: encode:: { EncodeConvert , Encoding } ;
8
8
use crate :: runtime:: { ivar_offset, Object } ;
9
9
10
+ /// Types that may be used in ivars.
11
+ ///
12
+ /// This may be either:
13
+ /// - [`bool`].
14
+ /// - [`IvarDrop<T>`][super::IvarDrop].
15
+ /// - Something that implements [`Encode`][crate::Encode].
16
+ ///
17
+ /// This is a sealed
18
+ ///
19
+ ///
20
+ /// # Safety
21
+ ///
22
+ /// You cannot rely on any safety guarantees from this.
23
+ pub unsafe trait InnerIvarType {
24
+ #[ doc( hidden) ]
25
+ const __ENCODING: Encoding ;
26
+
27
+ // SAFETY: It must be safe to transmute from `__Inner` to `Output`.
28
+ #[ doc( hidden) ]
29
+ type __Inner ;
30
+
31
+ /// The type that an `Ivar` containing this will dereference to.
32
+ ///
33
+ /// E.g. `Ivar<IvarDrop<Box<u8>>>` will deref to `Box<u8>`.
34
+ type Output ;
35
+
36
+ // SAFETY: The __Inner type must be safe to drop even if zero-initialized.
37
+ #[ doc( hidden) ]
38
+ const __MAY_DROP: bool ;
39
+
40
+ #[ doc( hidden) ]
41
+ unsafe fn __to_ref ( inner : & Self :: __Inner ) -> & Self :: Output ;
42
+
43
+ #[ doc( hidden) ]
44
+ unsafe fn __to_mut ( inner : & mut Self :: __Inner ) -> & mut Self :: Output ;
45
+
46
+ #[ doc( hidden) ]
47
+ fn __to_ptr ( inner : NonNull < Self :: __Inner > ) -> NonNull < Self :: Output > ;
48
+ }
49
+
50
+ unsafe impl < T : EncodeConvert > InnerIvarType for T {
51
+ const __ENCODING: Encoding = <Self as EncodeConvert >:: __ENCODING;
52
+ type __Inner = Self ;
53
+ type Output = Self ;
54
+ // Note: We explicitly tell `Ivar` that it shouldn't do anything to drop,
55
+ // since if the object was deallocated before an `init` method was called,
56
+ // the ivar would not have been initialized properly!
57
+ //
58
+ // For example in the case of `NonNull<u8>`, it would be zero-initialized
59
+ // which is an invalid state for that.
60
+ const __MAY_DROP: bool = false ;
61
+
62
+ #[ inline]
63
+ unsafe fn __to_ref ( inner : & Self :: __Inner ) -> & Self :: Output {
64
+ inner
65
+ }
66
+
67
+ #[ inline]
68
+ unsafe fn __to_mut ( inner : & mut Self :: __Inner ) -> & mut Self :: Output {
69
+ inner
70
+ }
71
+
72
+ #[ inline]
73
+ fn __to_ptr ( inner : NonNull < Self :: __Inner > ) -> NonNull < Self :: Output > {
74
+ inner
75
+ }
76
+ }
77
+
10
78
/// Helper trait for defining instance variables.
11
79
///
12
80
/// This should be implemented for an empty marker type, which can then be
@@ -39,7 +107,7 @@ use crate::runtime::{ivar_offset, Object};
39
107
/// ```
40
108
pub unsafe trait IvarType {
41
109
/// The type of the instance variable.
42
- type Type : EncodeConvert ;
110
+ type Type : InnerIvarType ;
43
111
/// The name of the instance variable.
44
112
const NAME : & ' static str ;
45
113
@@ -132,7 +200,18 @@ pub struct Ivar<T: IvarType> {
132
200
/// Make this type allowed in `repr(C)`
133
201
inner : [ u8 ; 0 ] ,
134
202
/// For proper variance and auto traits
135
- item : PhantomData < T :: Type > ,
203
+ item : PhantomData < <T :: Type as InnerIvarType >:: Output > ,
204
+ }
205
+
206
+ impl < T : IvarType > Drop for Ivar < T > {
207
+ #[ inline]
208
+ fn drop ( & mut self ) {
209
+ if <T :: Type as InnerIvarType >:: __MAY_DROP {
210
+ // SAFETY: We drop the inner type, which is guaranteed by
211
+ // `__MAY_DROP` to always be safe to drop.
212
+ unsafe { ptr:: drop_in_place ( self . as_inner_mut_ptr ( ) . as_ptr ( ) ) }
213
+ }
214
+ }
136
215
}
137
216
138
217
impl < T : IvarType > Ivar < T > {
@@ -143,8 +222,12 @@ impl<T: IvarType> Ivar<T> {
143
222
///
144
223
/// This is similar to [`MaybeUninit::as_ptr`], see that for usage
145
224
/// instructions.
146
- pub fn as_ptr ( this : & Self ) -> * const T :: Type {
147
- let ptr: NonNull < Object > = NonNull :: from ( this) . cast ( ) ;
225
+ pub fn as_ptr ( this : & Self ) -> * const <T :: Type as InnerIvarType >:: Output {
226
+ T :: Type :: __to_ptr ( this. as_inner_ptr ( ) ) . as_ptr ( )
227
+ }
228
+
229
+ fn as_inner_ptr ( & self ) -> NonNull < <T :: Type as InnerIvarType >:: __Inner > {
230
+ let ptr: NonNull < Object > = NonNull :: from ( self ) . cast ( ) ;
148
231
149
232
// SAFETY: The user ensures that this is placed in a struct that can
150
233
// be reinterpreted as an `Object`. Since `Ivar` can never be
@@ -159,9 +242,7 @@ impl<T: IvarType> Ivar<T> {
159
242
// so that is fine.
160
243
let offset = unsafe { T :: __offset ( ptr) } ;
161
244
// SAFETY: The offset is valid
162
- let ptr = unsafe { Object :: ivar_at_offset :: < T :: Type > ( ptr, offset) } ;
163
-
164
- ptr. as_ptr ( )
245
+ unsafe { Object :: ivar_at_offset :: < <T :: Type as InnerIvarType >:: __Inner > ( ptr, offset) }
165
246
}
166
247
167
248
/// Get a mutable pointer to the instance variable.
@@ -174,16 +255,17 @@ impl<T: IvarType> Ivar<T> {
174
255
///
175
256
/// This is similar to [`MaybeUninit::as_mut_ptr`], see that for usage
176
257
/// instructions.
177
- fn as_mut_ptr ( this : & mut Self ) -> * mut T :: Type {
178
- let ptr: NonNull < Object > = NonNull :: from ( this) . cast ( ) ;
258
+ pub fn as_mut_ptr ( this : & mut Self ) -> * mut <T :: Type as InnerIvarType >:: Output {
259
+ T :: Type :: __to_ptr ( this. as_inner_mut_ptr ( ) ) . as_ptr ( )
260
+ }
261
+
262
+ fn as_inner_mut_ptr ( & mut self ) -> NonNull < <T :: Type as InnerIvarType >:: __Inner > {
263
+ let ptr: NonNull < Object > = NonNull :: from ( self ) . cast ( ) ;
179
264
180
- // SAFETY: Same as `as_ptr `
265
+ // SAFETY: Same as `as_inner_ptr `
181
266
let offset = unsafe { T :: __offset ( ptr) } ;
182
267
// SAFETY: The offset is valid
183
- let ptr = unsafe { Object :: ivar_at_offset :: < T :: Type > ( ptr, offset) } ;
184
-
185
- // Safe as *mut T because it came from `&mut Self`
186
- ptr. as_ptr ( )
268
+ unsafe { Object :: ivar_at_offset :: < <T :: Type as InnerIvarType >:: __Inner > ( ptr, offset) }
187
269
}
188
270
189
271
/// Sets the value of the instance variable.
@@ -193,15 +275,19 @@ impl<T: IvarType> Ivar<T> {
193
275
///
194
276
/// This is similar to [`MaybeUninit::write`], see that for usage
195
277
/// instructions.
196
- pub fn write ( this : & mut Self , val : T :: Type ) -> & mut T :: Type {
197
- let ptr: * mut MaybeUninit < T :: Type > = Self :: as_mut_ptr ( this) . cast ( ) ;
278
+ pub fn write (
279
+ this : & mut Self ,
280
+ val : <T :: Type as InnerIvarType >:: Output ,
281
+ ) -> & mut <T :: Type as InnerIvarType >:: Output {
282
+ let ptr: * mut MaybeUninit < <T :: Type as InnerIvarType >:: Output > =
283
+ Self :: as_mut_ptr ( this) . cast ( ) ;
198
284
let ivar = unsafe { ptr. as_mut ( ) . unwrap_unchecked ( ) } ;
199
285
ivar. write ( val)
200
286
}
201
287
}
202
288
203
289
impl < T : IvarType > Deref for Ivar < T > {
204
- type Target = T :: Type ;
290
+ type Target = < T :: Type as InnerIvarType > :: Output ;
205
291
206
292
#[ inline]
207
293
fn deref ( & self ) -> & Self :: Target {
@@ -210,7 +296,7 @@ impl<T: IvarType> Deref for Ivar<T> {
210
296
//
211
297
// Since all accesses to a particular ivar only goes through one
212
298
// `Ivar`, if we have `&Ivar` we know that `&T` is safe.
213
- unsafe { Self :: as_ptr ( self ) . as_ref ( ) . unwrap_unchecked ( ) }
299
+ unsafe { T :: Type :: __to_ref ( self . as_inner_ptr ( ) . as_ref ( ) ) }
214
300
}
215
301
}
216
302
@@ -241,25 +327,27 @@ impl<T: IvarType> DerefMut for Ivar<T> {
241
327
//
242
328
// And using `mut` would create aliasing mutable reference to the
243
329
// object.
244
- unsafe { Self :: as_mut_ptr ( self ) . as_mut ( ) . unwrap_unchecked ( ) }
330
+ unsafe { T :: Type :: __to_mut ( self . as_inner_mut_ptr ( ) . as_mut ( ) ) }
245
331
}
246
332
}
247
333
248
334
/// Format as a pointer to the instance variable.
249
335
impl < T : IvarType > fmt:: Pointer for Ivar < T > {
250
336
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
251
- let ptr: * const T :: Type = & * * self ;
252
- fmt:: Pointer :: fmt ( & ptr, f)
337
+ fmt:: Pointer :: fmt ( & Self :: as_ptr ( self ) , f)
253
338
}
254
339
}
255
340
256
341
#[ cfg( test) ]
257
342
mod tests {
258
343
use core:: mem;
259
344
use core:: panic:: { RefUnwindSafe , UnwindSafe } ;
345
+ use std:: sync:: atomic:: { AtomicBool , Ordering } ;
260
346
261
347
use super :: * ;
262
- use crate :: { msg_send, test_utils, MessageReceiver } ;
348
+ use crate :: foundation:: NSObject ;
349
+ use crate :: rc:: { Id , Owned } ;
350
+ use crate :: { declare_class, msg_send, msg_send_id, test_utils, ClassType , MessageReceiver } ;
263
351
264
352
struct TestIvar ;
265
353
@@ -297,4 +385,31 @@ mod tests {
297
385
} ;
298
386
assert_eq ! ( * obj. foo, 42 ) ;
299
387
}
388
+
389
+ #[ test]
390
+ fn ensure_custom_drop_is_possible ( ) {
391
+ static HAS_RUN_DEALLOC : AtomicBool = AtomicBool :: new ( false ) ;
392
+
393
+ declare_class ! (
394
+ #[ derive( Debug , PartialEq ) ]
395
+ struct CustomDrop {
396
+ ivar: u8 ,
397
+ }
398
+
399
+ unsafe impl ClassType for CustomDrop {
400
+ type Super = NSObject ;
401
+ }
402
+
403
+ unsafe impl CustomDrop {
404
+ #[ sel( dealloc) ]
405
+ fn dealloc( & mut self ) {
406
+ HAS_RUN_DEALLOC . store( true , Ordering :: SeqCst ) ;
407
+ }
408
+ }
409
+ ) ;
410
+
411
+ let _: Id < CustomDrop , Owned > = unsafe { msg_send_id ! [ CustomDrop :: class( ) , new] } ;
412
+
413
+ assert ! ( HAS_RUN_DEALLOC . load( Ordering :: SeqCst ) ) ;
414
+ }
300
415
}
0 commit comments