1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
use std::fs::File;
use std::io::{BufReader, BufRead};
use std::path::PathBuf;

use anyhow::{Result, Context};

pub fn find_matches<'a>(path: &PathBuf, pattern: &'a str) -> Result<impl Iterator<Item=String> + 'a> {
    let file = File::open(path)
        .with_context(|| format!("could not open file `{}`", path.display()))?;
    let results = BufReader::new(file)
        .lines()
        // Convert Iterator<Item=Result<T>> into  Iterator<Item=T>:
        //   https://stackoverflow.com/a/36371890/3592218
        // There are two *different* solutions: `filter_map` and `scan`.
        // >>> `filter_map`:
        .filter_map(|x| x.ok())
        // >>> `scan`:
        // .scan((), |_, x| x.ok())
        .filter(move |line| line.contains(pattern));
    Ok(results)
}