Skip to content

Commit bb9ca9f

Browse files
Add the impls for Box<[T]>: IntoIterator
Co-authored-by: ltdk <[email protected]>
1 parent b5522b6 commit bb9ca9f

File tree

2 files changed

+86
-0
lines changed

2 files changed

+86
-0
lines changed

library/alloc/src/boxed.rs

+83
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,45 @@
135135
//! is not allowed. For more guidance on working with box from unsafe code, see
136136
//! [rust-lang/unsafe-code-guidelines#326][ucg#326].
137137
//!
138+
//! # Editions
139+
//!
140+
//! A special case exists for the implementation of `IntoIterator` for arrays on the Rust 2021
141+
//! edition, as documented [here][array]. Unfortunately, it was later found that a similar
142+
//! workaround should be added for boxed slices, and this was applied in the 2024 edition.
143+
//!
144+
//! Specifically, `IntoIterator` is implemented for `Box<[T]>` on all editions, but specific calls
145+
//! to `into_iter()` for boxed slices will defer to the slice implementation on editions before
146+
//! 2024:
147+
//!
148+
#![cfg_attr(bootstrap, doc = "```rust,edition2021,ignore")]
149+
#![cfg_attr(not(bootstrap), doc = "```rust,edition2021")]
150+
//! // Rust 2015, 2018, and 2021:
151+
//!
152+
//! # #![allow(boxed_slice_into_iter)] // override our `deny(warnings)`
153+
//! let boxed_slice: Box<[i32]> = vec![0; 3].into_boxed_slice();
154+
//!
155+
//! // This creates a slice iterator, producing references to each value.
156+
//! for item in boxed_slice.into_iter().enumerate() {
157+
//! let (i, x): (usize, &i32) = item;
158+
//! println!("boxed_slice[{i}] = {x}");
159+
//! }
160+
//!
161+
//! // The `boxed_slice_into_iter` lint suggests this change for future compatibility:
162+
//! for item in boxed_slice.iter().enumerate() {
163+
//! let (i, x): (usize, &i32) = item;
164+
//! println!("boxed_slice[{i}] = {x}");
165+
//! }
166+
//!
167+
//! // You can explicitly iterate a boxed slice by value using `IntoIterator::into_iter`
168+
//! for item in IntoIterator::into_iter(boxed_slice).enumerate() {
169+
//! let (i, x): (usize, i32) = item;
170+
//! println!("boxed_slice[{i}] = {x}");
171+
//! }
172+
//! ```
173+
//!
174+
//! Similar to the array implementation, this may be modified in the future to remove this override,
175+
//! and it's best to avoid relying on this edition-dependent behavior if you wish to preserve
176+
//! compatibility with future versions of the compiler.
138177
//!
139178
//! [ucg#198]: https://github.com/rust-lang/unsafe-code-guidelines/issues/198
140179
//! [ucg#326]: https://github.com/rust-lang/unsafe-code-guidelines/issues/326
@@ -165,6 +204,7 @@ use core::ops::{
165204
};
166205
use core::pin::Pin;
167206
use core::ptr::{self, addr_of_mut, NonNull, Unique};
207+
use core::slice;
168208
use core::task::{Context, Poll};
169209

170210
#[cfg(not(no_global_oom_handling))]
@@ -177,6 +217,7 @@ use crate::raw_vec::RawVec;
177217
use crate::str::from_boxed_utf8_unchecked;
178218
#[cfg(not(no_global_oom_handling))]
179219
use crate::string::String;
220+
use crate::vec;
180221
#[cfg(not(no_global_oom_handling))]
181222
use crate::vec::Vec;
182223

@@ -2080,6 +2121,48 @@ impl<I> FromIterator<I> for Box<[I]> {
20802121
}
20812122
}
20822123

2124+
/// `Box` is fundamental, so coherence needs help understanding these impls are okay.
2125+
#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
2126+
impl<I, A: Allocator> !Iterator for Box<[I], A> {}
2127+
2128+
/// `Box` is fundamental, so coherence needs help understanding these impls are okay.
2129+
#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
2130+
impl<'a, I, A: Allocator> !Iterator for &'a Box<[I], A> {}
2131+
2132+
/// `Box` is fundamental, so coherence needs help understanding these impls are okay.
2133+
#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
2134+
impl<'a, I, A: Allocator> !Iterator for &'a mut Box<[I], A> {}
2135+
2136+
// Note: the `#[rustc_skip_during_method_dispatch(boxed_slice)]` on `trait IntoIterator`
2137+
// hides this implementation from explicit `.into_iter()` calls on editions < 2024,
2138+
// so those calls will still resolve to the slice implementation, by reference.
2139+
#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
2140+
impl<I, A: Allocator> IntoIterator for Box<[I], A> {
2141+
type IntoIter = vec::IntoIter<I, A>;
2142+
type Item = I;
2143+
fn into_iter(self) -> vec::IntoIter<I, A> {
2144+
self.into_vec().into_iter()
2145+
}
2146+
}
2147+
2148+
#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
2149+
impl<'a, I, A: Allocator> IntoIterator for &'a Box<[I], A> {
2150+
type IntoIter = slice::Iter<'a, I>;
2151+
type Item = &'a I;
2152+
fn into_iter(self) -> slice::Iter<'a, I> {
2153+
self.iter()
2154+
}
2155+
}
2156+
2157+
#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
2158+
impl<'a, I, A: Allocator> IntoIterator for &'a mut Box<[I], A> {
2159+
type IntoIter = slice::IterMut<'a, I>;
2160+
type Item = &'a mut I;
2161+
fn into_iter(self) -> slice::IterMut<'a, I> {
2162+
self.iter_mut()
2163+
}
2164+
}
2165+
20832166
#[cfg(not(no_global_oom_handling))]
20842167
#[stable(feature = "box_slice_clone", since = "1.3.0")]
20852168
impl<T: Clone, A: Allocator + Clone> Clone for Box<[T], A> {

library/core/src/slice/iter.rs

+3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ use crate::ptr::{self, without_provenance, without_provenance_mut, NonNull};
1616

1717
use super::{from_raw_parts, from_raw_parts_mut};
1818

19+
#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
20+
impl<T> !Iterator for [T] {}
21+
1922
#[stable(feature = "rust1", since = "1.0.0")]
2023
impl<'a, T> IntoIterator for &'a [T] {
2124
type Item = &'a T;

0 commit comments

Comments
 (0)