use std::{error::Error, fs, env::{self, Args}}; pub struct Config { query: String, filename: String, case_sensitive: bool, } impl Config { pub fn new(mut args: env::Args) -> Result { if args.len() < 3 { return Err("not enough arguments!"); } args.next(); let query = match args.next() { Some(arg) => arg, None => return Err("Didn't get a query string"), }; let filename = match args.next() { Some(arg) => arg, None => return Err("Didn't get a query string"), }; let case_sensitive = env::var("CASE_INSENTSITIVE").is_err(); Ok(Config { query, filename, case_sensitive }) } } pub fn run(config: Config) -> Result<(), Box> { let contents = fs::read_to_string(config.filename)?; let result = if config.case_sensitive { search(&config.query, &contents) } else { search_case_insensitive(&config.query, &contents) }; for line in result { println!("{}", line); } Ok(()) } fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { contents.lines().filter(|line| line.contains(query)).collect() } fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { let mut results = Vec::new(); let query = query.to_lowercase(); for line in contents.lines() { if line.to_lowercase().contains(&query) { results.push(line); } } results } #[cfg(test)] mod tests { use crate::{search, search_case_insensitive}; #[test] fn case_sensitive() { let query = "Rust"; let contents = "\ Rust: safe, fast, productive. Pick three. Trust me"; assert_eq!(vec!["Rust:"], search(query, contents)) } #[test] fn case_insensitive() { let query = "Rust"; let contents = "\ Rust: safe, fast, productive. Pick three. Trust me"; assert_eq!( vec!["Rust:", "Trust me"], search_case_insensitive(query, contents) ) } }