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