use std::io::{self, BufRead, Read};
use sha1::{Digest, Sha1};
use crate::{
hash::{HashKind, ObjectHash, get_hash_kind},
utils::HashAlgorithm,
};
pub struct Wrapper<R> {
inner: R,
hash: Option<HashAlgorithm>,
bytes_read: usize,
}
impl<R> Wrapper<R>
where
R: BufRead,
{
pub fn new(inner: R) -> Self {
Self {
inner,
hash: Some(match get_hash_kind() {
HashKind::Sha1 => HashAlgorithm::Sha1(Sha1::new()),
HashKind::Sha256 => HashAlgorithm::Sha256(sha2::Sha256::new()),
}), bytes_read: 0,
}
}
pub fn new_without_hash(inner: R) -> Self {
Self {
inner,
hash: None,
bytes_read: 0,
}
}
pub fn bytes_read(&self) -> usize {
self.bytes_read
}
pub fn final_hash(&self) -> ObjectHash {
match &self
.hash
.clone()
.expect("Wrapper::final_hash called while hash tracking is disabled")
{
HashAlgorithm::Sha1(hasher) => {
let re: [u8; 20] = hasher.clone().finalize().into(); ObjectHash::from_bytes(&re).unwrap()
}
HashAlgorithm::Sha256(hasher) => {
let re: [u8; 32] = hasher.clone().finalize().into(); ObjectHash::from_bytes(&re).unwrap()
}
}
}
}
impl<R> BufRead for Wrapper<R>
where
R: BufRead,
{
fn fill_buf(&mut self) -> io::Result<&[u8]> {
self.inner.fill_buf() }
fn consume(&mut self, amt: usize) {
let buffer = self.inner.fill_buf().expect("Failed to fill buffer");
if let Some(hash) = &mut self.hash {
match hash {
HashAlgorithm::Sha1(hasher) => hasher.update(&buffer[..amt]), HashAlgorithm::Sha256(hasher) => hasher.update(&buffer[..amt]), }
}
self.inner.consume(amt); self.bytes_read += amt;
}
}
impl<R> Read for Wrapper<R>
where
R: BufRead,
{
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let o = self.inner.read(buf)?; if let Some(hash) = &mut self.hash {
match hash {
HashAlgorithm::Sha1(hasher) => hasher.update(&buf[..o]), HashAlgorithm::Sha256(hasher) => hasher.update(&buf[..o]), }
}
self.bytes_read += o;
Ok(o) }
}
#[cfg(test)]
mod tests {
use std::io::{self, BufReader, Cursor, Read};
use sha1::{Digest, Sha1};
use crate::{
hash::{HashKind, ObjectHash, set_hash_kind_for_test},
internal::pack::wrapper::Wrapper,
};
fn wrapper_read(kind: HashKind) {
let _guard = set_hash_kind_for_test(kind);
let data = b"Hello, world!"; let cursor = Cursor::new(data.as_ref());
let buf_reader = BufReader::new(cursor);
let mut wrapper = Wrapper::new(buf_reader);
let mut buffer = vec![0; data.len()];
wrapper.read_exact(&mut buffer).unwrap();
assert_eq!(buffer, data);
}
#[test]
fn test_wrapper_read() {
wrapper_read(HashKind::Sha1);
wrapper_read(HashKind::Sha256);
}
fn wrapper_hash_with_kind(kind: HashKind) -> io::Result<()> {
let _guard = set_hash_kind_for_test(kind);
let data = b"Hello, world!";
let cursor = Cursor::new(data.as_ref());
let buf_reader = BufReader::new(cursor);
let mut wrapper = Wrapper::new(buf_reader);
let mut buffer = vec![0; data.len()];
wrapper.read_exact(&mut buffer)?;
let hash_result = wrapper.final_hash();
let expected_hash = match kind {
HashKind::Sha1 => ObjectHash::from_bytes(&Sha1::digest(data)).unwrap(),
HashKind::Sha256 => ObjectHash::from_bytes(&sha2::Sha256::digest(data)).unwrap(),
};
assert_eq!(hash_result, expected_hash);
Ok(())
}
#[test]
fn test_wrapper_hash() -> io::Result<()> {
wrapper_hash_with_kind(HashKind::Sha1)?;
wrapper_hash_with_kind(HashKind::Sha256)?;
Ok(())
}
}