1use std::env;
7use std::error::Error;
8use std::fs::File;
9use std::io::prelude::*;
10
11pub struct Config {
25 pub query: String,
27 pub filename: String,
29 pub case_sensitive: bool,
31}
32
33impl Config {
34 pub fn new(mut args: std::env::Args) -> Result<Config, &'static str> {
40 args.next();
41
42 let query = match args.next() {
43 Some(arg) => arg,
44 None => return Err("Didn't get a query string"),
45 };
46
47 let filename = match args.next() {
48 Some(arg) => arg,
49 None => return Err("Didn't get a file name"),
50 };
51
52 let case_sensitive = env::var("CASE_INSENSITIVE").is_err();
54
55 Ok(Config {
56 query,
57 filename,
58 case_sensitive,
59 })
60 }
61}
62
63pub fn run(config: Config) -> Result<(), Box<Error>> {
64 let mut f = File::open(config.filename)?;
65
66 let mut contents = String::new();
67 f.read_to_string(&mut contents)?;
68
69 let results = if config.case_sensitive {
70 search(&config.query, &contents)
71 } else {
72 search_case_insensitive(&config.query, &contents)
73 };
74
75 for line in results {
76 println!("{}", line);
77 }
78
79 Ok(())
80}
81
82pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
83 contents
84 .lines()
85 .filter(|line| line.contains(query))
86 .collect()
87}
88
89fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
90 let query = query.to_lowercase();
91 let mut results = Vec::new();
92
93 for line in contents.lines() {
94 if line.to_lowercase().contains(&query) {
95 results.push(line);
96 }
97 }
98
99 results
100}
101
102#[cfg(test)]
103mod test {
104 use super::*;
105
106 #[test]
107 fn case_sensitive() {
108 let query = "duct";
109 let contents = "\
110Rust:
111safe, fast, productive.
112Pick three.";
113
114 assert_eq!(vec!["safe, fast, productive."], search(query, contents));
115 }
116
117 #[test]
118 fn case_insensitive() {
119 let query = "rUsT";
120 let contents = "\
121Rust:
122safe, fast, productive.
123Pick three.
124Trust me.";
125
126 assert_eq!(
127 vec!["Rust:", "Trust me."],
128 search_case_insensitive(query, contents)
129 );
130 }
131}