Search code examples
rustiterator

How can I compose iterator adapter without boilerplate each time like in node.js Readable.compose


I want to be able to compose iterators that even support genawaiter crate and avoid the boilerplate for every iterator adapter

I want to be able to iterator.compose(fn) like below (I know I can use the map operator but this is a simplified example for when I need to have some state in the iterators):

use genawaiter::{rc::gen, yield_};
use std::iter::Iterator;

fn wrap_with_option<Input, I: Iterator<Item = Input>>(iter: I) -> impl Iterator<Item = Option<Input>> {
    return gen!({
            for item in iter {
                yield_!(Some(item));
            }
        })
    .into_iter();
}
fn run() {

    let input: Vec<i32> = vec![1, 2, 3, 4, 5];
    let output: Vec<Option<&i32>> = input
        .iter()
        .compose(wrap_with_option)
        .collect();

    let expected = vec![
        Some(&1),
        Some(&2),
        Some(&3),
        Some(&4),
        Some(&5)
    ];
    assert_eq!(output, expected);
}

Solution

  • There is the tap crate that provides this general functionality. It provides methods to use function calls in a method-chained way.

    You would use the .pipe() method via its Pipe trait.

    use tap::Pipe;
    
    let output: Vec<Option<&i32>> = input
        .iter()
        .pipe(wrap_with_option)
        .collect();