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>`
This commit is contained in:
commit
72b50e729d
@ -57,6 +57,7 @@ pub fn read_crates(diag: @mut span_handler,
|
||||
warn_if_multiple_versions(e, diag, *e.crate_cache);
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
struct cache_entry {
|
||||
cnum: int,
|
||||
span: span,
|
||||
@ -76,22 +77,13 @@ fn dump_crates(crate_cache: &[cache_entry]) {
|
||||
fn warn_if_multiple_versions(e: @mut Env,
|
||||
diag: @mut span_handler,
|
||||
crate_cache: &[cache_entry]) {
|
||||
use std::either::*;
|
||||
|
||||
if crate_cache.len() != 0u {
|
||||
let name = loader::crate_name_from_metas(
|
||||
*crate_cache[crate_cache.len() - 1].metas
|
||||
);
|
||||
|
||||
let vec: ~[Either<cache_entry, cache_entry>] = crate_cache.iter().map(|&entry| {
|
||||
let othername = loader::crate_name_from_metas(*entry.metas);
|
||||
if name == othername {
|
||||
Left(entry)
|
||||
} else {
|
||||
Right(entry)
|
||||
}
|
||||
}).collect();
|
||||
let (matches, non_matches) = partition(vec);
|
||||
let (matches, non_matches) = crate_cache.partitioned(|entry|
|
||||
name == loader::crate_name_from_metas(*entry.metas));
|
||||
|
||||
assert!(!matches.is_empty());
|
||||
|
||||
|
@ -68,7 +68,7 @@
|
||||
use middle::typeck::infer::{TypeTrace};
|
||||
use util::common::indent;
|
||||
|
||||
use std::result::{iter_vec2, map_vec2};
|
||||
use std::result;
|
||||
use std::vec;
|
||||
use syntax::ast::{Onceness, purity};
|
||||
use syntax::ast;
|
||||
@ -275,9 +275,9 @@ pub fn super_tps<C:Combine>(
|
||||
// variance.
|
||||
|
||||
if vec::same_length(as_, bs) {
|
||||
iter_vec2(as_, bs, |a, b| {
|
||||
eq_tys(this, *a, *b)
|
||||
}).then(|| Ok(as_.to_owned()) )
|
||||
result::fold_(as_.iter().zip(bs.iter())
|
||||
.map(|(a, b)| eq_tys(this, *a, *b)))
|
||||
.then(|| Ok(as_.to_owned()))
|
||||
} else {
|
||||
Err(ty::terr_ty_param_size(
|
||||
expected_found(this, as_.len(), bs.len())))
|
||||
@ -427,7 +427,8 @@ pub fn super_fn_sigs<C:Combine>(
|
||||
{
|
||||
fn argvecs<C:Combine>(this: &C, a_args: &[ty::t], b_args: &[ty::t]) -> cres<~[ty::t]> {
|
||||
if vec::same_length(a_args, b_args) {
|
||||
map_vec2(a_args, b_args, |a, b| this.args(*a, *b))
|
||||
result::collect(a_args.iter().zip(b_args.iter())
|
||||
.map(|(a, b)| this.args(*a, *b)))
|
||||
} else {
|
||||
Err(ty::terr_arg_count)
|
||||
}
|
||||
@ -586,8 +587,9 @@ pub fn super_tys<C:Combine>(
|
||||
|
||||
(&ty::ty_tup(ref as_), &ty::ty_tup(ref bs)) => {
|
||||
if as_.len() == bs.len() {
|
||||
map_vec2(*as_, *bs, |a, b| this.tys(*a, *b) )
|
||||
.chain(|ts| Ok(ty::mk_tup(tcx, ts)) )
|
||||
result::collect(as_.iter().zip(bs.iter())
|
||||
.map(|(a, b)| this.tys(*a, *b)))
|
||||
.chain(|ts| Ok(ty::mk_tup(tcx, ts)) )
|
||||
} else {
|
||||
Err(ty::terr_tuple_size(
|
||||
expected_found(this, as_.len(), bs.len())))
|
||||
|
@ -16,7 +16,7 @@
|
||||
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 @@ pub fn unwrap_right(self) -> 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 @@ fn f_right(x: &uint) -> bool { *x == 10u }
|
||||
#[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);
|
||||
}
|
||||
|
||||
|
@ -18,8 +18,7 @@
|
||||
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 @@ pub fn test_to_either() {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
@ -3445,7 +3445,7 @@ pub fn parse_fn_decl(&self) -> fn_decl {
|
||||
|p| p.parse_arg()
|
||||
);
|
||||
|
||||
let inputs = either::lefts(args_or_capture_items);
|
||||
let inputs = either::lefts(args_or_capture_items.move_iter()).collect();
|
||||
|
||||
let (ret_style, ret_ty) = self.parse_ret_ty();
|
||||
ast::fn_decl {
|
||||
@ -3608,7 +3608,7 @@ fn maybe_parse_borrowed_explicit_self(this: &Parser) -> ast::explicit_self_ {
|
||||
|
||||
let hi = self.span.hi;
|
||||
|
||||
let inputs = either::lefts(args_or_capture_items);
|
||||
let inputs = either::lefts(args_or_capture_items.move_iter()).collect();
|
||||
let (ret_style, ret_ty) = self.parse_ret_ty();
|
||||
|
||||
let fn_decl = ast::fn_decl {
|
||||
@ -3641,7 +3641,7 @@ fn parse_fn_block_decl(&self) -> fn_decl {
|
||||
};
|
||||
|
||||
ast::fn_decl {
|
||||
inputs: either::lefts(inputs_captures),
|
||||
inputs: either::lefts(inputs_captures.move_iter()).collect(),
|
||||
output: output,
|
||||
cf: return_val,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user