72
72
//! This is handled by the [`InPlaceDrop`] guard for sink items (`U`) and by
73
73
//! [`vec::IntoIter::forget_allocation_drop_remaining()`] for remaining source items (`T`).
74
74
//!
75
- //! If dropping any remaining source item (`T`) panics then [`InPlaceDstBufDrop `] will handle dropping
75
+ //! If dropping any remaining source item (`T`) panics then [`InPlaceDstDataSrcBufDrop `] will handle dropping
76
76
//! the already collected sink items (`U`) and freeing the allocation.
77
77
//!
78
78
//! [`vec::IntoIter::forget_allocation_drop_remaining()`]: super::IntoIter::forget_allocation_drop_remaining()
@@ -158,17 +158,20 @@ use crate::alloc::{handle_alloc_error, Global};
158
158
use core:: alloc:: Allocator ;
159
159
use core:: alloc:: Layout ;
160
160
use core:: iter:: { InPlaceIterable , SourceIter , TrustedRandomAccessNoCoerce } ;
161
+ use core:: marker:: PhantomData ;
161
162
use core:: mem:: { self , ManuallyDrop , SizedTypeProperties } ;
162
163
use core:: num:: NonZeroUsize ;
163
164
use core:: ptr:: { self , NonNull } ;
164
165
165
- use super :: { InPlaceDrop , InPlaceDstBufDrop , SpecFromIter , SpecFromIterNested , Vec } ;
166
+ use super :: { InPlaceDrop , InPlaceDstDataSrcBufDrop , SpecFromIter , SpecFromIterNested , Vec } ;
166
167
167
168
const fn in_place_collectible < DEST , SRC > (
168
169
step_merge : Option < NonZeroUsize > ,
169
170
step_expand : Option < NonZeroUsize > ,
170
171
) -> bool {
171
- if const { SRC :: IS_ZST || DEST :: IS_ZST || mem:: align_of :: < SRC > ( ) < mem:: align_of :: < DEST > ( ) } {
172
+ // Require matching alignments because an alignment-changing realloc is inefficient on many
173
+ // system allocators and better implementations would require the unstable Allocator trait.
174
+ if const { SRC :: IS_ZST || DEST :: IS_ZST || mem:: align_of :: < SRC > ( ) != mem:: align_of :: < DEST > ( ) } {
172
175
return false ;
173
176
}
174
177
@@ -188,7 +191,8 @@ const fn in_place_collectible<DEST, SRC>(
188
191
189
192
const fn needs_realloc < SRC , DEST > ( src_cap : usize , dst_cap : usize ) -> bool {
190
193
if const { mem:: align_of :: < SRC > ( ) != mem:: align_of :: < DEST > ( ) } {
191
- return src_cap > 0 ;
194
+ // FIXME: use unreachable! once that works in const
195
+ panic ! ( "in_place_collectible() prevents this" ) ;
192
196
}
193
197
194
198
// If src type size is an integer multiple of the destination type size then
@@ -262,7 +266,7 @@ where
262
266
) ;
263
267
}
264
268
265
- // The ownership of the allocation and the new `T` values is temporarily moved into `dst_guard`.
269
+ // The ownership of the source allocation and the new `T` values is temporarily moved into `dst_guard`.
266
270
// This is safe because
267
271
// * `forget_allocation_drop_remaining` immediately forgets the allocation
268
272
// before any panic can occur in order to avoid any double free, and then proceeds to drop
@@ -273,11 +277,12 @@ where
273
277
// Note: This access to the source wouldn't be allowed by the TrustedRandomIteratorNoCoerce
274
278
// contract (used by SpecInPlaceCollect below). But see the "O(1) collect" section in the
275
279
// module documentation why this is ok anyway.
276
- let dst_guard = InPlaceDstBufDrop { ptr : dst_buf, len, cap : dst_cap } ;
280
+ let dst_guard =
281
+ InPlaceDstDataSrcBufDrop { ptr : dst_buf, len, src_cap, src : PhantomData :: < I :: Src > } ;
277
282
src. forget_allocation_drop_remaining ( ) ;
278
283
279
- // Adjust the allocation if the alignment didn't match or the source had a capacity in bytes
280
- // that wasn't a multiple of the destination type size.
284
+ // Adjust the allocation if the source had a capacity in bytes that wasn't a multiple
285
+ // of the destination type size.
281
286
// Since the discrepancy should generally be small this should only result in some
282
287
// bookkeeping updates and no memmove.
283
288
if needs_realloc :: < I :: Src , T > ( src_cap, dst_cap) {
@@ -290,7 +295,7 @@ where
290
295
let src_size = mem:: size_of :: < I :: Src > ( ) . unchecked_mul ( src_cap) ;
291
296
let old_layout = Layout :: from_size_align_unchecked ( src_size, src_align) ;
292
297
293
- // The must be equal or smaller for in-place iteration to be possible
298
+ // The allocation must be equal or smaller for in-place iteration to be possible
294
299
// therefore the new layout must be ≤ the old one and therefore valid.
295
300
let dst_align = mem:: align_of :: < T > ( ) ;
296
301
let dst_size = mem:: size_of :: < T > ( ) . unchecked_mul ( dst_cap) ;
0 commit comments