8888
8989extern crate alloc;
9090
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;
9295#[ cfg( feature = "erasable" ) ]
9396use erasable:: { Erasable , ErasedPtr } ;
9497use {
9598 alloc:: {
96- alloc:: { alloc, handle_alloc_error} ,
99+ alloc:: { alloc, dealloc , handle_alloc_error} ,
97100 boxed:: Box ,
98101 } ,
99- core:: { alloc:: Layout , ptr, slice} ,
102+ core:: { alloc:: Layout , mem :: ManuallyDrop , ptr, slice} ,
100103} ;
101104
102105/// A custom slice-based dynamically sized type.
@@ -195,9 +198,31 @@ unsafe impl<S: ?Sized + SliceDst> AllocSliceDst<S> for Box<S> {
195198 where
196199 I : FnOnce ( ptr:: NonNull < S > ) ,
197200 {
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 ( )
201226 }
202227}
203228
@@ -221,7 +246,7 @@ unsafe impl<Header, Item> SliceDst for SliceWithHeader<Header, Item> {
221246 Self :: layout ( len) . 0
222247 }
223248
224- fn retype ( ptr : NonNull < [ ( ) ] > ) -> NonNull < Self > {
249+ fn retype ( ptr : ptr :: NonNull < [ ( ) ] > ) -> ptr :: NonNull < Self > {
225250 unsafe { ptr:: NonNull :: new_unchecked ( ptr. as_ptr ( ) as * mut _ ) }
226251 }
227252}
@@ -246,30 +271,91 @@ impl<Header, Item> SliceWithHeader<Header, Item> {
246271 I : IntoIterator < Item = Item > ,
247272 I :: IntoIter : ExactSizeIterator ,
248273 {
249- let mut items = items. into_iter ( ) ;
274+ let items = items. into_iter ( ) ;
250275 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,
265338 }
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+ }
272356 }
357+
358+ unsafe { A :: new_slice_dst ( len, InProgress :: init ( len, header, items) ) }
273359 }
274360}
275361
@@ -286,11 +372,6 @@ where
286372#[ cfg( feature = "erasable" ) ]
287373unsafe impl < Header , Item > Erasable for SliceWithHeader < Header , Item > {
288374 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-
294375 let len: usize = ptr:: read ( this. as_ptr ( ) . cast ( ) ) ;
295376 let raw = ptr:: NonNull :: new_unchecked ( slice_from_raw_parts ( this. as_ptr ( ) . cast ( ) , len) ) ;
296377 Self :: retype ( raw)
0 commit comments