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