jiang_mini_grep/
lib.rs

1// use core::iter::traits::iterator;
2use std::error::Error;
3use std::{env, fs};
4
5pub struct Config {
6    pub query: String,
7    pub file_path: String,
8    pub ignore_case: bool,
9}
10
11impl Config {
12    pub fn build(mut args: impl Iterator<Item = String>) -> Result<Config, &'static str> {
13        args.next();
14
15        // let query = args[1].clone();
16        // let file_path = args[2].clone();
17        // let ignore_case = env::var("IGNORE_CASE").is_ok();
18
19        let query = match args.next() {
20            Some(arg) => arg,
21            None => return Err("Didn't get a query string"),
22        };
23
24        let file_path = match args.next() {
25            Some(arg) => arg,
26            None => return Err("Didn't get a file path"),
27        };
28
29        let ignore_case = env::var("IGNORE_CASE").is_ok();
30
31        Ok(Config {
32            query,
33            file_path,
34            ignore_case,
35        })
36    }
37}
38
39pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
40    let contents = fs::read_to_string(config.file_path)?;
41
42    let results = if config.ignore_case {
43        search_case_insensitive(&config.query, &contents)
44    } else {
45        search(&config.query, &contents)
46    };
47
48    for line in results {
49        println!("{line}");
50    }
51
52    Ok(())
53}
54pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
55    contents
56        .lines()
57        .filter(|line| line.contains(query))
58        .collect()
59}
60
61pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
62    let query = query.to_lowercase();
63    let mut results = Vec::new();
64
65    for line in contents.lines() {
66        if line.to_lowercase().contains(&query) {
67            results.push(line);
68        }
69    }
70
71    results
72}
73
74#[cfg(test)]
75mod tests {
76
77    #[test]
78    fn one_result() {
79        let query = "safe";
80        let contents = "\
81Rust:
82safe, fast, productive.
83Pick three.";
84
85        assert_eq!(
86            vec!["safe, fast, productive."],
87            crate::search(query, contents)
88        );
89    }
90
91    #[test]
92    fn case_insensitive() {
93        let query = "rUsT";
94        let contents = "\
95Rust:
96safe, fast, productive.
97Pick three.
98Trust me.";
99
100        assert_eq!(
101            vec!["Rust:", "Trust me."],
102            crate::search_case_insensitive(query, contents)
103        );
104    }
105}