@@ -4,7 +4,7 @@ use core::mem::MaybeUninit;
4
4
use core:: ops:: { Deref , DerefMut } ;
5
5
use core:: ptr:: NonNull ;
6
6
7
- use crate :: encode:: { Encode , EncodeConvert } ;
7
+ use crate :: encode:: EncodeConvert ;
8
8
use crate :: runtime:: Object ;
9
9
10
10
/// Helper trait for defining instance variables.
@@ -44,14 +44,6 @@ pub unsafe trait IvarType {
44
44
const NAME : & ' static str ;
45
45
}
46
46
47
- unsafe impl < T : IvarType > IvarType for MaybeUninit < T >
48
- where
49
- T :: Type : Encode ,
50
- {
51
- type Type = MaybeUninit < T :: Type > ;
52
- const NAME : & ' static str = T :: NAME ;
53
- }
54
-
55
47
/// A wrapper type over a custom instance variable.
56
48
///
57
49
/// This type is not meant to be constructed by itself, it must reside within
@@ -138,7 +130,14 @@ pub struct Ivar<T: IvarType> {
138
130
}
139
131
140
132
impl < T : IvarType > Ivar < T > {
141
- fn get_ref ( & self ) -> & T :: Type {
133
+ /// Get a pointer to the instance variable.
134
+ ///
135
+ /// Note that if the ivar has already been initialized, you can simply
136
+ /// use the `Deref` implementation to get a reference.
137
+ ///
138
+ /// This is similar to [`MaybeUninit::as_ptr`], see that for usage
139
+ /// instructions.
140
+ pub fn as_ptr ( this : & Self ) -> * const T :: Type {
142
141
// SAFETY: The user ensures that this is placed in a struct that can
143
142
// be reinterpreted as an `Object`. Since `Ivar` can never be
144
143
// constructed by itself (and is neither Copy nor Clone), we know that
@@ -150,21 +149,27 @@ impl<T: IvarType> Ivar<T> {
150
149
// Note: We technically don't have provenance over the object, nor the
151
150
// ivar, but the object doesn't have provenance over the ivar either,
152
151
// so that is fine.
153
- let ptr = NonNull :: from ( self ) . cast :: < Object > ( ) ;
152
+ let ptr = NonNull :: from ( this ) . cast :: < Object > ( ) ;
154
153
let obj = unsafe { ptr. as_ref ( ) } ;
155
154
156
155
// SAFETY: User ensures that the `Ivar<T>` is only used when the ivar
157
156
// exists and has the correct type
158
- unsafe {
159
- obj. inner_ivar_ptr :: < T :: Type > ( T :: NAME )
160
- . as_ref ( )
161
- . unwrap_unchecked ( )
162
- }
157
+ unsafe { obj. inner_ivar_ptr :: < T :: Type > ( T :: NAME ) }
163
158
}
164
159
165
- fn get_mut_ptr ( & mut self ) -> * mut T :: Type {
166
- let ptr = NonNull :: from ( self ) . cast :: < Object > ( ) ;
167
- // SAFETY: Same as `get_ref`.
160
+ /// Get a mutable pointer to the instance variable.
161
+ ///
162
+ /// This is useful when you want to initialize the ivar inside an `init`
163
+ /// method (where it may otherwise not have been safely initialized yet).
164
+ ///
165
+ /// Note that if the ivar has already been initialized, you can simply
166
+ /// use the `DerefMut` implementation to get a mutable reference.
167
+ ///
168
+ /// This is similar to [`MaybeUninit::as_mut_ptr`], see that for usage
169
+ /// instructions.
170
+ fn as_mut_ptr ( this : & mut Self ) -> * mut T :: Type {
171
+ let ptr = NonNull :: from ( this) . cast :: < Object > ( ) ;
172
+ // SAFETY: Same as `as_ptr`.
168
173
//
169
174
// Note: We don't use `mut` because the user might have two mutable
170
175
// references to different ivars, as such:
@@ -185,6 +190,9 @@ impl<T: IvarType> Ivar<T> {
185
190
// And using `mut` would create aliasing mutable reference to the
186
191
// object.
187
192
//
193
+ // Since `Object` is `UnsafeCell`, so mutable access through `&Object`
194
+ // is allowed.
195
+ //
188
196
// TODO: Not entirely sure, it might be safe to just do `as_mut`, but
189
197
// this is definitely safe.
190
198
let obj = unsafe { ptr. as_ref ( ) } ;
@@ -194,12 +202,17 @@ impl<T: IvarType> Ivar<T> {
194
202
unsafe { obj. inner_ivar_ptr :: < T :: Type > ( T :: NAME ) }
195
203
}
196
204
197
- #[ inline]
198
- fn get_mut ( & mut self ) -> & mut T :: Type {
199
- // SAFETY: Safe as mutable because there is only one access to a
200
- // particular ivar at a time (since we have `&mut self`). `Object` is
201
- // `UnsafeCell`, so mutable access through `&Object` is allowed.
202
- unsafe { self . get_mut_ptr ( ) . as_mut ( ) . unwrap_unchecked ( ) }
205
+ /// Sets the value of the instance variable.
206
+ ///
207
+ /// This is useful when you want to initialize the ivar inside an `init`
208
+ /// method (where it may otherwise not have been safely initialized yet).
209
+ ///
210
+ /// This is similar to [`MaybeUninit::write`], see that for usage
211
+ /// instructions.
212
+ pub fn write ( this : & mut Self , val : T :: Type ) -> & mut T :: Type {
213
+ let ptr: * mut MaybeUninit < T :: Type > = Self :: as_mut_ptr ( this) . cast ( ) ;
214
+ let ivar = unsafe { ptr. as_mut ( ) . unwrap_unchecked ( ) } ;
215
+ ivar. write ( val)
203
216
}
204
217
}
205
218
@@ -208,14 +221,20 @@ impl<T: IvarType> Deref for Ivar<T> {
208
221
209
222
#[ inline]
210
223
fn deref ( & self ) -> & Self :: Target {
211
- self . get_ref ( )
224
+ // SAFETY: The ivar pointer always points to a valid instance.
225
+ //
226
+ // Since all accesses to a particular ivar only goes through one
227
+ // `Ivar`, if we have `&Ivar` we know that `&T` is safe.
228
+ unsafe { Self :: as_ptr ( self ) . as_ref ( ) . unwrap_unchecked ( ) }
212
229
}
213
230
}
214
231
215
232
impl < T : IvarType > DerefMut for Ivar < T > {
216
233
#[ inline]
217
234
fn deref_mut ( & mut self ) -> & mut Self :: Target {
218
- self . get_mut ( )
235
+ // SAFETY: Safe as mutable because there is only one access to a
236
+ // particular ivar at a time (since we have `&mut self`).
237
+ unsafe { Self :: as_mut_ptr ( self ) . as_mut ( ) . unwrap_unchecked ( ) }
219
238
}
220
239
}
221
240
0 commit comments