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