Skip to content

Commit

Permalink
rollup merge of rust-lang#20790: japaric/for-loops
Browse files Browse the repository at this point in the history
As per [RFC rust-lang#235][rfc], you can now do:

[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0235-collections-conventions.md#intoiterator-and-iterable

``` rust
let mut v = vec![1];

// iterate over immutable references
for x in &v {
    assert_eq!(x, &1);
}

// iterate over mutable references
for x in &mut v {
    assert_eq!(x, &mut 1);
}

// iterate over values, this consumes `v`
for x in v {
    assert_eq!(x, 1);
}
```

[breaking-change]s

For loops now "consume" (move) the iterator, this breaks iterating over mutable references to iterators, and also breaks multiple iterations over the same iterator:

``` rust
fn foo(mut it: &mut Iter) {  // `Iter` implements `Iterator`
    for x in it { .. }  //~ error: `&mut Iter` doesn't implement Iterator
}

fn bar() {
    for x in it { .. }  //~ note: `it` moved here
    for x in it { .. }  //~ error: `it` has been moved
}
```

Both cases can be fixed using the `by_ref()` adapter to create an iterator from the mutable reference:

``` rust
fn foo(mut it: &mut Iter) {
    for x in it.by_ref() { .. }
}

fn bar() {
    for x in it.by_ref() { .. }
    for x in it { .. }
}
```

This PR also makes iterator non-implicitly copyable, as this was source of subtle bugs in the libraries. You can still use `clone()` to explictly copy the iterator.

Finally, since the for loops are implemented in the frontend and use global paths to `IntoIterator`, `Iterator` and `Option` variants, users of the `core` crate will have to use add an `std` module to the root of their crate to be able to use for loops:

``` rust
#![no_std]

extern crate core;

fn main() {
    for x in 0..10 {}
}

#[doc(hidden)]
mod std {
    // these imports are needed to use for-loops
    pub use core::iter;
    pub use core::option;
}
```

---

r? @nikomatsakis @aturon
cc rust-lang#18424
closes rust-lang#18045
  • Loading branch information
alexcrichton committed Jan 30, 2015
2 parents 1a51eb9 + b9a9030 commit 341e858
Show file tree
Hide file tree
Showing 70 changed files with 588 additions and 599 deletions.
4 changes: 4 additions & 0 deletions src/doc/trpl/unsafe.md
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,10 @@ extern fn panic_fmt(args: &core::fmt::Arguments,
#[lang = "eh_personality"] extern fn eh_personality() {}
# #[start] fn start(argc: isize, argv: *const *const u8) -> isize { 0 }
# fn main() {}
# mod std { // for-loops
# pub use core::iter;
# pub use core::option;
# }
```

Note that there is one extra lang item here which differs from the examples
Expand Down
18 changes: 17 additions & 1 deletion src/libcollections/binary_heap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@
use core::prelude::*;

use core::default::Default;
use core::iter::FromIterator;
use core::iter::{FromIterator, IntoIterator};
use core::mem::{zeroed, replace, swap};
use core::ptr;

Expand Down Expand Up @@ -655,6 +655,22 @@ impl<T: Ord> FromIterator<T> for BinaryHeap<T> {
}
}

impl<T: Ord> IntoIterator for BinaryHeap<T> {
type Iter = IntoIter<T>;

fn into_iter(self) -> IntoIter<T> {
self.into_iter()
}
}

impl<'a, T> IntoIterator for &'a BinaryHeap<T> where T: Ord {
type Iter = Iter<'a, T>;

fn into_iter(self) -> Iter<'a, T> {
self.iter()
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Ord> Extend<T> for BinaryHeap<T> {
fn extend<Iter: Iterator<Item=T>>(&mut self, mut iter: Iter) {
Expand Down
17 changes: 16 additions & 1 deletion src/libcollections/bit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ use core::fmt;
use core::hash;
use core::iter::RandomAccessIterator;
use core::iter::{Chain, Enumerate, Repeat, Skip, Take, repeat, Cloned};
use core::iter::{self, FromIterator};
use core::iter::{self, FromIterator, IntoIterator};
use core::num::Int;
use core::ops::Index;
use core::slice;
Expand Down Expand Up @@ -1070,6 +1070,14 @@ impl<'a> RandomAccessIterator for Iter<'a> {
}
}

impl<'a> IntoIterator for &'a Bitv {
type Iter = Iter<'a>;

fn into_iter(self) -> Iter<'a> {
self.iter()
}
}

/// An implementation of a set using a bit vector as an underlying
/// representation for holding unsigned numerical elements.
///
Expand Down Expand Up @@ -1873,6 +1881,13 @@ impl<'a> Iterator for SymmetricDifference<'a> {
#[inline] fn size_hint(&self) -> (uint, Option<uint>) { self.0.size_hint() }
}

impl<'a> IntoIterator for &'a BitvSet {
type Iter = SetIter<'a>;

fn into_iter(self) -> SetIter<'a> {
self.iter()
}
}

#[cfg(test)]
mod tests {
Expand Down
26 changes: 25 additions & 1 deletion src/libcollections/btree/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use core::cmp::Ordering;
use core::default::Default;
use core::fmt::Debug;
use core::hash::{Hash, Hasher};
use core::iter::{Map, FromIterator};
use core::iter::{Map, FromIterator, IntoIterator};
use core::ops::{Index, IndexMut};
use core::{iter, fmt, mem};
use Bound::{self, Included, Excluded, Unbounded};
Expand Down Expand Up @@ -478,6 +478,30 @@ impl<K: Ord, V> BTreeMap<K, V> {
}
}

impl<K, V> IntoIterator for BTreeMap<K, V> {
type Iter = IntoIter<K, V>;

fn into_iter(self) -> IntoIter<K, V> {
self.into_iter()
}
}

impl<'a, K, V> IntoIterator for &'a BTreeMap<K, V> {
type Iter = Iter<'a, K, V>;

fn into_iter(self) -> Iter<'a, K, V> {
self.iter()
}
}

impl<'a, K, V> IntoIterator for &'a mut BTreeMap<K, V> {
type Iter = IterMut<'a, K, V>;

fn into_iter(mut self) -> IterMut<'a, K, V> {
self.iter_mut()
}
}

/// A helper enum useful for deciding whether to continue a loop since we can't
/// return from a closure
enum Continuation<A, B> {
Expand Down
8 changes: 4 additions & 4 deletions src/libcollections/btree/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ impl<T> DoubleEndedIterator for RawItems<T> {
#[unsafe_destructor]
impl<T> Drop for RawItems<T> {
fn drop(&mut self) {
for _ in *self {}
for _ in self.by_ref() {}
}
}

Expand Down Expand Up @@ -1374,9 +1374,9 @@ impl<K, V> Drop for MoveTraversalImpl<K, V> {
fn drop(&mut self) {
// We need to cleanup the stored values manually, as the RawItems destructor would run
// after our deallocation.
for _ in self.keys {}
for _ in self.vals {}
for _ in self.edges {}
for _ in self.keys.by_ref() {}
for _ in self.vals.by_ref() {}
for _ in self.edges.by_ref() {}

let (alignment, size) =
calculate_allocation_generic::<K, V>(self.capacity, self.is_leaf);
Expand Down
18 changes: 17 additions & 1 deletion src/libcollections/btree/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use core::cmp::Ordering::{self, Less, Greater, Equal};
use core::default::Default;
use core::fmt::Debug;
use core::fmt;
use core::iter::{Peekable, Map, FromIterator};
use core::iter::{Peekable, Map, FromIterator, IntoIterator};
use core::ops::{BitOr, BitAnd, BitXor, Sub};

use btree_map::{BTreeMap, Keys};
Expand Down Expand Up @@ -480,6 +480,22 @@ impl<T: Ord> FromIterator<T> for BTreeSet<T> {
}
}

impl<T> IntoIterator for BTreeSet<T> {
type Iter = IntoIter<T>;

fn into_iter(self) -> IntoIter<T> {
self.into_iter()
}
}

impl<'a, T> IntoIterator for &'a BTreeSet<T> {
type Iter = Iter<'a, T>;

fn into_iter(self) -> Iter<'a, T> {
self.iter()
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Ord> Extend<T> for BTreeSet<T> {
#[inline]
Expand Down
26 changes: 25 additions & 1 deletion src/libcollections/dlist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use core::cmp::Ordering;
use core::default::Default;
use core::fmt;
use core::hash::{Writer, Hasher, Hash};
use core::iter::{self, FromIterator};
use core::iter::{self, FromIterator, IntoIterator};
use core::mem;
use core::ptr;

Expand Down Expand Up @@ -830,6 +830,30 @@ impl<A> FromIterator<A> for DList<A> {
}
}

impl<T> IntoIterator for DList<T> {
type Iter = IntoIter<T>;

fn into_iter(self) -> IntoIter<T> {
self.into_iter()
}
}

impl<'a, T> IntoIterator for &'a DList<T> {
type Iter = Iter<'a, T>;

fn into_iter(self) -> Iter<'a, T> {
self.iter()
}
}

impl<'a, T> IntoIterator for &'a mut DList<T> {
type Iter = IterMut<'a, T>;

fn into_iter(mut self) -> IterMut<'a, T> {
self.iter_mut()
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A> Extend<A> for DList<A> {
fn extend<T: Iterator<Item=A>>(&mut self, mut iterator: T) {
Expand Down
10 changes: 9 additions & 1 deletion src/libcollections/enum_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
use core::prelude::*;
use core::fmt;
use core::num::Int;
use core::iter::FromIterator;
use core::iter::{FromIterator, IntoIterator};
use core::ops::{Sub, BitOr, BitAnd, BitXor};

// FIXME(contentions): implement union family of methods? (general design may be wrong here)
Expand Down Expand Up @@ -256,6 +256,14 @@ impl<E:CLike> FromIterator<E> for EnumSet<E> {
}
}

impl<'a, E> IntoIterator for &'a EnumSet<E> where E: CLike {
type Iter = Iter<E>;

fn into_iter(self) -> Iter<E> {
self.iter()
}
}

impl<E:CLike> Extend<E> for EnumSet<E> {
fn extend<I: Iterator<Item=E>>(&mut self, mut iterator: I) {
for element in iterator {
Expand Down
4 changes: 4 additions & 0 deletions src/libcollections/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
#![feature(unicode)]
#![feature(hash)]
#![cfg_attr(test, feature(test))]
// NOTE(stage0): remove after a snapshot
#![cfg_attr(not(stage0), allow(unused_mut))]

#[macro_use]
extern crate core;
Expand Down Expand Up @@ -114,6 +116,8 @@ mod std {
pub use core::marker; // derive(Copy)
pub use core::hash; // derive(Hash)
pub use core::ops; // RangeFull
// for-loops
pub use core::iter;
}

#[cfg(test)]
Expand Down
28 changes: 26 additions & 2 deletions src/libcollections/ring_buf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use core::prelude::*;
use core::cmp::Ordering;
use core::default::Default;
use core::fmt;
use core::iter::{self, repeat, FromIterator, RandomAccessIterator};
use core::iter::{self, repeat, FromIterator, IntoIterator, RandomAccessIterator};
use core::marker;
use core::mem;
use core::num::{Int, UnsignedInt};
Expand Down Expand Up @@ -1510,7 +1510,7 @@ pub struct Drain<'a, T: 'a> {
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: 'a> Drop for Drain<'a, T> {
fn drop(&mut self) {
for _ in *self {}
for _ in self.by_ref() {}
self.inner.head = 0;
self.inner.tail = 0;
}
Expand Down Expand Up @@ -1609,6 +1609,30 @@ impl<A> FromIterator<A> for RingBuf<A> {
}
}

impl<T> IntoIterator for RingBuf<T> {
type Iter = IntoIter<T>;

fn into_iter(self) -> IntoIter<T> {
self.into_iter()
}
}

impl<'a, T> IntoIterator for &'a RingBuf<T> {
type Iter = Iter<'a, T>;

fn into_iter(self) -> Iter<'a, T> {
self.iter()
}
}

impl<'a, T> IntoIterator for &'a mut RingBuf<T> {
type Iter = IterMut<'a, T>;

fn into_iter(mut self) -> IterMut<'a, T> {
self.iter_mut()
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A> Extend<A> for RingBuf<A> {
fn extend<T: Iterator<Item=A>>(&mut self, mut iterator: T) {
Expand Down
2 changes: 1 addition & 1 deletion src/libcollections/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1958,7 +1958,7 @@ mod tests {
let mut amt = 0;
let mut it = v.permutations();
let (min_size, max_opt) = it.size_hint();
for _perm in it {
for _perm in it.by_ref() {
amt += 1;
}
assert_eq!(amt, it.swaps.swaps_made);
Expand Down
6 changes: 3 additions & 3 deletions src/libcollections/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ impl<'a> Iterator for Decompositions<'a> {
}

if !self.sorted {
for ch in self.iter {
for ch in self.iter.by_ref() {
let buffer = &mut self.buffer;
let sorted = &mut self.sorted;
{
Expand Down Expand Up @@ -279,7 +279,7 @@ impl<'a> Iterator for Recompositions<'a> {
loop {
match self.state {
Composing => {
for ch in self.iter {
for ch in self.iter.by_ref() {
let ch_class = unicode::char::canonical_combining_class(ch);
if self.composee.is_none() {
if ch_class != 0 {
Expand Down Expand Up @@ -2154,7 +2154,7 @@ mod tests {
let s = "ศไทย中华Việt Nam";
let mut it = s.chars();
it.next();
assert!(it.zip(it.clone()).all(|(x,y)| x == y));
assert!(it.clone().zip(it).all(|(x,y)| x == y));
}

#[test]
Expand Down
Loading

0 comments on commit 341e858

Please sign in to comment.