use std::fs; //use std::fs::File; //use std::io::prelude::*; use std::error::Error; use std::env; pub struct Config { query: String, filename: String, insensitive: bool, } pub fn run(conf: Config) -> Result<(), Box> { let contents = fs::read_to_string(conf.filename)?; let results = if conf.insensitive { search(&conf.query, &contents) } else { search_insensitive(&conf.query, &contents) }; for line in results { println!("{}", line); } Ok(()) } fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { let mut results = Vec::new(); for line in contents.lines() { if line.contains(query) { results.push(line); } } results } fn search_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { let query = query.to_lowercase(); let mut results = Vec::new(); for line in contents.lines() { if line.to_lowercase().contains(&query) { results.push(line); } } results } impl Config { pub fn new(args: &[String]) -> Result { if args.len() < 3 { return Err("too few arguments") } Ok(Config { query: args[1].clone(), filename: args[2].clone(), insensitive: env::var("CASE_INSENSITIVE").is_err(), }) } } #[cfg(test)] mod tests { use super::*; #[test] fn case_sensitive() { let query = "duct"; let contents = "\ Rust: safe, fast, productive. Pick three."; assert_eq!( vec!["safe, fast, productive."], 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_insensitive(query, contents) ); } }