@@ -168,7 +168,7 @@ const fn in_place_collectible<DEST, SRC>(
168
168
step_merge : Option < NonZeroUsize > ,
169
169
step_expand : Option < NonZeroUsize > ,
170
170
) -> bool {
171
- if DEST :: IS_ZST || mem:: align_of :: < SRC > ( ) < mem:: align_of :: < DEST > ( ) {
171
+ if const { SRC :: IS_ZST || DEST :: IS_ZST || mem:: align_of :: < SRC > ( ) < mem:: align_of :: < DEST > ( ) } {
172
172
return false ;
173
173
}
174
174
@@ -186,6 +186,32 @@ const fn in_place_collectible<DEST, SRC>(
186
186
}
187
187
}
188
188
189
+ const fn needs_realloc < SRC , DEST > ( src_cap : usize , dst_cap : usize ) -> bool {
190
+ if const { mem:: align_of :: < SRC > ( ) != mem:: align_of :: < DEST > ( ) } {
191
+ return true ;
192
+ }
193
+
194
+ if const {
195
+ // examples that may require reallocs unless src/dest capacities turn out to be multiples at runtime
196
+ // Vec<u8> -> Vec<[u8; 4]>
197
+ let dst_larger = mem:: size_of :: < SRC > ( ) < mem:: size_of :: < DEST > ( ) ;
198
+
199
+ // Vec<[u8; 3]> -> Vec<[u8; 2]>
200
+ // dest_sz can't actually be 0 since in_place_collectible() checks for that but const eval doesn't know that
201
+ let dest_sz = mem:: size_of :: < DEST > ( ) ;
202
+ let src_not_multiple_of_dest =
203
+ dest_sz == 0 || mem:: size_of :: < SRC > ( ) % mem:: size_of :: < DEST > ( ) != 0 ;
204
+
205
+ dst_larger || src_not_multiple_of_dest
206
+ } {
207
+ return src_cap * mem:: size_of :: < SRC > ( ) != dst_cap * mem:: size_of :: < DEST > ( ) ;
208
+ }
209
+
210
+ // Equal size + alignment won't need a realloc.
211
+ // src size being an integer multiple of the dest size works too
212
+ return false ;
213
+ }
214
+
189
215
/// This provides a shorthand for the source type since local type aliases aren't a thing.
190
216
#[ rustc_specialization_trait]
191
217
trait InPlaceCollect : SourceIter < Source : AsVecIntoIter > + InPlaceIterable {
@@ -259,12 +285,7 @@ where
259
285
// that wasn't a multiple of the destination type size.
260
286
// Since the discrepancy should generally be small this should only result in some
261
287
// bookkeeping updates and no memmove.
262
- if ( const {
263
- let src_sz = mem:: size_of :: < I :: Src > ( ) ;
264
- src_sz > 0 && mem:: size_of :: < T > ( ) % src_sz != 0
265
- } && src_cap * mem:: size_of :: < I :: Src > ( ) != dst_cap * mem:: size_of :: < T > ( ) )
266
- || const { mem:: align_of :: < T > ( ) != mem:: align_of :: < I :: Src > ( ) }
267
- {
288
+ if needs_realloc :: < I :: Src , T > ( src_cap, dst_cap) {
268
289
let alloc = Global ;
269
290
unsafe {
270
291
// The old allocation exists, therefore it must have a valid layout.
@@ -286,6 +307,8 @@ where
286
307
let Ok ( reallocated) = result else { handle_alloc_error ( new_layout) } ;
287
308
dst_buf = reallocated. as_ptr ( ) as * mut T ;
288
309
}
310
+ } else {
311
+ debug_assert_eq ! ( src_cap * mem:: size_of:: <I :: Src >( ) , dst_cap * mem:: size_of:: <T >( ) ) ;
289
312
}
290
313
291
314
mem:: forget ( dst_guard) ;
0 commit comments