diff --git a/src/libcore/array.rs b/src/libcore/array.rs index 3d24f8902bd83..364fe105791b6 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -24,7 +24,10 @@ use cmp::Ordering; use convert::TryFrom; use fmt; use hash::{Hash, self}; -use marker::Unsize; +use iter::{FusedIterator, TrustedLen}; +use marker::{PhantomData, Unsize}; +use mem::{ManuallyDrop, self}; +use ptr; use slice::{Iter, IterMut}; /// Utility trait implemented only on arrays of fixed size @@ -52,6 +55,7 @@ unsafe impl> FixedSizeArray for A { fn as_slice(&self) -> &[T] { self } + #[inline] fn as_mut_slice(&mut self) -> &mut [T] { self @@ -210,6 +214,21 @@ macro_rules! array_impls { } } + #[unstable(feature = "array_into_iter", issue = "0")] + impl IntoIterator for [T; $N] { + type Item = T; + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + Self::IntoIter { + array: ManuallyDrop::new(self), + index: 0, + index_back: $N, + _marker: PhantomData, + } + } + } + // NOTE: some less important impls are omitted to reduce code bloat __impl_slice_eq1! { [A; $N], [B; $N] } __impl_slice_eq2! { [A; $N], [B] } @@ -285,3 +304,171 @@ macro_rules! array_impl_default { } array_impl_default!{32, T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T} + + +/// An iterator that moves out of an array. +/// +/// This `struct` is created by the `into_iter` method on [arrays] +/// (provided by the [`IntoIterator`] trait). +/// +/// [arrays]: ../../std/primitive.array.html +/// [`IntoIterator`]: ../../std/iter/trait.IntoIterator.html +#[unstable(feature = "array_into_iter", issue = "0")] +pub struct IntoIter> { + // Invariants: index <= index_back <= array.len() + // Only values in array[index..index_back] are alive at any given time. + // Values from array[..index] and array[index_back..] are already moved/dropped. + array: ManuallyDrop, + index: usize, + index_back: usize, + _marker: PhantomData, +} + +impl> IntoIter { + /// Returns the remaining items of this iterator as a slice. + /// + /// # Examples + /// + /// ``` + /// #![feature(array_into_iter)] + /// + /// # fn main() { + /// let array = ['a', 'b', 'c']; + /// let mut into_iter = array.into_iter(); + /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); + /// let _ = into_iter.next().unwrap(); + /// assert_eq!(into_iter.as_slice(), &['b', 'c']); + /// # } + /// ``` + #[inline] + #[unstable(feature = "array_into_iter", issue = "0")] + pub fn as_slice(&self) -> &[T] { + &self.array.as_slice()[self.index..self.index_back] + } + + /// Returns the remaining items of this iterator as a mutable slice. + /// + /// # Examples + /// + /// ``` + /// #![feature(array_into_iter)] + /// + /// # fn main() { + /// let array = ['a', 'b', 'c']; + /// let mut into_iter = array.into_iter(); + /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); + /// into_iter.as_mut_slice()[2] = 'z'; + /// assert_eq!(into_iter.next().unwrap(), 'a'); + /// assert_eq!(into_iter.next().unwrap(), 'b'); + /// assert_eq!(into_iter.next().unwrap(), 'z'); + /// # } + /// ``` + #[inline] + #[unstable(feature = "array_into_iter", issue = "0")] + pub fn as_mut_slice(&mut self) -> &mut [T] { + &mut self.array.as_mut_slice()[self.index..self.index_back] + } +} + +#[unstable(feature = "array_into_iter", issue = "0")] +impl> Drop for IntoIter { + #[inline] + fn drop(&mut self) { + // Drop values that are still alive. + for p in self.as_mut_slice() { + unsafe { ptr::drop_in_place(p); } + } + } +} + +#[unstable(feature = "array_into_iter", issue = "0")] +impl> Clone for IntoIter { + fn clone(&self) -> Self { + unsafe { + let mut iter = Self { + array: ManuallyDrop::new(mem::uninitialized()), + index: 0, + index_back: 0, + _marker: PhantomData, + }; + + // Clone values that are still alive. + for (dst, src) in iter.array.as_mut_slice().iter_mut().zip(self.as_slice()) { + ptr::write(dst, src.clone()); + iter.index_back += 1; + } + + iter + } + } +} + +#[unstable(feature = "array_into_iter", issue = "0")] +impl> fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("IntoIter") + .field(&self.as_slice()) + .finish() + } +} + +#[unstable(feature = "array_into_iter", issue = "0")] +impl> Iterator for IntoIter { + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + if self.index < self.index_back { + let p = &self.array.as_slice()[self.index]; + self.index += 1; + unsafe { Some(ptr::read(p)) } + } else { + None + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let len = self.len(); + (len, Some(len)) + } + + #[inline] + fn count(self) -> usize { + self.len() + } +} + +#[unstable(feature = "array_into_iter", issue = "0")] +impl> DoubleEndedIterator for IntoIter { + #[inline] + fn next_back(&mut self) -> Option { + if self.index < self.index_back { + self.index_back -= 1; + let p = &self.array.as_slice()[self.index_back]; + unsafe { Some(ptr::read(p)) } + } else { + None + } + } +} + +#[unstable(feature = "array_into_iter", issue = "0")] +impl> ExactSizeIterator for IntoIter { + #[inline] + fn len(&self) -> usize { + self.index_back - self.index + } + + #[inline] + fn is_empty(&self) -> bool { + self.index_back == self.index + } +} + +#[unstable(feature = "array_into_iter", issue = "0")] +impl> FusedIterator for IntoIter {} + +// #[unstable(feature = "trusted_len", issue = "37572")] +#[unstable(feature = "array_into_iter", issue = "0")] +unsafe impl> TrustedLen for IntoIter {} diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 2cfbc09229342..6646eb873db0e 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -285,7 +285,7 @@ pub trait Iterator { /// ``` /// #![feature(iterator_step_by)] /// let a = [0, 1, 2, 3, 4, 5]; - /// let mut iter = a.into_iter().step_by(2); + /// let mut iter = a.iter().step_by(2); /// /// assert_eq!(iter.next(), Some(&0)); /// assert_eq!(iter.next(), Some(&2)); @@ -461,7 +461,7 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// let mut iter = a.into_iter().map(|x| 2 * x); + /// let mut iter = a.iter().map(|x| 2 * x); /// /// assert_eq!(iter.next(), Some(2)); /// assert_eq!(iter.next(), Some(4)); @@ -550,7 +550,7 @@ pub trait Iterator { /// ``` /// let a = [0i32, 1, 2]; /// - /// let mut iter = a.into_iter().filter(|x| x.is_positive()); + /// let mut iter = a.iter().filter(|x| x.is_positive()); /// /// assert_eq!(iter.next(), Some(&1)); /// assert_eq!(iter.next(), Some(&2)); @@ -564,7 +564,7 @@ pub trait Iterator { /// ``` /// let a = [0, 1, 2]; /// - /// let mut iter = a.into_iter().filter(|x| **x > 1); // need two *s! + /// let mut iter = a.iter().filter(|x| **x > 1); // need two *s! /// /// assert_eq!(iter.next(), Some(&2)); /// assert_eq!(iter.next(), None); @@ -576,7 +576,7 @@ pub trait Iterator { /// ``` /// let a = [0, 1, 2]; /// - /// let mut iter = a.into_iter().filter(|&x| *x > 1); // both & and * + /// let mut iter = a.iter().filter(|&x| *x > 1); // both & and * /// /// assert_eq!(iter.next(), Some(&2)); /// assert_eq!(iter.next(), None); @@ -587,7 +587,7 @@ pub trait Iterator { /// ``` /// let a = [0, 1, 2]; /// - /// let mut iter = a.into_iter().filter(|&&x| x > 1); // two &s + /// let mut iter = a.iter().filter(|&&x| x > 1); // two &s /// /// assert_eq!(iter.next(), Some(&2)); /// assert_eq!(iter.next(), None); @@ -767,7 +767,7 @@ pub trait Iterator { /// ``` /// let a = [-1i32, 0, 1]; /// - /// let mut iter = a.into_iter().skip_while(|x| x.is_negative()); + /// let mut iter = a.iter().skip_while(|x| x.is_negative()); /// /// assert_eq!(iter.next(), Some(&0)); /// assert_eq!(iter.next(), Some(&1)); @@ -781,7 +781,7 @@ pub trait Iterator { /// ``` /// let a = [-1, 0, 1]; /// - /// let mut iter = a.into_iter().skip_while(|x| **x < 0); // need two *s! + /// let mut iter = a.iter().skip_while(|x| **x < 0); // need two *s! /// /// assert_eq!(iter.next(), Some(&0)); /// assert_eq!(iter.next(), Some(&1)); @@ -793,7 +793,7 @@ pub trait Iterator { /// ``` /// let a = [-1, 0, 1, -2]; /// - /// let mut iter = a.into_iter().skip_while(|x| **x < 0); + /// let mut iter = a.iter().skip_while(|x| **x < 0); /// /// assert_eq!(iter.next(), Some(&0)); /// assert_eq!(iter.next(), Some(&1)); @@ -828,7 +828,7 @@ pub trait Iterator { /// ``` /// let a = [-1i32, 0, 1]; /// - /// let mut iter = a.into_iter().take_while(|x| x.is_negative()); + /// let mut iter = a.iter().take_while(|x| x.is_negative()); /// /// assert_eq!(iter.next(), Some(&-1)); /// assert_eq!(iter.next(), None); @@ -841,7 +841,7 @@ pub trait Iterator { /// ``` /// let a = [-1, 0, 1]; /// - /// let mut iter = a.into_iter().take_while(|x| **x < 0); // need two *s! + /// let mut iter = a.iter().take_while(|x| **x < 0); // need two *s! /// /// assert_eq!(iter.next(), Some(&-1)); /// assert_eq!(iter.next(), None); @@ -852,7 +852,7 @@ pub trait Iterator { /// ``` /// let a = [-1, 0, 1, -2]; /// - /// let mut iter = a.into_iter().take_while(|x| **x < 0); + /// let mut iter = a.iter().take_while(|x| **x < 0); /// /// assert_eq!(iter.next(), Some(&-1)); /// @@ -867,7 +867,7 @@ pub trait Iterator { /// /// ``` /// let a = [1, 2, 3, 4]; - /// let mut iter = a.into_iter(); + /// let mut iter = a.iter(); /// /// let result: Vec = iter.by_ref() /// .take_while(|n| **n != 3) @@ -1229,7 +1229,7 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// let iter = a.into_iter(); + /// let iter = a.iter(); /// /// let sum: i32 = iter.take(5).fold(0, |acc, i| acc + i ); /// @@ -1242,7 +1242,7 @@ pub trait Iterator { /// // let's try that again /// let a = [1, 2, 3]; /// - /// let mut iter = a.into_iter(); + /// let mut iter = a.iter(); /// /// // instead, we add in a .by_ref() /// let sum: i32 = iter.by_ref().take(2).fold(0, |acc, i| acc + i ); @@ -1386,7 +1386,7 @@ pub trait Iterator { /// let a = [1, 2, 3]; /// /// let (even, odd): (Vec, Vec) = a - /// .into_iter() + /// .iter() /// .partition(|&n| n % 2 == 0); /// /// assert_eq!(even, vec![2]); diff --git a/src/libcore/tests/array.rs b/src/libcore/tests/array.rs index 6278d5e23e0d6..264fb4235ebff 100644 --- a/src/libcore/tests/array.rs +++ b/src/libcore/tests/array.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::array::FixedSizeArray; +use core::array::{FixedSizeArray, IntoIter}; use core::convert::TryFrom; #[test] @@ -49,3 +49,160 @@ fn array_try_from() { 30 31 32 } } + +#[test] +fn test_into_iter_as_slice() { + let array = ['a', 'b', 'c']; + let mut into_iter = array.into_iter(); + assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); + let _ = into_iter.next().unwrap(); + assert_eq!(into_iter.as_slice(), &['b', 'c']); + let _ = into_iter.next().unwrap(); + let _ = into_iter.next().unwrap(); + assert_eq!(into_iter.as_slice(), &[]); +} + +#[test] +fn test_into_iter_as_mut_slice() { + let array = ['a', 'b', 'c']; + let mut into_iter = array.into_iter(); + assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); + into_iter.as_mut_slice()[0] = 'x'; + into_iter.as_mut_slice()[1] = 'y'; + assert_eq!(into_iter.next().unwrap(), 'x'); + assert_eq!(into_iter.as_slice(), &['y', 'c']); +} + +#[test] +fn test_into_iter_debug() { + let array = ['a', 'b', 'c']; + let into_iter = array.into_iter(); + let debug = format!("{:?}", into_iter); + assert_eq!(debug, "IntoIter(['a', 'b', 'c'])"); +} + +#[test] +fn test_into_iter_clone() { + fn iter_equal>(it: I, slice: &[i32]) { + let v: Vec = it.collect(); + assert_eq!(&v[..], slice); + } + let mut it = [1, 2, 3].into_iter(); + iter_equal(it.clone(), &[1, 2, 3]); + assert_eq!(it.next(), Some(1)); + let mut it = it.rev(); + iter_equal(it.clone(), &[3, 2]); + assert_eq!(it.next(), Some(3)); + iter_equal(it.clone(), &[2]); + assert_eq!(it.next(), Some(2)); + iter_equal(it.clone(), &[]); + assert_eq!(it.next(), None); +} + +#[test] +fn test_into_iter_nth() { + let v = [0, 1, 2, 3, 4]; + for i in 0..v.len() { + assert_eq!(v.clone().into_iter().nth(i).unwrap(), v[i]); + } + assert_eq!(v.clone().into_iter().nth(v.len()), None); + + let mut iter = v.into_iter(); + assert_eq!(iter.nth(2).unwrap(), v[2]); + assert_eq!(iter.nth(1).unwrap(), v[4]); +} + +#[test] +fn test_into_iter_last() { + let v = [0, 1, 2, 3, 4]; + assert_eq!(v.into_iter().last().unwrap(), 4); + assert_eq!([0].into_iter().last().unwrap(), 0); +} + +#[test] +fn test_into_iter_count() { + let v = [0, 1, 2, 3, 4]; + assert_eq!(v.clone().into_iter().count(), 5); + + let mut iter2 = v.into_iter(); + iter2.next(); + iter2.next(); + assert_eq!(iter2.count(), 3); +} + +#[test] +fn test_into_iter_flat_map() { + assert!((0..5).flat_map(|i| [2 * i, 2 * i + 1]).eq(0..10)); +} + +#[test] +fn test_into_iter_drops() { + use core::cell::Cell; + + struct R<'a> { + i: &'a Cell, + } + + impl<'a> Drop for R<'a> { + fn drop(&mut self) { + self.i.set(self.i.get() + 1); + } + } + + fn r(i: &Cell) -> R { + R { + i: i + } + } + + fn v(i: &Cell) -> [R; 5] { + [r(i), r(i), r(i), r(i), r(i)] + } + + let i = Cell::new(0); + { + v(&i).into_iter(); + } + assert_eq!(i.get(), 5); + + let i = Cell::new(0); + { + let mut iter = v(&i).into_iter(); + let _x = iter.next(); + assert_eq!(i.get(), 0); + assert_eq!(iter.count(), 4); + assert_eq!(i.get(), 4); + } + assert_eq!(i.get(), 5); + + let i = Cell::new(0); + { + let mut iter = v(&i).into_iter(); + let _x = iter.nth(2); + assert_eq!(i.get(), 2); + let _y = iter.last(); + assert_eq!(i.get(), 3); + } + assert_eq!(i.get(), 5); + + let i = Cell::new(0); + for (index, _x) in v(&i).into_iter().enumerate() { + assert_eq!(i.get(), index); + } + assert_eq!(i.get(), 5); + + let i = Cell::new(0); + for (index, _x) in v(&i).into_iter().rev().enumerate() { + assert_eq!(i.get(), index); + } + assert_eq!(i.get(), 5); +} + +#[allow(dead_code)] +fn assert_covariance() { + fn into_iter<'new>( + i: IntoIter<&'static str, [&'static str; 10]>, + ) -> IntoIter<&'new str, [&'new str; 10]> { + i + } +} diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 5bd5bca19c4e5..81acd94181147 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -10,6 +10,7 @@ #![deny(warnings)] +#![feature(array_into_iter)] #![feature(ascii_ctype)] #![feature(box_syntax)] #![feature(core_float)] diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 678e1762a5519..059982ea863b5 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -459,7 +459,7 @@ fn init_ids() -> FxHashMap { "methods", "deref-methods", "implementations", - ].into_iter().map(|id| (String::from(*id), 1)).collect() + ].into_iter().map(|id| (String::from(id), 1)).collect() } /// This method resets the local table of used ID attributes. This is typically diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 358aa2c37dfb4..dfd163884b985 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -413,7 +413,7 @@ mod prim_pointer { } /// the element type allows it: /// /// - [`Debug`][debug] -/// - [`IntoIterator`][intoiterator] (implemented for `&[T; N]` and `&mut [T; N]`) +/// - [`IntoIterator`][intoiterator] (implemented for `[T; N]`, `&[T; N]`, and `&mut [T; N]`) /// - [`PartialEq`][partialeq], [`PartialOrd`][partialord], [`Eq`][eq], [`Ord`][ord] /// - [`Hash`][hash] /// - [`AsRef`][asref], [`AsMut`][asmut] @@ -435,8 +435,8 @@ mod prim_pointer { } /// an array. Indeed, this provides most of the API for working with arrays. /// Slices have a dynamic size and do not coerce to arrays. /// -/// There is no way to move elements out of an array. See [`mem::replace`][replace] -/// for an alternative. +/// There is no way to move individual elements out of an array. See [`mem::replace`][replace] +/// for an alternative, or use [`IntoIterator`][intoiterator] to move the entire array. /// /// # Examples /// @@ -454,16 +454,16 @@ mod prim_pointer { } /// } /// ``` /// -/// An array itself is not iterable: +/// An array itself is iterable by value: /// -/// ```compile_fail,E0277 +/// ``` /// let array: [i32; 3] = [0; 3]; /// /// for x in array { } -/// // error: the trait bound `[i32; 3]: std::iter::Iterator` is not satisfied /// ``` /// -/// The solution is to coerce the array to a slice by calling a slice method: +/// You can also coerce an array to a slice by calling a slice method +/// to iterate by reference: /// /// ``` /// # let array: [i32; 3] = [0; 3];