@@ -25,7 +25,7 @@ use core::{
25
25
cell:: UnsafeCell ,
26
26
convert:: { AsRef , TryFrom } ,
27
27
marker:: { PhantomData , Unsize } ,
28
- mem:: ManuallyDrop ,
28
+ mem:: { ManuallyDrop , MaybeUninit } ,
29
29
ops:: Deref ,
30
30
pin:: Pin ,
31
31
ptr:: { self , NonNull } ,
@@ -107,8 +107,8 @@ impl<T> Ref<T> {
107
107
// SAFETY: By the invariant, `RefInner` is pinned and `T` is also pinned.
108
108
let pinned = unsafe { Pin :: new_unchecked ( & mut inner. as_mut ( ) . data ) } ;
109
109
110
- // INVARIANT: The only places where `&mut T` is available are here , which is explicitly
111
- // pinned, and in `drop`. Both are compatible with the pin requirements.
110
+ // INVARIANT: The only places where `&mut T` is available are in constructors , which are
111
+ // explicitly pinned, and in `drop`. Both are compatible with the pin requirements.
112
112
init ( pinned) ;
113
113
114
114
// SAFETY: We just created `inner` with a reference count of 1, which is owned by the new
@@ -343,3 +343,45 @@ impl<T: ?Sized> Deref for RefBorrow<T> {
343
343
self . inner_ref . deref ( )
344
344
}
345
345
}
346
+
347
+ /// An allocated but not yet initialised ref-counted object.
348
+ pub struct RefReservation < T > {
349
+ mem : Ref < MaybeUninit < T > > ,
350
+ }
351
+
352
+ impl < T > RefReservation < T > {
353
+ /// Allocates memory for a [`Ref<T>`] instance.
354
+ ///
355
+ /// The instance is not initialised yet.
356
+ pub fn try_new ( ) -> Result < Self > {
357
+ Ok ( Self {
358
+ mem : Ref :: try_new ( MaybeUninit :: < T > :: uninit ( ) ) ?,
359
+ } )
360
+ }
361
+
362
+ /// Converts a reservation into a real ref-counted object by initialising it.
363
+ pub fn commit ( self , data : T ) -> Ref < T > {
364
+ let mut inner = ManuallyDrop :: new ( self ) . mem . ptr ;
365
+ // SAFETY: `inner.data` is writable and properly aligned because it was allocated for a
366
+ // `MaybeUninit<T>`, which is compatible with `T`.
367
+ unsafe { inner. as_mut ( ) . data . as_mut_ptr ( ) . write ( data) } ;
368
+ // SAFETY: The new `Ref` is taking over `inner` from `self.mem` (which won't be dropped).
369
+ unsafe { Ref :: < T > :: from_inner ( inner. cast ( ) ) }
370
+ }
371
+
372
+ /// Converts a reservation into a real ref-counted object by initialising it with the given
373
+ /// value and callback.
374
+ ///
375
+ /// This is useful because it provides a mutable reference to `T` at its final location.
376
+ pub fn commit_and_init < U : FnOnce ( Pin < & mut T > ) > ( self , data : T , init : U ) -> Ref < T > {
377
+ let mut ret = self . commit ( data) ;
378
+
379
+ // SAFETY: By the invariant, `RefInner` is pinned and `T` is also pinned.
380
+ let pinned = unsafe { Pin :: new_unchecked ( & mut ret. ptr . as_mut ( ) . data ) } ;
381
+
382
+ // INVARIANT: The only places where `&mut T` is available are in constructors, which are
383
+ // explicitly pinned, and in `drop`. Both are compatible with the pin requirements.
384
+ init ( pinned) ;
385
+ ret
386
+ }
387
+ }
0 commit comments