extern crate sha2; extern crate async_std; use sha2::{Sha256, Digest}; use async_std::io::ReadExt; pub struct FileHash([u8; 32]); fn copy_slice(src: &[T], dst: &mut [T]) -> usize { let mut c =0; for (d, s) in dst.iter_mut().zip(src.iter()) { *d = *s; c += 1; } c } const BLOCK_SIZE: usize = 32; async fn copy_to_hash(src: &mut async_std::fs::File, mut do_block: F) -> Result { assert!(BLOCK_SIZE>0); let mut res: usize =0; let mut buf: [u8; BLOCK_SIZE] = [0; BLOCK_SIZE]; loop { let n = src.read(&mut buf).await?; if n == 0 { break; } do_block(&buf[..n]); res+=n; } Ok(res) } impl FileHash { pub fn create(file: &mut std::fs::File) -> Result { let mut hash = Sha256::default(); std::io::copy(file, &mut hash)?; let mut u: [u8; 32] = [0; 32]; copy_slice(&hash.result()[..], &mut u); Ok(Self(u)) } pub async fn create_async(file: &mut async_std::fs::File) -> Result { let mut hash = Sha256::default(); //async_std::io::copy(file, &mut hash).await?; copy_to_hash(file, |buffer| { &hash.input(buffer); }).await?; let mut u: [u8; 32] = [0; 32]; copy_slice(&hash.result()[..], &mut u); Ok(Self(u)) } pub fn iter(&self) -> std::slice::Iter { self.0.iter() } pub fn iter_mut(&mut self) -> std::slice::IterMut { self.0.iter_mut() } } impl Clone for FileHash { fn clone(&self) -> Self { let mut u: [u8; 32] = [0; 32]; copy_slice(&self.0, &mut u); Self(u) } } impl AsRef<[u8; 32]> for FileHash { fn as_ref(&self) -> &[u8; 32] { &self.0 } } impl AsMut<[u8; 32]> for FileHash { fn as_mut(&mut self) -> &mut [u8; 32] { &mut self.0 } } impl Default for FileHash { fn default() -> Self { Self([0; 32]) } } fn hex_string(bytes: &[u8]) -> String { bytes.iter().map(|x| format!("{:02x}", x)).collect::() } impl std::fmt::Display for FileHash { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", hex_string(&self.0)) } } impl std::cmp::PartialEq for FileHash { fn eq(&self, other: &Self) -> bool { self.0.iter() .zip(other.0 .iter()) .map(|(x, y)| x^y) .fold(0, |x, y| x|y) == 0 } } impl std::cmp::Eq for FileHash{} impl<'a> IntoIterator for &'a mut FileHash { type Item = &'a mut u8; type IntoIter = std::slice::IterMut<'a, u8>; fn into_iter(self) -> Self::IntoIter { self.0.iter_mut() } } impl<'a> IntoIterator for &'a FileHash { type Item = &'a u8; type IntoIter = std::slice::Iter<'a, u8>; fn into_iter(self) -> Self::IntoIter { self.0.iter() } }