1use std::{fs, error::Error, env};
6
7
8pub struct Config {
9 pub query: String,
10 pub filename: String,
11 pub case_sensitive: bool,
12}
13
14impl Config {
15 pub fn new(args: &[String]) -> Result<Config, &'static str> {
16 if args.len() < 3{
17 return Err("not enough arguments");
18 }
19 let str = &args[1];
20 let file = &args[2];
21 let case_sensitive = env::var("CASE_INSENSITIVE").is_err();
22 println!("{} at {}", str, file);
23
24 Ok(Config {
25 query: str.to_string(),
26 filename: file.to_string(),
27 case_sensitive,
28 })
29 }
30}
31
32
33pub fn find_query_in_file(config: &Config) -> Result<(), Box<dyn Error>> {
34 let contents =
35 fs::read_to_string(&config.filename)?;
36 println!("With text:\n{}", contents);
37 if config.case_sensitive {
38 for line in search(&config.query, &contents) {
39 println!("{}", line);
40 }
41 } else {
42 for line in search_case_insensitive(&config.query, &contents) {
43 println!("{}", line);
44 }
45 }
46
47 Ok(())
48}
49
50pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
51 contents.lines()
52 .filter(|line| line.contains(query))
53 .collect()
54}
55
56pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
72 let lowercase_query = query.to_lowercase();
73 contents.lines()
74 .filter(|line| line.to_lowercase().contains(&lowercase_query))
75 .collect()
76}
77
78#[cfg(test)]
79mod test {
80 use super::*;
81
82 #[test]
83 fn test_search() {
84 let query = "duct";
85 let contents = "\
86Rust:
87safe, fast, productive.
88Pick three.";
89 assert_eq!(
90 vec!["safe, fast, productive."],
91 search(query, contents)
92 );
93 }
94
95 #[test]
96 fn test_search_case_insensitive() {
97 let query = "rUsT";
98 let contents = "\
99Rust:
100safe, fast, productive.
101Pick three.
102Trust me.";
103 assert_eq!(
104 vec!["Rust:", "Trust me."],
105 search_case_insensitive(query, contents)
106 );
107 }
108}