|
|
@ -102,3 +102,81 @@ impl fmt::Display for OutputError
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
|
|
|
pub struct Input(pub File, pub fs::Metadata);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl Input
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
fn try_from_file(file: File) -> Result<Self,InputError>
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
let stat = file.metadata().map_err(InputError::Stat)?;
|
|
|
|
|
|
|
|
Ok(Self(file,stat))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Open an input file
|
|
|
|
|
|
|
|
pub fn open(filename: impl AsRef<Path>) -> Result<Self, InputError>
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
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<U: AsRef<Path> + fmt::Debug, I>(inputs: I) -> Result<Vec<Input>, InputError<U>>
|
|
|
|
|
|
|
|
where I: IntoIterator<Item = U>
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
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<T = std::convert::Infallible>
|
|
|
|
|
|
|
|
where T: fmt::Debug
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Open(io::Error),
|
|
|
|
|
|
|
|
Stat(io::Error),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
WithData(Box<InputError>, T),
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> error::Error for InputError<T>
|
|
|
|
|
|
|
|
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<T> fmt::Display for InputError<T>
|
|
|
|
|
|
|
|
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),
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|