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