rust-lang / libs-team

The home of the library team
Apache License 2.0
127 stars 19 forks source link

ACP: Implement FromIterator for Box<str> #196

Closed calebsander closed 8 months ago

calebsander commented 1 year ago

Proposal

Problem statement

Boxed slices are space-saving alternatives to Vec and String when the ability to grow the allocation is not required. To make them easier replacements, it would be ideal for Box<[T]> and Box<str> to provide all the functionality of Vec<T> and String that doesn't require resizing. One functionality gap is that String implements FromIterator (for 6 types of Iterator item), but Box<str> doesn't. There's already an analogous implementation for Box<[T]>: FromIterator is implemented for Box<[T]> by using Vec<T>'s FromIterator implementation and then calling into_boxed_slice() to convert to a Box<[T]>. The proposal is to do the same thing for Box<str>: provide the same FromIterator implementations that String has, which can be implemented by collecting into a String and then calling into_boxed_str().

Additionally, impl FromIterator<Box<str>> for String and impl Extend<Box<str>> for String can be generalized to allow boxed strings with allocators other than Global. The implementations already copy the bytes to the String's allocation, so they work for Box<str, A> with any A: Allocator.

Motivation, use-cases

The existing impl<I> FromIterator<I> for Box<[I]> makes it convenient to collect an iterator into a boxed slice, for example:

let squares: Box<_> = (1..10).map(|x| x * x).collect();

Box<str> is an even more useful alternative to String than Box<[T]> is for Vec<T>, as strings are often immutable. The existing FromIterator<char> implementation for String makes it easy, for example, to reverse the characters in a string:

fn reverse(s: &str) -> String {
    s.chars().rev().collect()
}

However, returning a Box<str> requires a much more verbose implementation:

fn reverse(s: &str) -> Box<str> {
    s.chars().rev().collect::<String>().into_boxed_str()
}

Providing a FromIterator implementation for Box<str> would allow for the same implementation as for String.

Solution sketches

An implementation is available here: https://github.com/rust-lang/rust/pull/99969 The same FromIterator implementations as for String are added for Box<str>. The implementations are straightforward, using String's FromIterator implementation and then calling into_boxed_str() to remove the excess capacity, analogous to impl<I> FromIterator<I> for Box<[I]>.

One other possibility is to extend the FromIterator implementations to Box<str, A> for all A: Allocator. But this is not currently done for Box<[T], A> or Vec<T, A>, so I opted to do the same and only add implementations for Box<str>.

Links and related work

rust-lang PR: https://github.com/rust-lang/rust/pull/99969

What happens now?

This issue is part of the libs-api team API change proposal process. Once this issue is filed the libs-api team will review open proposals in its weekly meeting. You should receive feedback within a week or two.