157157use crate :: alloc:: { handle_alloc_error, Global } ;
158158use core:: alloc:: Allocator ;
159159use core:: alloc:: Layout ;
160- use core:: iter:: { InPlaceIterable , SourceIter , TrustedRandomAccessNoCoerce } ;
160+ use core:: iter:: UncheckedIndexedIterator ;
161+ use core:: iter:: { InPlaceIterable , SourceIter } ;
161162use core:: marker:: PhantomData ;
162163use core:: mem:: { self , ManuallyDrop , SizedTypeProperties } ;
163164use core:: num:: NonZeroUsize ;
@@ -237,7 +238,7 @@ where
237238 return SpecFromIterNested :: from_iter ( iterator) ;
238239 }
239240
240- let ( src_buf, src_ptr , src_cap, mut dst_buf, dst_end, dst_cap) = unsafe {
241+ let ( src_buf, _src_ptr , src_cap, mut dst_buf, dst_end, dst_cap) = unsafe {
241242 let inner = iterator. as_inner ( ) . as_into_iter ( ) ;
242243 (
243244 inner. buf . as_ptr ( ) ,
@@ -256,15 +257,11 @@ where
256257 // check if SourceIter contract was upheld
257258 // caveat: if they weren't we might not even make it to this point
258259 debug_assert_eq ! ( src_buf, src. buf. as_ptr( ) ) ;
259- // check InPlaceIterable contract. This is only possible if the iterator advanced the
260- // source pointer at all. If it uses unchecked access via TrustedRandomAccess
261- // then the source pointer will stay in its initial position and we can't use it as reference
262- if src. ptr != src_ptr {
263- debug_assert ! (
264- unsafe { dst_buf. add( len) as * const _ } <= src. ptr. as_ptr( ) ,
265- "InPlaceIterable contract violation, write pointer advanced beyond read pointer"
266- ) ;
267- }
260+ // check InPlaceIterable contract.
261+ debug_assert ! (
262+ unsafe { dst_buf. add( len) as * const _ } <= src. ptr. as_ptr( ) ,
263+ "InPlaceIterable contract violation, write pointer advanced beyond read pointer"
264+ ) ;
268265
269266 // The ownership of the source allocation and the new `T` values is temporarily moved into `dst_guard`.
270267 // This is safe because
@@ -369,28 +366,93 @@ where
369366 }
370367}
371368
369+ // impl<T, I> SpecInPlaceCollect<T, I> for I
370+ // where
371+ // I: Iterator<Item = T> + TrustedRandomAccessNoCoerce,
372+ // {
373+ // #[inline]
374+ // unsafe fn collect_in_place(&mut self, dst_buf: *mut T, end: *const T) -> usize {
375+ // let len = self.size();
376+ // let mut drop_guard = InPlaceDrop { inner: dst_buf, dst: dst_buf };
377+ // for i in 0..len {
378+ // // Safety: InplaceIterable contract guarantees that for every element we read
379+ // // one slot in the underlying storage will have been freed up and we can immediately
380+ // // write back the result.
381+ // unsafe {
382+ // let dst = dst_buf.add(i);
383+ // debug_assert!(dst as *const _ <= end, "InPlaceIterable contract violation");
384+ // ptr::write(dst, self.__iterator_get_unchecked(i));
385+ // // Since this executes user code which can panic we have to bump the pointer
386+ // // after each step.
387+ // drop_guard.dst = dst.add(1);
388+ // }
389+ // }
390+ // mem::forget(drop_guard);
391+ // len
392+ // }
393+ // }
394+
372395impl < T , I > SpecInPlaceCollect < T , I > for I
373396where
374- I : Iterator < Item = T > + TrustedRandomAccessNoCoerce ,
397+ I : Iterator < Item = T > + UncheckedIndexedIterator ,
375398{
376399 #[ inline]
377400 unsafe fn collect_in_place ( & mut self , dst_buf : * mut T , end : * const T ) -> usize {
378- let len = self . size ( ) ;
379- let mut drop_guard = InPlaceDrop { inner : dst_buf, dst : dst_buf } ;
380- for i in 0 ..len {
381- // Safety: InplaceIterable contract guarantees that for every element we read
382- // one slot in the underlying storage will have been freed up and we can immediately
383- // write back the result.
401+ let len = self . size_hint ( ) . 0 ;
402+
403+ if len == 0 {
404+ return 0 ;
405+ }
406+
407+ struct LoopGuard < ' a , I >
408+ where
409+ I : Iterator + UncheckedIndexedIterator ,
410+ {
411+ it : & ' a mut I ,
412+ len : usize ,
413+ idx : usize ,
414+ dst_buf : * mut I :: Item ,
415+ }
416+
417+ impl < I > Drop for LoopGuard < ' _ , I >
418+ where
419+ I : Iterator + UncheckedIndexedIterator ,
420+ {
421+ #[ inline]
422+ fn drop ( & mut self ) {
423+ unsafe {
424+ let new_len = self . len - self . idx ;
425+ self . it . set_front_index_from_end_unchecked ( new_len, self . len ) ;
426+ if self . idx != self . len {
427+ let raw_slice =
428+ ptr:: slice_from_raw_parts_mut :: < I :: Item > ( self . dst_buf , self . idx ) ;
429+ ptr:: drop_in_place ( raw_slice) ;
430+ }
431+ }
432+ }
433+ }
434+
435+ let mut state = LoopGuard { it : self , len, idx : 0 , dst_buf } ;
436+
437+ loop {
384438 unsafe {
385- let dst = dst_buf. add ( i) ;
439+ let idx = state. idx ;
440+ state. idx = state. idx . unchecked_add ( 1 ) ;
441+ let dst = state. dst_buf . add ( idx) ;
386442 debug_assert ! ( dst as * const _ <= end, "InPlaceIterable contract violation" ) ;
387- ptr:: write ( dst, self . __iterator_get_unchecked ( i) ) ;
388- // Since this executes user code which can panic we have to bump the pointer
389- // after each step.
390- drop_guard. dst = dst. add ( 1 ) ;
443+ dst. write ( state. it . index_from_end_unchecked ( state. len - idx) ) ;
444+ //drop_guard.dst = dst_buf.add(i).add(1);
445+ }
446+ if state. idx == len {
447+ break ;
391448 }
392449 }
393- mem:: forget ( drop_guard) ;
450+
451+ // disarm guard, we don't want the front elements to get dropped
452+ mem:: forget ( state) ;
453+ // since the guard is disarmed, update the iterator state
454+ unsafe { self . set_front_index_from_end_unchecked ( 0 , len) } ;
455+
394456 len
395457 }
396458}
0 commit comments