diff --git a/Cargo.toml b/Cargo.toml index a1be1a0..a131ac1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rust_util" -version = "0.2.6" +version = "0.3.0" authors = ["Hatter Jiang "] edition = "2018" description = "Hatter's Rust Util" diff --git a/README.md b/README.md index 75b3f12..ae91fdd 100644 --- a/README.md +++ b/README.md @@ -22,3 +22,8 @@ $ cargo update ``` +## Update Log + +* Jun 21, 2020 v0.3.0 + * add struct `JoinFilesReader` + diff --git a/src/util_file.rs b/src/util_file.rs index 47bce8f..1b6919b 100644 --- a/src/util_file.rs +++ b/src/util_file.rs @@ -1,7 +1,8 @@ use std::{ env, - fs, + fs::{self, File}, + io::{Lines, BufReader}, path::{Path, PathBuf}, }; @@ -13,6 +14,69 @@ use super::{ XResult, }; +pub struct JoinFilesReader { + files: Vec, + file_ptr: usize, + file_lines: Option>>>, +} + +fn open_file_as_lines(f: &str) -> XResult>> { + let f = File::open(&f)?; + let br = BufReader::new(f); + use std::io::BufRead; + Ok(br.lines()) +} + +impl JoinFilesReader { + + pub fn new(fns: &[&str]) -> XResult { + let mut files: Vec = vec![]; + for f in fns { + files.push(f.to_string()); + } + let file_ptr = 0; + let mut file_lines = None; + if !files.is_empty() { + file_lines = Some(Box::new(open_file_as_lines(&files[0])?)); + } + Ok(Self { + files, + file_ptr, + file_lines, + }) + } +} + +impl Iterator for JoinFilesReader { + type Item = XResult; + + fn next(&mut self) -> Option { + loop { + match self.file_lines { + Some(ref mut ln) => match ln.next() { + Some(r) => return Some(r.map_err(|e| e.into())), + None => { + self.file_ptr += 1; + self.file_lines = None; + if self.file_ptr >= self.files.len() { + return None; + } else { + // if open file failed, will not continue read files + self.file_lines = Some(Box::new(match open_file_as_lines(&self.files[self.file_ptr]) { + Ok(ln) => ln, Err(e) => return Some(Err(e)), + })); + } + }, + }, + None => return None, + } + if self.file_ptr >= self.files.len() { + return None; + } + } + } +} + pub fn locate_file(files: &[String]) -> Option { for f in files { match PathBuf::from(&resolve_file_path(f)) {