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