use std::path::Path;
#[macro_export]
macro_rules! hash {
($($await:ident)? : $Hasher:ty, $reader:expr $(,$write:ident)?) => {{
let mut hasher = <$Hasher>::new();
let mut reader = $reader;
let mut buf = [0; 16384];
let mut len:usize = 0;
loop {
let n = reader.read(&mut buf)$(.$await)??;
if n == 0 {
break;
}
len+=n;
let bin = &buf[..n];
hasher.update(bin);
$(let _ = $write.write(bin)?;)?
}
(hasher,len)
}};
}
pub async fn hash<H: digest::Digest>(path: impl AsRef<Path>) -> Result<H, std::io::Error> {
use tokio::{fs::File, io::AsyncReadExt};
let file = File::open(path).await?;
Ok(hash!(await: H, file).0)
}
pub fn hash_len(path: impl AsRef<Path>) -> Result<([u8; 32], usize), std::io::Error> {
use std::io::Read;
let file = std::fs::File::open(path)?;
let (hash, len) = hash!(: blake3::Hasher, file);
Ok((*hash.finalize().as_bytes(), len))
}