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