5252//! Otherwise the input capacity (and thus layout) in bytes may not be representable by the output
5353//! `Vec<U>`. In that case `alloc.shrink()` is used to update the allocation's layout.
5454//!
55- //! Currently alignments of `T` and `U` must be the same. In principle smaller output alignments
56- //! could be supported but that would require always calling `alloc.shrink` for those transformations .
55+ //! Alignments of `T` must be the same or larger than `U`. Since alignments are always a power
56+ //! of two _larger_ implies _is a multiple of_ .
5757//!
5858//! See `in_place_collectible()` for the current conditions.
5959//!
@@ -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 DEST :: IS_ZST || mem:: align_of :: < SRC > ( ) < mem:: align_of :: < DEST > ( ) {
172172 return false ;
173173 }
174174
@@ -178,7 +178,7 @@ const fn in_place_collectible<DEST, SRC>(
178178 // e.g.
179179 // - 1 x [u8; 4] -> 4x u8, via flatten
180180 // - 4 x u8 -> 1x [u8; 4], via array_chunks
181- mem:: size_of :: < SRC > ( ) * step_merge. get ( ) = = mem:: size_of :: < DEST > ( ) * step_expand. get ( )
181+ mem:: size_of :: < SRC > ( ) * step_merge. get ( ) > = mem:: size_of :: < DEST > ( ) * step_expand. get ( )
182182 }
183183 // Fall back to other from_iter impls if an overflow occurred in the step merge/expansion
184184 // tracking.
@@ -255,12 +255,15 @@ where
255255 let dst_guard = InPlaceDstBufDrop { ptr : dst_buf, len, cap : dst_cap } ;
256256 src. forget_allocation_drop_remaining ( ) ;
257257
258- // Adjust the allocation size if the source had a capacity in bytes that wasn't a multiple
259- // of the destination type size.
258+ // Adjust the allocation if the alignment didn't match or the source had a capacity in bytes
259+ // that wasn't a multiple of the destination type size.
260260 // Since the discrepancy should generally be small this should only result in some
261261 // bookkeeping updates and no memmove.
262- if const { mem:: size_of :: < T > ( ) > mem:: size_of :: < I :: Src > ( ) }
263- && src_cap * mem:: size_of :: < I :: Src > ( ) != dst_cap * mem:: size_of :: < T > ( )
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 > ( ) }
264267 {
265268 let alloc = Global ;
266269 unsafe {
0 commit comments