/// Generic `Iterator` over implementor's of /// [`Entry`](trait.Entry.html)'s. /// /// # Examples /// /// #### Iterate over /etc/passwd printing usernames /// /// ``` /// use std::path::Path; /// use pgs_files::passwd::PasswdEntry; /// use pgs_files::Entries; /// /// for entry in Entries::::new(&Path::new("/etc/passwd")) { /// println!("{}", entry.name); /// } /// ``` use std::{ io::{BufRead,BufReader,Write}, fs::{OpenOptions,File}, path::Path, marker::PhantomData, num::ParseIntError, }; pub struct Entries { path: String, cursor: BufReader, marker: PhantomData, } impl Entries { pub fn new(file_path: &str) -> Entries { let file = Path::new(&file_path); if ! file.exists() { File::create(file).unwrap_or_else(|e|{ eprintln!("Error file: {}",e); std::process::exit(2) }); } let reader = BufReader::new(File::open(file).ok().unwrap()); Entries { path: file_path.to_owned(), cursor: reader, marker: PhantomData, } } pub fn append(&self, entry: String) -> anyhow::Result<()> { let file = Path::new(&self.path); if ! file.exists() { std::fs::write(file,format!("{}\n",entry).as_bytes())?; } else { let target_file = OpenOptions::new() .write(true) .append(true) // This is needed to append to file .open(&file); if let Ok(mut file) = target_file { file.write_all( format!("{}\n",entry).as_bytes())?; } } Ok(()) } pub fn write(&self, entries: &Vec) -> anyhow::Result<()> { let file = Path::new(&self.path); std::fs::write(file,format!("{}\n",entries.clone().join("\n")).as_bytes())?; // let target_file = OpenOptions::new() // .write(true) // .open(&file); // if let Ok(mut file) = target_file { // file.write_all(entries.clone().join("\n").as_bytes())?; // } Ok(()) } } impl Iterator for Entries { type Item = T; fn next(&mut self) -> Option { let mut line = String::new(); loop { // We might need to make multiple loops to drain off // comment lines. Start with an empty string per loop. line.clear(); match self.cursor.read_line(&mut line){ Ok(0) => return None, Ok(_) => (), _ => return None, } if line.starts_with("#") { continue; } match T::from_line(&line) { Ok(entry) => return Some(entry), // Parse Error. Just ignore this entry. _ => (), } } } } /// A Trait to represent an entry of data from an /// /etc/{`passwd`,`group`,`shadow`} file. pub trait Entry: Sized { fn from_line(line: &str) -> anyhow::Result; }