mRFC: iterable Box<[T]>

Specifically, add this to std:

impl<T> IntoIterator for Box<[T]> {
    type Item = T;
    type IntoIter = IntoIter<T>;
    fn into_iter(&self) -> IntoIter<T>;
}

impl<'a, T> IntoIterator for &'a Box<[T]> {
    type Item = &'a T;
    type IntoIter = slice::Iter<'a, T>;

    fn into_iter(self) -> slice::Iter<'a, T>;
}

impl<'a, T> IntoIterator for &'a mut Box<[T]> {
    type Item = &'a mut T;
    type IntoIter = slice::IterMut<'a, T>;

    fn into_iter(self) -> slice::IterMut<'a, T>;
}

impl<T> Box<[T]> {
    pub fn iter(&self) -> slice::Iter<'_, T>;
    pub fn iter_mut(&mut self) -> slice::IterMut<'_, T>;
}

pub struct IntoIter<T> { .. }

impl<T> IntoIter<T> {
    pub fn as_slice(&self) -> &[T];
    pub fn as_slice_mut(&mut self) -> &mut [T];
}

impl<T>
  Clone,
  Debug,
  DoubleEndedIterator,
  Drop,
  ExactSizeIterator,
  FusedIterator,
  Iterator,
  Send,
  Sync,
  TrustedLen
for IntoIter<T>;

Are there any problems with this (or missing API), or should I draft a PR? It seems only right that Box<[T]> should gain the "owned slice" powers of Vec<T> that don't require resizing. I was trying to rewrite a function taking Box<[T]> to work with both Vec and Box and noticed that Box<[T]> doesn't have any of the iterators.

Perhaps the IntoIterator for &Box<[T]> could be generalized further to IntoIterator for Box<I> where for<'a> &'a I: IntoIterator.

2 Likes

We could just reuse std::vec::IntoIter right? They both would basically do the same thing, so reusing it would be better.

2 Likes

I assumed that it wouldn't be reusable, but actually, thinking about it, you're right. We can use vec::IntoIter and just tell it we're a Vec with capacity == len. (Because the on-heap representation of the two is identical.)

So the added API surface would be:

impl<T> IntoIterator for Box<[T]> {
    type Item = T;
    type IntoIter = vec::IntoIter<T>;
    fn into_iter(self) -> Self::IntoIter {
        Vec::from(self).into_iter()
    }
}

impl<'a, I> IntoIterator for &'a Box<I>
where
    &'a I: IntoIterator,
{
    type Item = <&I>::Item;
    type IntoIter = <&I>::IntoIter;
    fn into_iter(self) -> {
        (&**self).into_iter()
    }
}

impl<'a, I> IntoIterator for &'a mut Box<I>
where
    &'a mut I: IntoIterator
{
    type Item = <&mut I>::Item;
    type IntoIter = <&mut I>::IntoIter;
    fn into_iter(self) -> Self::IntoIter {
        (&mut **self).into_iter()
    }
}

Box<[T]>::iter and Box<[T]>::iter_mut aren't needed because for inherent methods you can just deref to slice like normal.

The "RefIntoIter" latter two implementations can be debated the utility of, but the first one at least seems nonproblematic.

3 Likes

I don't think that this requires a RFC, you could just send a PR with the relavant changes.

I just wanted to get a pair of eyes on it before posting the PR. Thus the "mRFC"/"mini RFC".

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

3 Likes

Oh, right, IntoIterator for Box<[T]> conflicts with IntoIterator for I where I: Iterator> (and Iterator for Box<impl Iterator + ?Sized> ).

Also, Box is #[fundamental] and I don't know how that factors into things either.

:disappointed: Looks like these impls will have to wait.

Damn :slightly_frowning_face: And what about a an associated .into_iter() function on Box<[T]> ? This at least could allow someone to use Box::into_iter(my_boxed_slice) on generic functions expecting a impl IntoIterator, and in non-generic context could also be quite useful.

Agreed: given that semantically a Vec<T> is

struct Vec<T> {
    raw_buffer: Box<[MaybeUninit<T>]>, // ptr, cap
    initialized_count: usize, // len
}

factoring the iteration logic between Box<[T]> and Vec<T> looks like the right thing to do.

Users can already just convert the boxed slice into a Vec, and doing so is O(1) as we've already noted.

1 Like

But reusing Vec iteration logic is an implementation detail that should not be imposed onto the users.

1 Like

I don't think that's substantially more of an "implementation detail" than <[T]>::Owned being Vec<T>. I think Vec::from(the_box).into_iter() is acceptable.