1use std::env;
3use std::fs::File;
4use std::io::Read;
5use std::env::Args;
6use std::error::Error;
7
8pub struct Config {
10 query: String,
11 filename: String,
12 case_sensitive: bool,
13}
14
15impl Config {
16 pub fn new(mut args: Args) -> Result<Config, &'static str> {
17 args.next();
18
19 let _query = match args.next() {
20 Some(v) => v,
21 None => return Err("Didnt get query to search for")
22 };
23
24 let _filename = match args.next() {
25 Some(v) => v,
26 None => return Err("Didnt get filename for searching")
27 };
28
29 let _case_sensitive = env::var("CASE_INSENSITIVE").is_err();
30
31 return Result::Ok(
32 Config {
33 query: _query,
34 filename: _filename,
35 case_sensitive: _case_sensitive,
36 }
37 );
38 }
39}
40
41pub fn run(config: Config) -> Result<(), Box<Error>> {
43 let mut file = File::open(config.filename.clone())?;
44 let mut content = String::new();
45
46 file.read_to_string(&mut content)?;
47
48 let results = if config.case_sensitive {
49 search_sensitive(&config.query, &content)
50 } else {
51 search_insensitive(&config.query, &content)
52 };
53
54 for result in results {
55 println!("{}", result);
56 }
57
58 Ok(())
59}
60
61pub fn search_sensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
63 contents.lines().filter(|line| line.contains(query)).collect()
64}
65
66pub fn search_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
68 let query = query.to_lowercase();
69 contents.lines().filter(|line| line.contains(&query)).collect()
70}
71
72
73#[cfg(test)]
74mod test {
75 use crate::*;
76
77 #[test]
78 fn case_sensitive() {
79 let query = "duct";
80 let contents = "Rust:\nsafe, fast, productive\nPick three\nDuct Tape";
81 assert_eq!(vec!["safe, fast, productive"], search_sensitive(query, contents));
82 }
83
84 #[test]
85 fn case_insensitive() {
86 let query = "rUsT";
87 let contents = "Rust:\nsafe, fast, productive\nPick three.\nTrust me";
88 assert_eq!(vec!["Rust:", "Trust me"], search_insensitive(query, contents));
89 }
90}