@@ -168,7 +168,7 @@ const fn in_place_collectible<DEST, SRC>(
168168 step_merge : Option < NonZeroUsize > ,
169169 step_expand : Option < NonZeroUsize > ,
170170) -> 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 > ( ) } {
172172 return false ;
173173 }
174174
@@ -186,6 +186,34 @@ const fn in_place_collectible<DEST, SRC>(
186186 }
187187}
188188
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+ let src_sz = mem:: size_of :: < SRC > ( ) ;
196+ let dest_sz = mem:: size_of :: < DEST > ( ) ;
197+
198+ // examples that may require reallocs unless src/dest capacities turn out to be multiples at runtime
199+ // Vec<u8> -> Vec<[u8; 4]>
200+ let dst_larger = src_sz < dest_sz;
201+
202+ // Vec<[u8; 3]> -> Vec<[u8; 2]>
203+ // dest_sz can't actually be 0 since in_place_collectible() makes this unreachable in that case.
204+ // but const eval still runs on dead branches.
205+ let src_not_multiple_of_dest = dest_sz == 0 || src_sz % dest_sz != 0 ;
206+
207+ dst_larger || src_not_multiple_of_dest
208+ } {
209+ return src_cap * mem:: size_of :: < SRC > ( ) != dst_cap * mem:: size_of :: < DEST > ( ) ;
210+ }
211+
212+ // Equal size + alignment won't need a realloc.
213+ // src size being an integer multiple of the dest size works too
214+ return false ;
215+ }
216+
189217/// This provides a shorthand for the source type since local type aliases aren't a thing.
190218#[ rustc_specialization_trait]
191219trait InPlaceCollect : SourceIter < Source : AsVecIntoIter > + InPlaceIterable {
@@ -259,12 +287,7 @@ where
259287 // that wasn't a multiple of the destination type size.
260288 // Since the discrepancy should generally be small this should only result in some
261289 // 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- {
290+ if needs_realloc :: < I :: Src , T > ( src_cap, dst_cap) {
268291 let alloc = Global ;
269292 unsafe {
270293 // The old allocation exists, therefore it must have a valid layout.
@@ -286,6 +309,8 @@ where
286309 let Ok ( reallocated) = result else { handle_alloc_error ( new_layout) } ;
287310 dst_buf = reallocated. as_ptr ( ) as * mut T ;
288311 }
312+ } else {
313+ debug_assert_eq ! ( src_cap * mem:: size_of:: <I :: Src >( ) , dst_cap * mem:: size_of:: <T >( ) ) ;
289314 }
290315
291316 mem:: forget ( dst_guard) ;
0 commit comments