#[cfg(test)]
mod tests;
use super::{ArtifactError, ArtifactIdentity, HashingWriter, visit_reader};
use std::{
fmt,
io::{self, Read, Write},
};
#[derive(Debug)]
pub enum CopyError {
Input(ArtifactError),
Output(io::Error),
}
impl fmt::Display for CopyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Input(source) => write!(f, "copy input failed: {source}"),
Self::Output(source) => write!(f, "copy output failed: {source}"),
}
}
}
impl std::error::Error for CopyError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Input(source) => Some(source),
Self::Output(source) => Some(source),
}
}
}
impl From<ArtifactError> for CopyError {
fn from(source: ArtifactError) -> Self {
Self::Input(source)
}
}
impl From<CopyError> for io::Error {
fn from(error: CopyError) -> Self {
match error {
CopyError::Input(ArtifactError::Io(source)) | CopyError::Output(source) => source,
other @ CopyError::Input(_) => Self::other(other),
}
}
}
pub fn copy_reader(
mut reader: impl Read,
writer: &mut impl Write,
max_bytes: u64,
) -> Result<ArtifactIdentity, CopyError> {
let mut writer = HashingWriter::new(writer, max_bytes);
visit_reader::<CopyError>(&mut reader, max_bytes, |chunk| {
writer.write_all(chunk).map_err(CopyError::Output)
})?;
Ok(writer.into_parts().1)
}