diff options
| author | bors <bors@rust-lang.org> | 2013-08-16 01:56:16 -0700 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2013-08-16 01:56:16 -0700 |
| commit | 72b50e729d9662ed22f87aa1fcb97a309afbc0fa (patch) | |
| tree | c47e2e3115f2e08a621b0825533e457e3a9f6a68 /src/libstd | |
| parent | 92af0db0a3919f5371de362cb6060ff87190aafe (diff) | |
| parent | 88c149195af66c95d94db30bc55de6204ad82f8f (diff) | |
| download | rust-72b50e729d9662ed22f87aa1fcb97a309afbc0fa.tar.gz rust-72b50e729d9662ed22f87aa1fcb97a309afbc0fa.zip | |
auto merge of #8526 : blake2-ppc/rust/either-result, r=catamorphism
Retry of PR #8471
Replace the remaining functions marked for issue #8228 with similar functions that are iterator-based.
Change `either::{lefts, rights}` to be iterator-filtering instead of returning a vector.
Replace `map_vec`, `map_vec2`, `iter_vec2` in std::result with three functions:
* `result::collect` gathers `Iterator<Result<V, U>>` to `Result<~[V], U>`
* `result::fold` folds `Iterator<Result<T, E>>` to `Result<V, E>`
* `result::fold_` folds `Iterator<Result<T, E>>` to `Result<(), E>`
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/either.rs | 58 | ||||
| -rw-r--r-- | src/libstd/result.rs | 139 |
2 files changed, 115 insertions, 82 deletions
diff --git a/src/libstd/either.rs b/src/libstd/either.rs index 132ebc72960..5d988965e8c 100644 --- a/src/libstd/either.rs +++ b/src/libstd/either.rs @@ -16,7 +16,7 @@ use option::{Some, None}; use clone::Clone; use container::Container; use cmp::Eq; -use iterator::Iterator; +use iterator::{Iterator, FilterMap}; use result::Result; use result; use str::StrSlice; @@ -116,40 +116,44 @@ impl<L, R> Either<L, R> { } } -// FIXME: #8228 Replaceable by an external iterator? -/// Extracts from a vector of either all the left values -pub fn lefts<L: Clone, R>(eithers: &[Either<L, R>]) -> ~[L] { - do vec::build_sized(eithers.len()) |push| { - for elt in eithers.iter() { - match *elt { - Left(ref l) => { push((*l).clone()); } - _ => { /* fallthrough */ } - } +/// An iterator yielding the `Left` values of its source +pub type Lefts<L, R, Iter> = FilterMap<'static, Either<L, R>, L, Iter>; + +/// An iterator yielding the `Right` values of its source +pub type Rights<L, R, Iter> = FilterMap<'static, Either<L, R>, R, Iter>; + +/// Extracts all the left values +pub fn lefts<L, R, Iter: Iterator<Either<L, R>>>(eithers: Iter) + -> Lefts<L, R, Iter> { + do eithers.filter_map |elt| { + match elt { + Left(x) => Some(x), + _ => None, } } } -// FIXME: #8228 Replaceable by an external iterator? -/// Extracts from a vector of either all the right values -pub fn rights<L, R: Clone>(eithers: &[Either<L, R>]) -> ~[R] { - do vec::build_sized(eithers.len()) |push| { - for elt in eithers.iter() { - match *elt { - Right(ref r) => { push((*r).clone()); } - _ => { /* fallthrough */ } - } +/// Extracts all the right values +pub fn rights<L, R, Iter: Iterator<Either<L, R>>>(eithers: Iter) + -> Rights<L, R, Iter> { + do eithers.filter_map |elt| { + match elt { + Right(x) => Some(x), + _ => None, } } } + // FIXME: #8228 Replaceable by an external iterator? /// Extracts from a vector of either all the left values and right values /// /// Returns a structure containing a vector of left values and a vector of /// right values. pub fn partition<L, R>(eithers: ~[Either<L, R>]) -> (~[L], ~[R]) { - let mut lefts: ~[L] = ~[]; - let mut rights: ~[R] = ~[]; + let n_lefts = eithers.iter().count(|elt| elt.is_left()); + let mut lefts = vec::with_capacity(n_lefts); + let mut rights = vec::with_capacity(eithers.len() - n_lefts); for elt in eithers.move_iter() { match elt { Left(l) => lefts.push(l), @@ -182,42 +186,42 @@ mod tests { #[test] fn test_lefts() { let input = ~[Left(10), Right(11), Left(12), Right(13), Left(14)]; - let result = lefts(input); + let result = lefts(input.move_iter()).to_owned_vec(); assert_eq!(result, ~[10, 12, 14]); } #[test] fn test_lefts_none() { let input: ~[Either<int, int>] = ~[Right(10), Right(10)]; - let result = lefts(input); + let result = lefts(input.move_iter()).to_owned_vec(); assert_eq!(result.len(), 0u); } #[test] fn test_lefts_empty() { let input: ~[Either<int, int>] = ~[]; - let result = lefts(input); + let result = lefts(input.move_iter()).to_owned_vec(); assert_eq!(result.len(), 0u); } #[test] fn test_rights() { let input = ~[Left(10), Right(11), Left(12), Right(13), Left(14)]; - let result = rights(input); + let result = rights(input.move_iter()).to_owned_vec(); assert_eq!(result, ~[11, 13]); } #[test] fn test_rights_none() { let input: ~[Either<int, int>] = ~[Left(10), Left(10)]; - let result = rights(input); + let result = rights(input.move_iter()).to_owned_vec(); assert_eq!(result.len(), 0u); } #[test] fn test_rights_empty() { let input: ~[Either<int, int>] = ~[]; - let result = rights(input); + let result = rights(input.move_iter()).to_owned_vec(); assert_eq!(result.len(), 0u); } diff --git a/src/libstd/result.rs b/src/libstd/result.rs index 9de5e69148a..9ae901d60bc 100644 --- a/src/libstd/result.rs +++ b/src/libstd/result.rs @@ -18,8 +18,7 @@ use either; use iterator::Iterator; use option::{None, Option, Some, OptionIterator}; use vec; -use vec::{OwnedVector, ImmutableVector}; -use container::Container; +use vec::OwnedVector; use to_str::ToStr; use str::StrSlice; @@ -269,86 +268,76 @@ pub fn map_opt<T, U: ToStr, V>(o_t: &Option<T>, } } -// FIXME: #8228 Replaceable by an external iterator? -/// Maps each element in the vector `ts` using the operation `op`. Should an -/// error occur, no further mappings are performed and the error is returned. -/// Should no error occur, a vector containing the result of each map is -/// returned. +/// Takes each element in the iterator: if it is an error, no further +/// elements are taken, and the error is returned. +/// Should no error occur, a vector containing the values of each Result +/// is returned. /// /// Here is an example which increments every integer in a vector, /// checking for overflow: /// -/// fn inc_conditionally(x: uint) -> result<uint,str> { +/// fn inc_conditionally(x: uint) -> Result<uint, &'static str> { /// if x == uint::max_value { return Err("overflow"); } /// else { return Ok(x+1u); } /// } -/// map(~[1u, 2u, 3u], inc_conditionally).chain {|incd| -/// assert!(incd == ~[2u, 3u, 4u]); -/// } +/// let v = [1u, 2, 3]; +/// let res = collect(v.iter().map(|&x| inc_conditionally(x))); +/// assert!(res == Ok(~[2u, 3, 4])); #[inline] -pub fn map_vec<T,U,V>(ts: &[T], op: &fn(&T) -> Result<V,U>) - -> Result<~[V],U> { - let mut vs: ~[V] = vec::with_capacity(ts.len()); - for t in ts.iter() { - match op(t) { - Ok(v) => vs.push(v), - Err(u) => return Err(u) +pub fn collect<T, E, Iter: Iterator<Result<T, E>>>(mut iterator: Iter) + -> Result<~[T], E> { + let (lower, _) = iterator.size_hint(); + let mut vs: ~[T] = vec::with_capacity(lower); + for t in iterator { + match t { + Ok(v) => vs.push(v), + Err(u) => return Err(u) } } - return Ok(vs); + Ok(vs) } -// FIXME: #8228 Replaceable by an external iterator? -/// Same as map, but it operates over two parallel vectors. +/// Perform a fold operation over the result values from an iterator. /// -/// A precondition is used here to ensure that the vectors are the same -/// length. While we do not often use preconditions in the standard -/// library, a precondition is used here because result::t is generally -/// used in 'careful' code contexts where it is both appropriate and easy -/// to accommodate an error like the vectors being of different lengths. +/// If an `Err` is encountered, it is immediately returned. +/// Otherwise, the folded value is returned. #[inline] -pub fn map_vec2<S, T, U: ToStr, V>(ss: &[S], ts: &[T], - op: &fn(&S,&T) -> Result<V,U>) -> Result<~[V],U> { - assert!(vec::same_length(ss, ts)); - let n = ts.len(); - let mut vs = vec::with_capacity(n); - let mut i = 0u; - while i < n { - match op(&ss[i],&ts[i]) { - Ok(v) => vs.push(v), - Err(u) => return Err(u) +pub fn fold<T, V, E, + Iter: Iterator<Result<T, E>>>( + mut iterator: Iter, + mut init: V, + f: &fn(V, T) -> V) + -> Result<V, E> { + for t in iterator { + match t { + Ok(v) => init = f(init, v), + Err(u) => return Err(u) } - i += 1u; } - return Ok(vs); + Ok(init) } -// FIXME: #8228 Replaceable by an external iterator? -/// Applies op to the pairwise elements from `ss` and `ts`, aborting on -/// error. This could be implemented using `map_zip()` but it is more efficient -/// on its own as no result vector is built. +/// Perform a trivial fold operation over the result values +/// from an iterator. +/// +/// If an `Err` is encountered, it is immediately returned. +/// Otherwise, a simple `Ok(())` is returned. #[inline] -pub fn iter_vec2<S, T, U: ToStr>(ss: &[S], ts: &[T], - op: &fn(&S,&T) -> Result<(),U>) -> Result<(),U> { - assert!(vec::same_length(ss, ts)); - let n = ts.len(); - let mut i = 0u; - while i < n { - match op(&ss[i],&ts[i]) { - Ok(()) => (), - Err(u) => return Err(u) - } - i += 1u; - } - return Ok(()); +pub fn fold_<T, E, Iter: Iterator<Result<T, E>>>( + iterator: Iter) + -> Result<(), E> { + fold(iterator, (), |_, _| ()) } + #[cfg(test)] mod tests { use super::*; use either; + use iterator::range; use str::OwnedStr; + use vec::ImmutableVector; pub fn op1() -> Result<int, ~str> { Ok(666) } @@ -431,4 +420,44 @@ mod tests { assert_eq!(r.to_either(), either::Right(100)); assert_eq!(err.to_either(), either::Left(404)); } + + #[test] + fn test_collect() { + assert_eq!(collect(range(0, 0) + .map(|_| Ok::<int, ()>(0))), + Ok(~[])); + assert_eq!(collect(range(0, 3) + .map(|x| Ok::<int, ()>(x))), + Ok(~[0, 1, 2])); + assert_eq!(collect(range(0, 3) + .map(|x| if x > 1 { Err(x) } else { Ok(x) })), + Err(2)); + + // test that it does not take more elements than it needs + let functions = [|| Ok(()), || Err(1), || fail!()]; + + assert_eq!(collect(functions.iter().map(|f| (*f)())), + Err(1)); + } + + #[test] + fn test_fold() { + assert_eq!(fold_(range(0, 0) + .map(|_| Ok::<(), ()>(()))), + Ok(())); + assert_eq!(fold(range(0, 3) + .map(|x| Ok::<int, ()>(x)), + 0, |a, b| a + b), + Ok(3)); + assert_eq!(fold_(range(0, 3) + .map(|x| if x > 1 { Err(x) } else { Ok(()) })), + Err(2)); + + // test that it does not take more elements than it needs + let functions = [|| Ok(()), || Err(1), || fail!()]; + + assert_eq!(fold_(functions.iter() + .map(|f| (*f)())), + Err(1)); + } } |
