@@ -18,8 +18,7 @@ use either;
18
18
use iterator:: Iterator ;
19
19
use option:: { None , Option , Some , OptionIterator } ;
20
20
use vec;
21
- use vec:: { OwnedVector , ImmutableVector } ;
22
- use container:: Container ;
21
+ use vec:: OwnedVector ;
23
22
use to_str:: ToStr ;
24
23
use str:: StrSlice ;
25
24
@@ -269,86 +268,76 @@ pub fn map_opt<T, U: ToStr, V>(o_t: &Option<T>,
269
268
}
270
269
}
271
270
272
- // FIXME: #8228 Replaceable by an external iterator?
273
- /// Maps each element in the vector `ts` using the operation `op`. Should an
274
- /// error occur, no further mappings are performed and the error is returned.
275
- /// Should no error occur, a vector containing the result of each map is
276
- /// returned.
271
+ /// Takes each element in the iterator: if it is an error, no further
272
+ /// elements are taken, and the error is returned.
273
+ /// Should no error occur, a vector containing the values of each Result
274
+ /// is returned.
277
275
///
278
276
/// Here is an example which increments every integer in a vector,
279
277
/// checking for overflow:
280
278
///
281
- /// fn inc_conditionally(x: uint) -> result <uint,str> {
279
+ /// fn inc_conditionally(x: uint) -> Result <uint, &'static str> {
282
280
/// if x == uint::max_value { return Err("overflow"); }
283
281
/// else { return Ok(x+1u); }
284
282
/// }
285
- /// map(~ [1u, 2u, 3u], inc_conditionally).chain {|incd|
286
- /// assert!(incd == ~[2u, 3u, 4u] );
287
- /// }
283
+ /// let v = [1u, 2, 3];
284
+ /// let res = collect(v.iter().map(|&x| inc_conditionally(x)) );
285
+ /// assert!(res == Ok(~[2u, 3, 4]));
288
286
#[ inline]
289
- pub fn map_vec < T , U , V > ( ts : & [ T ] , op : & fn ( & T ) -> Result < V , U > )
290
- -> Result < ~[ V ] , U > {
291
- let mut vs: ~[ V ] = vec:: with_capacity ( ts. len ( ) ) ;
292
- for t in ts. iter ( ) {
293
- match op ( t) {
294
- Ok ( v) => vs. push ( v) ,
295
- Err ( u) => return Err ( u)
287
+ pub fn collect < T , E , Iter : Iterator < Result < T , E > > > ( mut iterator : Iter )
288
+ -> Result < ~[ T ] , E > {
289
+ let ( lower, _) = iterator. size_hint ( ) ;
290
+ let mut vs: ~[ T ] = vec:: with_capacity ( lower) ;
291
+ for t in iterator {
292
+ match t {
293
+ Ok ( v) => vs. push ( v) ,
294
+ Err ( u) => return Err ( u)
296
295
}
297
296
}
298
- return Ok ( vs) ;
297
+ Ok ( vs)
299
298
}
300
299
301
- // FIXME: #8228 Replaceable by an external iterator?
302
- /// Same as map, but it operates over two parallel vectors.
300
+ /// Perform a fold operation over the result values from an iterator.
303
301
///
304
- /// A precondition is used here to ensure that the vectors are the same
305
- /// length. While we do not often use preconditions in the standard
306
- /// library, a precondition is used here because result::t is generally
307
- /// used in 'careful' code contexts where it is both appropriate and easy
308
- /// to accommodate an error like the vectors being of different lengths.
302
+ /// If an `Err` is encountered, it is immediately returned.
303
+ /// Otherwise, the folded value is returned.
309
304
#[ inline]
310
- pub fn map_vec2 < S , T , U : ToStr , V > ( ss : & [ S ] , ts : & [ T ] ,
311
- op : & fn ( & S , & T ) -> Result < V , U > ) -> Result < ~ [ V ] , U > {
312
- assert ! ( vec :: same_length ( ss , ts ) ) ;
313
- let n = ts . len ( ) ;
314
- let mut vs = vec :: with_capacity ( n ) ;
315
- let mut i = 0 u ;
316
- while i < n {
317
- match op ( & ss [ i ] , & ts [ i ] ) {
318
- Ok ( v) => vs . push ( v) ,
319
- Err ( u) => return Err ( u)
305
+ pub fn fold < T , V , E ,
306
+ Iter : Iterator < Result < T , E > > > (
307
+ mut iterator : Iter ,
308
+ mut init : V ,
309
+ f : & fn ( V , T ) -> V )
310
+ -> Result < V , E > {
311
+ for t in iterator {
312
+ match t {
313
+ Ok ( v) => init = f ( init , v) ,
314
+ Err ( u) => return Err ( u)
320
315
}
321
- i += 1 u;
322
316
}
323
- return Ok ( vs ) ;
317
+ Ok ( init )
324
318
}
325
319
326
- // FIXME: #8228 Replaceable by an external iterator?
327
- /// Applies op to the pairwise elements from `ss` and `ts`, aborting on
328
- /// error. This could be implemented using `map_zip()` but it is more efficient
329
- /// on its own as no result vector is built.
320
+ /// Perform a trivial fold operation over the result values
321
+ /// from an iterator.
322
+ ///
323
+ /// If an `Err` is encountered, it is immediately returned.
324
+ /// Otherwise, a simple `Ok(())` is returned.
330
325
#[ inline]
331
- pub fn iter_vec2 < S , T , U : ToStr > ( ss : & [ S ] , ts : & [ T ] ,
332
- op : & fn ( & S , & T ) -> Result < ( ) , U > ) -> Result < ( ) , U > {
333
- assert ! ( vec:: same_length( ss, ts) ) ;
334
- let n = ts. len ( ) ;
335
- let mut i = 0 u;
336
- while i < n {
337
- match op ( & ss[ i] , & ts[ i] ) {
338
- Ok ( ( ) ) => ( ) ,
339
- Err ( u) => return Err ( u)
340
- }
341
- i += 1 u;
342
- }
343
- return Ok ( ( ) ) ;
326
+ pub fn fold_ < T , E , Iter : Iterator < Result < T , E > > > (
327
+ iterator : Iter )
328
+ -> Result < ( ) , E > {
329
+ fold ( iterator, ( ) , |_, _| ( ) )
344
330
}
345
331
332
+
346
333
#[ cfg( test) ]
347
334
mod tests {
348
335
use super :: * ;
349
336
350
337
use either;
338
+ use iterator:: range;
351
339
use str:: OwnedStr ;
340
+ use vec:: ImmutableVector ;
352
341
353
342
pub fn op1 ( ) -> Result < int , ~str > { Ok ( 666 ) }
354
343
@@ -431,4 +420,44 @@ mod tests {
431
420
assert_eq ! ( r. to_either( ) , either:: Right ( 100 ) ) ;
432
421
assert_eq ! ( err. to_either( ) , either:: Left ( 404 ) ) ;
433
422
}
423
+
424
+ #[ test]
425
+ fn test_collect ( ) {
426
+ assert_eq ! ( collect( range( 0 , 0 )
427
+ . map( |_| Ok :: <int, ( ) >( 0 ) ) ) ,
428
+ Ok ( ~[ ] ) ) ;
429
+ assert_eq ! ( collect( range( 0 , 3 )
430
+ . map( |x| Ok :: <int, ( ) >( x) ) ) ,
431
+ Ok ( ~[ 0 , 1 , 2 ] ) ) ;
432
+ assert_eq ! ( collect( range( 0 , 3 )
433
+ . map( |x| if x > 1 { Err ( x) } else { Ok ( x) } ) ) ,
434
+ Err ( 2 ) ) ;
435
+
436
+ // test that it does not take more elements than it needs
437
+ let functions = [ || Ok ( ( ) ) , || Err ( 1 ) , || fail ! ( ) ] ;
438
+
439
+ assert_eq ! ( collect( functions. iter( ) . map( |f| ( * f) ( ) ) ) ,
440
+ Err ( 1 ) ) ;
441
+ }
442
+
443
+ #[ test]
444
+ fn test_fold ( ) {
445
+ assert_eq ! ( fold_( range( 0 , 0 )
446
+ . map( |_| Ok :: <( ) , ( ) >( ( ) ) ) ) ,
447
+ Ok ( ( ) ) ) ;
448
+ assert_eq ! ( fold( range( 0 , 3 )
449
+ . map( |x| Ok :: <int, ( ) >( x) ) ,
450
+ 0 , |a, b| a + b) ,
451
+ Ok ( 3 ) ) ;
452
+ assert_eq ! ( fold_( range( 0 , 3 )
453
+ . map( |x| if x > 1 { Err ( x) } else { Ok ( ( ) ) } ) ) ,
454
+ Err ( 2 ) ) ;
455
+
456
+ // test that it does not take more elements than it needs
457
+ let functions = [ || Ok ( ( ) ) , || Err ( 1 ) , || fail ! ( ) ] ;
458
+
459
+ assert_eq ! ( fold_( functions. iter( )
460
+ . map( |f| ( * f) ( ) ) ) ,
461
+ Err ( 1 ) ) ;
462
+ }
434
463
}
0 commit comments