Skip to content

Commit a5fa1d9

Browse files
committed
auto merge of #11098 : erickt/rust/collect, r=alexcrichton
This patch changes `result::collect` (and adds a new `option::collect`) from creating a `~[T]` to take an `Iterator`. This makes the function much more flexible, and may replace the need for #10989. This patch is a little more complicated than it needs to be because of #11084. Once that is fixed we can replace the `CollectIterator` with a `Scan` iterator. It also fixes a test warning.
2 parents 1a9c8cc + 1da9112 commit a5fa1d9

File tree

3 files changed

+98
-31
lines changed

3 files changed

+98
-31
lines changed

src/libstd/io/comm_adapters.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,6 @@ mod test {
117117
use prelude::*;
118118
use super::*;
119119
use io;
120-
use comm;
121120
use task;
122121

123122
#[test]
@@ -136,7 +135,7 @@ mod test {
136135

137136
assert_eq!(false, reader.eof());
138137

139-
assert_eq!(Some(0), reader.read(~[]));
138+
assert_eq!(Some(0), reader.read([]));
140139
assert_eq!(false, reader.eof());
141140

142141
assert_eq!(Some(3), reader.read(buf));

src/libstd/option.rs

+65-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ use clone::DeepClone;
4343
use cmp::{Eq, TotalEq, TotalOrd};
4444
use default::Default;
4545
use fmt;
46-
use iter::{Iterator, DoubleEndedIterator, ExactSize};
46+
use iter::{Iterator, DoubleEndedIterator, FromIterator, ExactSize};
4747
use kinds::Send;
4848
use str::OwnedStr;
4949
use to_str::ToStr;
@@ -410,6 +410,46 @@ impl<A> DoubleEndedIterator<A> for OptionIterator<A> {
410410

411411
impl<A> ExactSize<A> for OptionIterator<A> {}
412412

413+
/////////////////////////////////////////////////////////////////////////////
414+
// Free functions
415+
/////////////////////////////////////////////////////////////////////////////
416+
417+
/// Takes each element in the `Iterator`: if it is `None`, no further
418+
/// elements are taken, and the `None` is returned. Should no `None` occur, a
419+
/// vector containing the values of each `Option` is returned.
420+
///
421+
/// Here is an example which increments every integer in a vector,
422+
/// checking for overflow:
423+
///
424+
/// fn inc_conditionally(x: uint) -> Option<uint> {
425+
/// if x == uint::max_value { return None; }
426+
/// else { return Some(x+1u); }
427+
/// }
428+
/// let v = [1u, 2, 3];
429+
/// let res = collect(v.iter().map(|&x| inc_conditionally(x)));
430+
/// assert!(res == Some(~[2u, 3, 4]));
431+
#[inline]
432+
pub fn collect<T, Iter: Iterator<Option<T>>, V: FromIterator<T>>(iter: Iter) -> Option<V> {
433+
// FIXME(#11084): This should be twice as fast once this bug is closed.
434+
let mut iter = iter.scan(false, |state, x| {
435+
match x {
436+
Some(x) => Some(x),
437+
None => {
438+
*state = true;
439+
None
440+
}
441+
}
442+
});
443+
444+
let v: V = FromIterator::from_iterator(&mut iter);
445+
446+
if iter.state {
447+
None
448+
} else {
449+
Some(v)
450+
}
451+
}
452+
413453
/////////////////////////////////////////////////////////////////////////////
414454
// Tests
415455
/////////////////////////////////////////////////////////////////////////////
@@ -418,8 +458,10 @@ impl<A> ExactSize<A> for OptionIterator<A> {}
418458
mod tests {
419459
use super::*;
420460

461+
use iter::range;
421462
use str::StrSlice;
422463
use util;
464+
use vec::ImmutableVector;
423465

424466
#[test]
425467
fn test_get_ptr() {
@@ -661,4 +703,26 @@ mod tests {
661703
assert!(!x.mutate_default(0i, |i| i+1));
662704
assert_eq!(x, Some(0i));
663705
}
706+
707+
#[test]
708+
fn test_collect() {
709+
let v: Option<~[int]> = collect(range(0, 0)
710+
.map(|_| Some(0)));
711+
assert_eq!(v, Some(~[]));
712+
713+
let v: Option<~[int]> = collect(range(0, 3)
714+
.map(|x| Some(x)));
715+
assert_eq!(v, Some(~[0, 1, 2]));
716+
717+
let v: Option<~[int]> = collect(range(0, 3)
718+
.map(|x| if x > 1 { None } else { Some(x) }));
719+
assert_eq!(v, None);
720+
721+
// test that it does not take more elements than it needs
722+
let functions = [|| Some(()), || None, || fail!()];
723+
724+
let v: Option<~[()]> = collect(functions.iter().map(|f| (*f)()));
725+
726+
assert_eq!(v, None);
727+
}
664728
}

src/libstd/result.rs

+32-28
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,10 @@
1313
use clone::Clone;
1414
use cmp::Eq;
1515
use fmt;
16-
use iter::Iterator;
16+
use iter::{Iterator, FromIterator};
1717
use option::{None, Option, Some};
1818
use str::OwnedStr;
1919
use to_str::ToStr;
20-
use vec::OwnedVector;
21-
use vec;
2220

2321
/// `Result` is a type that represents either success (`Ok`) or failure (`Err`).
2422
#[deriving(Clone, DeepClone, Eq, Ord, TotalEq, TotalOrd, ToStr)]
@@ -221,10 +219,9 @@ impl<T: fmt::Default, E: fmt::Default> fmt::Default for Result<T, E> {
221219
// Free functions
222220
/////////////////////////////////////////////////////////////////////////////
223221

224-
/// Takes each element in the iterator: if it is an error, no further
225-
/// elements are taken, and the error is returned.
226-
/// Should no error occur, a vector containing the values of each Result
227-
/// is returned.
222+
/// Takes each element in the `Iterator`: if it is an `Err`, no further
223+
/// elements are taken, and the `Err` is returned. Should no `Err` occur, a
224+
/// vector containing the values of each `Result` is returned.
228225
///
229226
/// Here is an example which increments every integer in a vector,
230227
/// checking for overflow:
@@ -237,17 +234,24 @@ impl<T: fmt::Default, E: fmt::Default> fmt::Default for Result<T, E> {
237234
/// let res = collect(v.iter().map(|&x| inc_conditionally(x)));
238235
/// assert!(res == Ok(~[2u, 3, 4]));
239236
#[inline]
240-
pub fn collect<T, E, Iter: Iterator<Result<T, E>>>(mut iterator: Iter)
241-
-> Result<~[T], E> {
242-
let (lower, _) = iterator.size_hint();
243-
let mut vs: ~[T] = vec::with_capacity(lower);
244-
for t in iterator {
245-
match t {
246-
Ok(v) => vs.push(v),
247-
Err(u) => return Err(u)
237+
pub fn collect<T, E, Iter: Iterator<Result<T, E>>, V: FromIterator<T>>(iter: Iter) -> Result<V, E> {
238+
// FIXME(#11084): This should be twice as fast once this bug is closed.
239+
let mut iter = iter.scan(None, |state, x| {
240+
match x {
241+
Ok(x) => Some(x),
242+
Err(err) => {
243+
*state = Some(err);
244+
None
245+
}
248246
}
247+
});
248+
249+
let v: V = FromIterator::from_iterator(&mut iter);
250+
251+
match iter.state {
252+
Some(err) => Err(err),
253+
None => Ok(v),
249254
}
250-
Ok(vs)
251255
}
252256

253257
/// Perform a fold operation over the result values from an iterator.
@@ -291,8 +295,8 @@ mod tests {
291295
use super::*;
292296

293297
use iter::range;
294-
use vec::ImmutableVector;
295298
use to_str::ToStr;
299+
use vec::ImmutableVector;
296300

297301
pub fn op1() -> Result<int, ~str> { Ok(666) }
298302
pub fn op2() -> Result<int, ~str> { Err(~"sadface") }
@@ -347,21 +351,21 @@ mod tests {
347351
348352
#[test]
349353
fn test_collect() {
350-
assert_eq!(collect(range(0, 0)
351-
.map(|_| Ok::<int, ()>(0))),
352-
Ok(~[]));
353-
assert_eq!(collect(range(0, 3)
354-
.map(|x| Ok::<int, ()>(x))),
355-
Ok(~[0, 1, 2]));
356-
assert_eq!(collect(range(0, 3)
357-
.map(|x| if x > 1 { Err(x) } else { Ok(x) })),
358-
Err(2));
354+
let v: Result<~[int], ()> = collect(range(0, 0).map(|_| Ok::<int, ()>(0)));
355+
assert_eq!(v, Ok(~[]));
356+
357+
let v: Result<~[int], ()> = collect(range(0, 3).map(|x| Ok::<int, ()>(x)));
358+
assert_eq!(v, Ok(~[0, 1, 2]));
359+
360+
let v: Result<~[int], int> = collect(range(0, 3)
361+
.map(|x| if x > 1 { Err(x) } else { Ok(x) }));
362+
assert_eq!(v, Err(2));
359363
360364
// test that it does not take more elements than it needs
361365
let functions = [|| Ok(()), || Err(1), || fail!()];
362366
363-
assert_eq!(collect(functions.iter().map(|f| (*f)())),
364-
Err(1));
367+
let v: Result<~[()], int> = collect(functions.iter().map(|f| (*f)()));
368+
assert_eq!(v, Err(1));
365369
}
366370
367371
#[test]

0 commit comments

Comments
 (0)