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
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()
|
|
}
|
|
}
|