hello_rust_spanti/
lib.rs

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