Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions library/alloc/src/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ mod iter;
/// [`ThinBox`] implementation.
mod thin;

#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")]
pub use iter::BoxedArrayIntoIter;
#[unstable(feature = "thin_box", issue = "92791")]
pub use thin::ThinBox;

Expand Down
158 changes: 155 additions & 3 deletions library/alloc/src/boxed/iter.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
use core::async_iter::AsyncIterator;
use core::iter::FusedIterator;
use core::iter::{FusedIterator, TrustedLen};
use core::num::NonZero;
use core::pin::Pin;
use core::slice;
use core::task::{Context, Poll};

use crate::alloc::Allocator;
use crate::alloc::{Allocator, Global};
#[cfg(not(no_global_oom_handling))]
use crate::borrow::Cow;
use crate::boxed::Box;
#[cfg(not(no_global_oom_handling))]
use crate::string::String;
use crate::vec;
#[cfg(not(no_global_oom_handling))]
use crate::vec::Vec;
use crate::{fmt, vec};

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Iterator + ?Sized, A: Allocator> Iterator for Box<I, A> {
Expand Down Expand Up @@ -192,3 +193,154 @@ impl<'a> FromIterator<Cow<'a, str>> for Box<str> {
String::from_iter(iter).into_boxed_str()
}
}

/// This implementation is required to make sure that the `Box<[I; N]>: IntoIterator`
/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket.
#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")]
impl<I, const N: usize, A: Allocator> !Iterator for Box<[I; N], A> {}

/// This implementation is required to make sure that the `&Box<[I; N]>: IntoIterator`
/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket.
#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")]
impl<'a, const N: usize, I, A: Allocator> !Iterator for &'a Box<[I; N], A> {}

/// This implementation is required to make sure that the `&mut Box<[I; N]>: IntoIterator`
/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket.
#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")]
impl<'a, const N: usize, I, A: Allocator> !Iterator for &'a mut Box<[I; N], A> {}

#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")]
impl<'a, T, const N: usize, A: Allocator> IntoIterator for &'a Box<[T; N], A> {
type IntoIter = slice::Iter<'a, T>;
type Item = &'a T;
fn into_iter(self) -> slice::Iter<'a, T> {
self.iter()
}
}

#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")]
impl<'a, T, const N: usize, A: Allocator> IntoIterator for &'a mut Box<[T; N], A> {
type IntoIter = slice::IterMut<'a, T>;
type Item = &'a mut T;
fn into_iter(self) -> slice::IterMut<'a, T> {
self.iter_mut()
}
}

/// A by-value `Box<[T; N]>` iterator.
#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")]
#[rustc_insignificant_dtor]
pub struct BoxedArrayIntoIter<T, const N: usize, A: Allocator = Global> {
// FIXME: make a more efficient implementation (without the need to store capacity)
inner: vec::IntoIter<T, A>,
}

impl<T, const N: usize, A: Allocator> BoxedArrayIntoIter<T, N, A> {
/// Returns an immutable slice of all elements that have not been yielded
/// yet.
#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")]
pub fn as_slice(&self) -> &[T] {
self.inner.as_slice()
}

/// Returns a mutable slice of all elements that have not been yielded yet.
#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")]
pub fn as_mut_slice(&mut self) -> &mut [T] {
self.inner.as_mut_slice()
}
}

#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")]
impl<T, const N: usize, A: Allocator> Iterator for BoxedArrayIntoIter<T, N, A> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}

fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.len();
(len, Some(len))
}

#[inline]
fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
self.inner.fold(init, fold)
}

fn count(self) -> usize {
self.len()
}

fn last(mut self) -> Option<Self::Item> {
self.next_back()
}

fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
self.inner.advance_by(n)
}
}

#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")]
impl<T, const N: usize, A: Allocator> DoubleEndedIterator for BoxedArrayIntoIter<T, N, A> {
fn next_back(&mut self) -> Option<Self::Item> {
self.inner.next_back()
}

#[inline]
fn rfold<Acc, Fold>(self, init: Acc, rfold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
self.inner.rfold(init, rfold)
}

fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
self.inner.advance_back_by(n)
}
}

#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")]
impl<T, const N: usize, A: Allocator> ExactSizeIterator for BoxedArrayIntoIter<T, N, A> {
fn len(&self) -> usize {
self.inner.len()
}

fn is_empty(&self) -> bool {
self.inner.is_empty()
}
}

#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")]
impl<T, const N: usize, A: Allocator> FusedIterator for BoxedArrayIntoIter<T, N, A> {}

#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")]
unsafe impl<T, const N: usize, A: Allocator> TrustedLen for BoxedArrayIntoIter<T, N, A> {}

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")]
impl<T: Clone, const N: usize, A: Clone + Allocator> Clone for BoxedArrayIntoIter<T, N, A> {
fn clone(&self) -> Self {
Self { inner: self.inner.clone() }
}
}

#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")]
impl<T: fmt::Debug, const N: usize, A: Allocator> fmt::Debug for BoxedArrayIntoIter<T, N, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// Only print the elements that were not yielded yet: we cannot
// access the yielded elements anymore.
f.debug_tuple("IntoIter").field(&self.as_slice()).finish()
}
}

#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")]
impl<T, const N: usize, A: Allocator> IntoIterator for Box<[T; N], A> {
type IntoIter = BoxedArrayIntoIter<T, N, A>;
type Item = T;
fn into_iter(self) -> BoxedArrayIntoIter<T, N, A> {
BoxedArrayIntoIter { inner: (self as Box<[T], A>).into_vec().into_iter() }
}
}
2 changes: 1 addition & 1 deletion library/alloc/src/vec/into_iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ where
#[doc(hidden)]
#[unstable(issue = "none", feature = "std_internals")]
#[rustc_unsafe_specialization_marker]
pub trait NonDrop {}
trait NonDrop {}

// T: Copy as approximation for !Drop since get_unchecked does not advance self.ptr
// and thus we can't implement drop-handling
Expand Down
5 changes: 4 additions & 1 deletion library/core/src/array/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ impl<T, const N: usize> IntoIter<T, N> {
}
}

#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")]
impl<T, const N: usize> !Iterator for [T; N] {}

// Note: the `#[rustc_skip_during_method_dispatch(array)]` on `trait IntoIterator`
// hides this implementation from explicit `.into_iter()` calls on editions < 2021,
// so those calls will still resolve to the slice implementation, by reference.
Expand Down Expand Up @@ -362,7 +365,7 @@ unsafe impl<T, const N: usize> TrustedLen for IntoIter<T, N> {}
#[doc(hidden)]
#[unstable(issue = "none", feature = "std_internals")]
#[rustc_unsafe_specialization_marker]
pub trait NonDrop {}
trait NonDrop {}

// T: Copy as approximation for !Drop since get_unchecked does not advance self.alive
// and thus we can't implement drop-handling
Expand Down
5 changes: 2 additions & 3 deletions tests/ui/iterators/into-iter-on-arrays-2018.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::array::IntoIter;
use std::ops::Deref;
use std::rc::Rc;
use std::slice::Iter;
use std::boxed::BoxedArrayIntoIter;

fn main() {
let array = [0; 10];
Expand All @@ -15,9 +16,7 @@ fn main() {
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning

let _: Iter<'_, i32> = Box::new(array).into_iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning
let _: BoxedArrayIntoIter<i32, 10> = Box::new(array).into_iter();

let _: Iter<'_, i32> = Rc::new(array).into_iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
Expand Down
19 changes: 5 additions & 14 deletions tests/ui/iterators/into-iter-on-arrays-2018.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
--> $DIR/into-iter-on-arrays-2018.rs:14:34
--> $DIR/into-iter-on-arrays-2018.rs:15:34
|
LL | let _: Iter<'_, i32> = array.into_iter();
| ^^^^^^^^^
Expand All @@ -19,16 +19,7 @@ LL + let _: Iter<'_, i32> = IntoIterator::into_iter(array);
|

warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
--> $DIR/into-iter-on-arrays-2018.rs:18:44
|
LL | let _: Iter<'_, i32> = Box::new(array).into_iter();
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
= warning: this changes meaning in Rust 2021
= note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html>

warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
--> $DIR/into-iter-on-arrays-2018.rs:22:43
--> $DIR/into-iter-on-arrays-2018.rs:21:43
|
LL | let _: Iter<'_, i32> = Rc::new(array).into_iter();
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
Expand All @@ -37,7 +28,7 @@ LL | let _: Iter<'_, i32> = Rc::new(array).into_iter();
= note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html>

warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
--> $DIR/into-iter-on-arrays-2018.rs:25:41
--> $DIR/into-iter-on-arrays-2018.rs:24:41
|
LL | let _: Iter<'_, i32> = Array(array).into_iter();
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
Expand All @@ -46,7 +37,7 @@ LL | let _: Iter<'_, i32> = Array(array).into_iter();
= note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html>

warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
--> $DIR/into-iter-on-arrays-2018.rs:32:24
--> $DIR/into-iter-on-arrays-2018.rs:31:24
|
LL | for _ in [1, 2, 3].into_iter() {}
| ^^^^^^^^^
Expand All @@ -64,5 +55,5 @@ LL - for _ in [1, 2, 3].into_iter() {}
LL + for _ in [1, 2, 3] {}
|

warning: 5 warnings emitted
warning: 4 warnings emitted

3 changes: 2 additions & 1 deletion tests/ui/iterators/into-iter-on-arrays-2021.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
use std::array::IntoIter;
use std::ops::Deref;
use std::rc::Rc;
use std::boxed::BoxedArrayIntoIter;

fn main() {
let array = [0; 10];

// In 2021, the method dispatches to `IntoIterator for [T; N]`.
let _: IntoIter<i32, 10> = array.into_iter();
let _: IntoIter<i32, 10> = Box::new(array).into_iter();
let _: BoxedArrayIntoIter<i32, 10> = Box::new(array).into_iter();

// The `array_into_iter` lint doesn't cover other wrappers that deref to an array.
let _: IntoIter<i32, 10> = Rc::new(array).into_iter();
Expand Down
32 changes: 8 additions & 24 deletions tests/ui/iterators/into-iter-on-arrays-lint.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -22,31 +22,15 @@ fn main() {
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning

Box::new(small).iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning
Box::new([1, 2]).iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning
Box::new(big).iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning
Box::new([0u8; 33]).iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning
Box::new(small).into_iter();
Box::new([1, 2]).into_iter();
Box::new(big).into_iter();
Box::new([0u8; 33]).into_iter();

Box::new(Box::new(small)).iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning
Box::new(Box::new([1, 2])).iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning
Box::new(Box::new(big)).iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning
Box::new(Box::new([0u8; 33])).iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning
Box::new(Box::new(small)).into_iter();
Box::new(Box::new([1, 2])).into_iter();
Box::new(Box::new(big)).into_iter();
Box::new(Box::new([0u8; 33])).into_iter();

// Expressions that should not
(&[1, 2]).into_iter();
Expand Down
16 changes: 0 additions & 16 deletions tests/ui/iterators/into-iter-on-arrays-lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,30 +23,14 @@ fn main() {
//~| WARNING this changes meaning

Box::new(small).into_iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning
Box::new([1, 2]).into_iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning
Box::new(big).into_iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning
Box::new([0u8; 33]).into_iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning

Box::new(Box::new(small)).into_iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning
Box::new(Box::new([1, 2])).into_iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning
Box::new(Box::new(big)).into_iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning
Box::new(Box::new([0u8; 33])).into_iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning

// Expressions that should not
(&[1, 2]).into_iter();
Expand Down
Loading
Loading