1use std::fs;
2use std::error::Error;
3use std::env;
4
5pub fn run(config:&Config)->Result<(), Box<dyn Error>> {
6 let contents = fs::read_to_string(&config.filename)?;
7 if config.case_sensitive{
8 for line in search(&config.query, &contents) {
9 println!("{}", line);
10 }
11 }
12 else{
13 for line in search_case_insensitive(&config.query, &contents) {
14 println!("{}", line);
15 }
16 }
17 Ok(())
18}
19
20pub struct Config {
21 pub query: String,
22 pub filename: String,
23 pub case_sensitive:bool,
24}
25
26impl Config {
27 pub fn new(mut args: std::env::Args)->Result<Config,&'static str>{
28 if args.len() < 3 {
29 return Err("Not enough arguement");
30 }
31 args.next();
32 let query = match args.next(){
33 Some(arg) => arg,
34 None => return Err("Didn't get a query string"),
35 };
36 let filename = match args.next(){
37 Some(arg) => arg,
38 None => return Err("Didn't get a query string"),
39 };
40 let case_sensitive = env::var("CASE_INSENSITIVE").is_err();
41 return Ok(Config { query, filename,case_sensitive })
42 }
43}
44
45
46pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
47 contents.lines()
48 .filter(|line| line.contains(query))
49 .collect()
50}
51pub fn search_case_insensitive<'a>(query: &str,contents: &'a str) ->Vec<&'a str>{
52 let query = query.to_lowercase();
53 contents.lines()
54 .filter(|line| line.to_lowercase().contains(&query))
55 .collect()
56}
57#[cfg(test)]
58mod tests {
59 use super::*;
60
61 #[test]
62 fn case_insensitive(){
63 let query = "rUsT";
64 let contents = "\
65Rust:
66safe, fast, productive.
67Pick three.
68Trust me.";
69
70 assert_eq!(
71 vec!["Rust:", "Trust me."],
72 search_case_insensitive(query, contents)
73 );
74 }
75 #[test]
76 fn case_sensitive(){
77 let query = "duct";
78 let contents = "\
79Rust:
80safe, fast, productive.
81Pick three.
82Duct tape.";
83
84 assert_eq!(
85 vec!["safe, fast, productive."],
86 search(query, contents)
87 );
88 }
89
90}
91
92
93
94