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