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
- alloc:: { alloc, handle_alloc_error} ,
99
+ alloc:: { alloc, dealloc , 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.
@@ -195,9 +198,31 @@ unsafe impl<S: ?Sized + SliceDst> AllocSliceDst<S> for Box<S> {
195
198
where
196
199
I : FnOnce ( ptr:: NonNull < S > ) ,
197
200
{
198
- let ptr = alloc_slice_dst ( len) ;
199
- init ( ptr) ;
200
- Box :: from_raw ( ptr. as_ptr ( ) )
201
+ struct RawBox < S : ?Sized + SliceDst > ( ptr:: NonNull < S > , Layout ) ;
202
+
203
+ impl < S : ?Sized + SliceDst > RawBox < S > {
204
+ unsafe fn new ( len : usize ) -> Self {
205
+ let layout = S :: layout_for ( len) ;
206
+ RawBox ( alloc_slice_dst ( len) , layout)
207
+ }
208
+
209
+ unsafe fn finalize ( self ) -> Box < S > {
210
+ let this = ManuallyDrop :: new ( self ) ;
211
+ Box :: from_raw ( this. 0 . as_ptr ( ) )
212
+ }
213
+ }
214
+
215
+ impl < S : ?Sized + SliceDst > Drop for RawBox < S > {
216
+ fn drop ( & mut self ) {
217
+ unsafe {
218
+ dealloc ( self . 0 . as_ptr ( ) . cast ( ) , self . 1 ) ;
219
+ }
220
+ }
221
+ }
222
+
223
+ let ptr = RawBox :: new ( len) ;
224
+ init ( ptr. 0 ) ;
225
+ ptr. finalize ( )
201
226
}
202
227
}
203
228
@@ -221,7 +246,7 @@ unsafe impl<Header, Item> SliceDst for SliceWithHeader<Header, Item> {
221
246
Self :: layout ( len) . 0
222
247
}
223
248
224
- fn retype ( ptr : NonNull < [ ( ) ] > ) -> NonNull < Self > {
249
+ fn retype ( ptr : ptr :: NonNull < [ ( ) ] > ) -> ptr :: NonNull < Self > {
225
250
unsafe { ptr:: NonNull :: new_unchecked ( ptr. as_ptr ( ) as * mut _ ) }
226
251
}
227
252
}
@@ -246,30 +271,91 @@ impl<Header, Item> SliceWithHeader<Header, Item> {
246
271
I : IntoIterator < Item = Item > ,
247
272
I :: IntoIter : ExactSizeIterator ,
248
273
{
249
- let mut items = items. into_iter ( ) ;
274
+ let items = items. into_iter ( ) ;
250
275
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 ) ;
276
+
277
+ struct InProgress < Header , Item > {
278
+ raw : ptr:: NonNull < SliceWithHeader < Header , Item > > ,
279
+ written : usize ,
280
+ layout : Layout ,
281
+ length_offset : usize ,
282
+ header_offset : usize ,
283
+ slice_offset : usize ,
284
+ }
285
+
286
+ impl < Header , Item > Drop for InProgress < Header , Item > {
287
+ fn drop ( & mut self ) {
288
+ unsafe {
289
+ ptr:: drop_in_place ( slice_from_raw_parts (
290
+ self . raw ( ) . add ( self . slice_offset ) . cast :: < Item > ( ) ,
291
+ self . written ,
292
+ ) ) ;
293
+ }
294
+ }
295
+ }
296
+
297
+ impl < Header , Item > InProgress < Header , Item > {
298
+ fn init (
299
+ len : usize ,
300
+ header : Header ,
301
+ mut items : impl Iterator < Item = Item > + ExactSizeIterator ,
302
+ ) -> impl FnOnce ( ptr:: NonNull < SliceWithHeader < Header , Item > > ) {
303
+ move |ptr| {
304
+ let mut this = Self :: new ( len, ptr) ;
305
+
306
+ unsafe {
307
+ for _ in 0 ..len {
308
+ let item = items
309
+ . next ( )
310
+ . expect ( "ExactSizeIterator over-reported length" ) ;
311
+ this. push ( item) ;
312
+ }
313
+
314
+ assert ! (
315
+ items. next( ) . is_none( ) ,
316
+ "ExactSizeIterator under-reported length"
317
+ ) ;
318
+
319
+ this. finish ( len, header)
320
+ }
321
+ }
322
+ }
323
+
324
+ fn raw ( & self ) -> * mut u8 {
325
+ self . raw . as_ptr ( ) . cast ( )
326
+ }
327
+
328
+ fn new ( len : usize , raw : ptr:: NonNull < SliceWithHeader < Header , Item > > ) -> Self {
329
+ let ( layout, [ length_offset, header_offset, slice_offset] ) =
330
+ SliceWithHeader :: < Header , Item > :: layout ( len) ;
331
+ InProgress {
332
+ raw,
333
+ written : 0 ,
334
+ layout,
335
+ length_offset,
336
+ header_offset,
337
+ slice_offset,
265
338
}
266
- assert ! (
267
- items. next( ) . is_none( ) ,
268
- "ExactSizeIterator under-reported length"
269
- ) ;
270
- assert_eq ! ( layout, Layout :: for_value( ptr. as_ref( ) ) ) ;
271
- } )
339
+ }
340
+
341
+ unsafe fn push ( & mut self , item : Item ) {
342
+ self . raw ( )
343
+ . add ( self . slice_offset )
344
+ . cast :: < Item > ( )
345
+ . add ( self . written )
346
+ . write ( item) ;
347
+ self . written += 1 ;
348
+ }
349
+
350
+ unsafe fn finish ( self , len : usize , header : Header ) {
351
+ let this = ManuallyDrop :: new ( self ) ;
352
+ ptr:: write ( this. raw ( ) . add ( this. length_offset ) . cast ( ) , len) ;
353
+ ptr:: write ( this. raw ( ) . add ( this. header_offset ) . cast ( ) , header) ;
354
+ debug_assert_eq ! ( this. layout, Layout :: for_value( this. raw. as_ref( ) ) )
355
+ }
272
356
}
357
+
358
+ unsafe { A :: new_slice_dst ( len, InProgress :: init ( len, header, items) ) }
273
359
}
274
360
}
275
361
@@ -286,11 +372,6 @@ where
286
372
#[ cfg( feature = "erasable" ) ]
287
373
unsafe impl < Header , Item > Erasable for SliceWithHeader < Header , Item > {
288
374
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
375
let len: usize = ptr:: read ( this. as_ptr ( ) . cast ( ) ) ;
295
376
let raw = ptr:: NonNull :: new_unchecked ( slice_from_raw_parts ( this. as_ptr ( ) . cast ( ) , len) ) ;
296
377
Self :: retype ( raw)
0 commit comments