When does vec.into_iter().map(...).collect() reallocate and when doesn't it?

62 points thefrankly93

Rust has a nifty optimization for the following pattern:
vec.into_iter().map(|x| x * 5).collect() where vec has type Vec<i32>.

In this case, the compiler will produce code that processes vec in-place and no allocation/deallocation takes place. It not only works with .map() but also .take() and .skip().

However, it doesn't work in some cases when I would expect it to work and I'd like to know what's the reason behind that.

If vec has type Vec<i32>, vec.into_iter().map(|x| (x as i16, x as i16)).collect() rellocates although the sizeof(i32) = sizeof((i16, i16)). So I thought, mapping between different types triggers reallocation. But vec.into_iter().map(|x| Foo(x)).collect() will run in-place (Rust will even figure out that it's a no-op so it just returns vec).

If vec has type Vec<(i16, i16)>, vec.into_iter().map(|_| Foo(42i16, 42i16)).collect() doesn't reallocate but vec.into_iter().map(|_| 42i32).collect() does.

Does anybody know why some cases need realloc while others don't?