diff --git a/src/job.rs b/src/job.rs index ee7f605..c03171a 100644 --- a/src/job.rs +++ b/src/job.rs @@ -104,6 +104,22 @@ impl Read for Job } } +/// Create a job description for this opened input +/// +/// `sz` is the offset of the *end* of the last job. (or 0 for the first). +/// `sz` is then updated with this file's size for this method to be used again on the next file. +pub fn create(file_num: usize, open::Input(file, stat): open::Input, sz: &mut usize) -> Prelude +{ + let offset = *sz; + + let prelude = Prelude { + file, stat, offset, file_num + }; + *sz += prelude.len(); + + prelude +} + /// Create a job description for this file. /// /// `sz` is the offset of the *end* of the last job. (or 0 for the first). diff --git a/src/main.rs b/src/main.rs index 1246355..ec910e1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,6 +26,7 @@ mod map; mod job; mod work; mod arg; + mod open; mod consts; @@ -36,6 +37,7 @@ fn work(arg::Operation{output, inputs}: arg::Operation) -> Result<(), Box Result + { + let stat = file.metadata().map_err(InputError::Stat)?; + Ok(Self(file,stat)) + } + + /// Open an input file + pub fn open(filename: impl AsRef) -> Result + { + let file = fs::OpenOptions::new() + .read(true) + .open(filename).map_err(InputError::Open)?; + + Self::try_from_file(file) + } +} + +/// Open all these inputs and return them. +/// +/// If one or more fail, then the operation will terminate early and return the error. +pub fn input + fmt::Debug, I>(inputs: I) -> Result, InputError> +where I: IntoIterator +{ + let inputs = inputs.into_iter(); + let mut outputs = { + match inputs.size_hint() { + (0, Some(0)) => Vec::default(), + (0, None) => Vec::new(), + (_, Some(x)) | (x, None) => Vec::with_capacity(x), + } + }; + for input in inputs + { + outputs.push(Input::open(&input) + .map_err(move |inner| InputError::WithData(Box::new(inner), input))?); + } + Ok(outputs) +} + +#[derive(Debug)] + #[non_exhaustive] +pub enum InputError +where T: fmt::Debug +{ + Open(io::Error), + Stat(io::Error), + + WithData(Box, T), +} +impl error::Error for InputError +where T: fmt::Debug +{ + fn source(&self) -> Option<&(dyn error::Error + 'static)> + { + match &self { + Self::Open(io) | Self::Stat(io) => Some(io), + Self::WithData(inner, _) => inner.source(), + } + } +} +impl fmt::Display for InputError +where T: fmt::Debug +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + match self { + Self::Open(io) => write!(f, "failed to open file for reading: {}", io), + Self::Stat(io) => write!(f, "failed to stat file: {}", io), + Self::WithData(inner, msg) => write!(f, "for {:?}: {}", msg, inner), + } + } +} +