diff options
Diffstat (limited to 'src/chunker.rs')
-rw-r--r-- | src/chunker.rs | 58 |
1 files changed, 43 insertions, 15 deletions
diff --git a/src/chunker.rs b/src/chunker.rs index 145b1db..9883f89 100644 --- a/src/chunker.rs +++ b/src/chunker.rs @@ -1,30 +1,54 @@ -use crate::checksummer::sha256; +//! Split file data into chunks. + use crate::chunk::DataChunk; use crate::chunkmeta::ChunkMeta; +use crate::label::{Label, LabelChecksumKind}; use std::io::prelude::*; +use std::path::{Path, PathBuf}; -pub struct Chunker { +/// Iterator over chunks in a file. +pub struct FileChunks { chunk_size: usize, + kind: LabelChecksumKind, buf: Vec<u8>, + filename: PathBuf, handle: std::fs::File, } -impl Chunker { - pub fn new(chunk_size: usize, handle: std::fs::File) -> Self { - let mut buf = vec![]; - buf.resize(chunk_size, 0); +/// Possible errors from data chunking. +#[derive(Debug, thiserror::Error)] +pub enum ChunkerError { + /// Error reading from a file. + #[error("failed to read file {0}: {1}")] + FileRead(PathBuf, std::io::Error), +} + +impl FileChunks { + /// Create new iterator. + pub fn new( + chunk_size: usize, + handle: std::fs::File, + filename: &Path, + kind: LabelChecksumKind, + ) -> Self { + let buf = vec![0; chunk_size]; Self { chunk_size, + kind, buf, handle, + filename: filename.to_path_buf(), } } - pub fn read_chunk(&mut self) -> anyhow::Result<Option<(ChunkMeta, DataChunk)>> { + fn read_chunk(&mut self) -> Result<Option<DataChunk>, ChunkerError> { let mut used = 0; loop { - let n = self.handle.read(&mut self.buf.as_mut_slice()[used..])?; + let n = self + .handle + .read(&mut self.buf.as_mut_slice()[used..]) + .map_err(|err| ChunkerError::FileRead(self.filename.to_path_buf(), err))?; used += n; if n == 0 || used == self.chunk_size { break; @@ -36,20 +60,24 @@ impl Chunker { } let buffer = &self.buf.as_slice()[..used]; - let hash = sha256(buffer); + let hash = match self.kind { + LabelChecksumKind::Blake2 => Label::blake2(buffer), + LabelChecksumKind::Sha256 => Label::sha256(buffer), + }; let meta = ChunkMeta::new(&hash); - let chunk = DataChunk::new(buffer.to_vec()); - Ok(Some((meta, chunk))) + let chunk = DataChunk::new(buffer.to_vec(), meta); + Ok(Some(chunk)) } } -impl Iterator for Chunker { - type Item = anyhow::Result<(ChunkMeta, DataChunk)>; +impl Iterator for FileChunks { + type Item = Result<DataChunk, ChunkerError>; - fn next(&mut self) -> Option<anyhow::Result<(ChunkMeta, DataChunk)>> { + /// Return the next chunk, if any, or an error. + fn next(&mut self) -> Option<Result<DataChunk, ChunkerError>> { match self.read_chunk() { Ok(None) => None, - Ok(Some((meta, chunk))) => Some(Ok((meta, chunk))), + Ok(Some(chunk)) => Some(Ok(chunk)), Err(e) => Some(Err(e)), } } |