88
88
89
89
extern crate alloc;
90
90
91
- use core:: ptr:: NonNull ;
91
+ #[ cfg( has_ptr_slice_from_raw_parts) ]
92
+ use core:: ptr:: slice_from_raw_parts_mut as slice_from_raw_parts;
93
+ #[ cfg( not( has_ptr_slice_from_raw_parts) ) ]
94
+ use core:: slice:: from_raw_parts_mut as slice_from_raw_parts;
92
95
#[ cfg( feature = "erasable" ) ]
93
96
use erasable:: { Erasable , ErasedPtr } ;
94
97
use {
95
98
alloc:: {
96
99
alloc:: { alloc, handle_alloc_error} ,
97
100
boxed:: Box ,
98
101
} ,
99
- core:: { alloc:: Layout , ptr, slice} ,
102
+ core:: { alloc:: Layout , mem :: ManuallyDrop , ptr, slice} ,
100
103
} ;
101
104
102
105
/// A custom slice-based dynamically sized type.
@@ -221,7 +224,7 @@ unsafe impl<Header, Item> SliceDst for SliceWithHeader<Header, Item> {
221
224
Self :: layout ( len) . 0
222
225
}
223
226
224
- fn retype ( ptr : NonNull < [ ( ) ] > ) -> NonNull < Self > {
227
+ fn retype ( ptr : ptr :: NonNull < [ ( ) ] > ) -> ptr :: NonNull < Self > {
225
228
unsafe { ptr:: NonNull :: new_unchecked ( ptr. as_ptr ( ) as * mut _ ) }
226
229
}
227
230
}
@@ -246,30 +249,91 @@ impl<Header, Item> SliceWithHeader<Header, Item> {
246
249
I : IntoIterator < Item = Item > ,
247
250
I :: IntoIter : ExactSizeIterator ,
248
251
{
249
- let mut items = items. into_iter ( ) ;
252
+ let items = items. into_iter ( ) ;
250
253
let len = items. len ( ) ;
251
- let ( layout, [ length_offset, header_offset, slice_offset] ) = Self :: layout ( len) ;
252
-
253
- unsafe {
254
- A :: new_slice_dst ( len, |ptr| {
255
- let raw = ptr. as_ptr ( ) . cast :: < u8 > ( ) ;
256
- ptr:: write ( raw. add ( length_offset) . cast ( ) , len) ;
257
- ptr:: write ( raw. add ( header_offset) . cast ( ) , header) ;
258
- let mut slice_ptr = raw. add ( slice_offset) . cast :: < Item > ( ) ;
259
- for _ in 0 ..len {
260
- let item = items
261
- . next ( )
262
- . expect ( "ExactSizeIterator over-reported length" ) ;
263
- ptr:: write ( slice_ptr, item) ;
264
- slice_ptr = slice_ptr. offset ( 1 ) ;
254
+
255
+ struct InProgress < Header , Item > {
256
+ raw : ptr:: NonNull < SliceWithHeader < Header , Item > > ,
257
+ written : usize ,
258
+ layout : Layout ,
259
+ length_offset : usize ,
260
+ header_offset : usize ,
261
+ slice_offset : usize ,
262
+ }
263
+
264
+ impl < Header , Item > Drop for InProgress < Header , Item > {
265
+ fn drop ( & mut self ) {
266
+ unsafe {
267
+ ptr:: drop_in_place ( slice_from_raw_parts (
268
+ self . raw ( ) . add ( self . slice_offset ) . cast :: < Item > ( ) ,
269
+ self . written ,
270
+ ) ) ;
265
271
}
266
- assert ! (
267
- items. next( ) . is_none( ) ,
268
- "ExactSizeIterator under-reported length"
269
- ) ;
270
- assert_eq ! ( layout, Layout :: for_value( ptr. as_ref( ) ) ) ;
271
- } )
272
+ }
272
273
}
274
+
275
+ impl < Header , Item > InProgress < Header , Item > {
276
+ fn init (
277
+ len : usize ,
278
+ header : Header ,
279
+ mut items : impl Iterator < Item = Item > + ExactSizeIterator ,
280
+ ) -> impl FnOnce ( ptr:: NonNull < SliceWithHeader < Header , Item > > ) {
281
+ move |ptr| {
282
+ let mut this = Self :: new ( len, ptr) ;
283
+
284
+ unsafe {
285
+ for _ in 0 ..len {
286
+ let item = items
287
+ . next ( )
288
+ . expect ( "ExactSizeIterator over-reported length" ) ;
289
+ this. push ( item) ;
290
+ }
291
+
292
+ assert ! (
293
+ items. next( ) . is_none( ) ,
294
+ "ExactSizeIterator under-reported length"
295
+ ) ;
296
+
297
+ this. finish ( len, header)
298
+ }
299
+ }
300
+ }
301
+
302
+ fn raw ( & self ) -> * mut u8 {
303
+ self . raw . as_ptr ( ) . cast ( )
304
+ }
305
+
306
+ fn new ( len : usize , raw : ptr:: NonNull < SliceWithHeader < Header , Item > > ) -> Self {
307
+ let ( layout, [ length_offset, header_offset, slice_offset] ) =
308
+ SliceWithHeader :: < Header , Item > :: layout ( len) ;
309
+ InProgress {
310
+ raw,
311
+ written : 0 ,
312
+ layout,
313
+ length_offset,
314
+ header_offset,
315
+ slice_offset,
316
+ }
317
+ }
318
+
319
+ unsafe fn push ( & mut self , item : Item ) {
320
+ self . raw ( )
321
+ . add ( self . slice_offset )
322
+ . cast :: < Item > ( )
323
+ . add ( self . written )
324
+ . write ( item) ;
325
+ self . written += 1 ;
326
+ }
327
+
328
+ unsafe fn finish ( self , len : usize , header : Header ) {
329
+ let this = ManuallyDrop :: new ( self ) ;
330
+ ptr:: write ( this. raw ( ) . add ( this. length_offset ) . cast ( ) , len) ;
331
+ ptr:: write ( this. raw ( ) . add ( this. header_offset ) . cast ( ) , header) ;
332
+ debug_assert_eq ! ( this. layout, Layout :: for_value( this. raw. as_ref( ) ) )
333
+ }
334
+ }
335
+
336
+ unsafe { A :: new_slice_dst ( len, InProgress :: init ( len, header, items) ) }
273
337
}
274
338
}
275
339
@@ -286,11 +350,6 @@ where
286
350
#[ cfg( feature = "erasable" ) ]
287
351
unsafe impl < Header , Item > Erasable for SliceWithHeader < Header , Item > {
288
352
unsafe fn unerase ( this : ErasedPtr ) -> ptr:: NonNull < Self > {
289
- #[ cfg( not( has_ptr_slice_from_raw_parts) ) ]
290
- let slice_from_raw_parts = slice:: from_raw_parts_mut :: < ( ) > ;
291
- #[ cfg( has_ptr_slice_from_raw_parts) ]
292
- let slice_from_raw_parts = ptr:: slice_from_raw_parts_mut :: < ( ) > ;
293
-
294
353
let len: usize = ptr:: read ( this. as_ptr ( ) . cast ( ) ) ;
295
354
let raw = ptr:: NonNull :: new_unchecked ( slice_from_raw_parts ( this. as_ptr ( ) . cast ( ) , len) ) ;
296
355
Self :: retype ( raw)
0 commit comments