1use std::error::Error;
7use std::fs;
8use std::env;
9
10pub fn add_one(x: i32) -> i32 {
22 x + 1
23}
24
25
26pub struct Config {
27 pub query: String,
28 pub filename: String,
29 pub case_sensitive:bool
30}
31
32impl Config {
33 pub fn new(mut args: env::Args) -> Result<Config, &'static str> {
34 args.next();
35 let query = match args.next() {
36 Some(arg) => arg,
37 None => return Err("Didn't get a query string")
38 };
39 let filename = match args.next() {
40 Some(arg) => arg,
41 None => return Err("Didn't get filename string")
42 };
43 let case_sensitive = env::var("CASE_INSENSITIVE").is_err();
44 Ok(Config { query, filename ,case_sensitive})
45 }
46}
47
48pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
49 let contents = fs::read_to_string(config.filename)?;
50
51 let results = if config.case_sensitive {
52 search(&config.query, &contents)
53 }else{
54 search_case_insensitive(&config.query, &contents)
55 };
56
57 for line in results {
58 println!("{}", line)
59 }
60
61 Ok(())
62}
63
64
65pub fn search<'a>(query:&str,contents:&'a str) -> Vec<&'a str> {
81 contents.lines().into_iter().filter(|line| line.contains(query)).collect()
82}
83
84pub fn search_case_insensitive<'a>(query:&str, contents:&'a str) -> Vec<&'a str> {
85 contents.lines().into_iter()
86 .filter(|line| line.to_lowercase().contains(&(query.to_lowercase())))
87 .collect()
88}
89
90
91#[cfg(test)]
92mod tests {
93
94 use crate::*;
95
96 #[test]
97 fn case_sensitive(){
98 let query = "duct";
99 let contents = "\
100Rust:
101safe, fast, productive.
102Pick three.
103Duct tape.";
104
105 assert_eq!(vec!["safe, fast, productive."], search(query, contents));
106 }
107
108
109 #[test]
110 fn case_insensitive(){
111 let query = "rUsT";
112 let contents = "\
113Rust:
114safe, fast, productive.
115Pick three.
116Trust me.";
117
118 assert_eq!(
119 vec!["Rust:", "Trust me."],
120 search_case_insensitive(query, contents)
121 );
122 }
123
124}