You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

136 lines
2.7 KiB

extern crate sha2;
extern crate async_std;
use sha2::{Sha256, Digest};
use async_std::io::ReadExt;
pub struct FileHash([u8; 32]);
fn copy_slice<T: Copy>(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<F: FnMut(&[u8])>(src: &mut async_std::fs::File, mut do_block: F) -> Result<usize, async_std::io::Error>
{
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<Self, std::io::Error> {
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<Self, async_std::io::Error> {
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<u8>
{
self.0.iter()
}
pub fn iter_mut(&mut self) -> std::slice::IterMut<u8>
{
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::<String>()
}
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()
}
}