filehasher/
filehasher.rs

1use std::{
2    hash::{DefaultHasher, Hasher},
3    io::{self, Read, Seek, SeekFrom, Write},
4};
5
6/// * Copy data from a reader to a writer from the current position.
7pub fn copy<R, W>(reader: &mut R, writer: &mut W, bytes_to_copy: u64) -> io::Result<()>
8where
9    R: Read,
10    W: Write,
11{
12    const BUFFER_SIZE: u64 = 1024;
13    let mut buf = vec![0u8; BUFFER_SIZE as usize];
14    let mut to_copy = bytes_to_copy;
15    while to_copy >= BUFFER_SIZE {
16        reader.read_exact(&mut buf)?;
17        writer.write_all(&buf)?;
18        to_copy -= BUFFER_SIZE;
19    }
20    if to_copy > 0 {
21        buf.resize(to_copy as usize, 0);
22        reader.read_exact(&mut buf)?;
23        writer.write_all(&buf)?;
24    }
25    Ok(())
26}
27
28/// * File hasher to calculate the hash for a section of a file, the hash is `u64` size. The `Write` trait was implemented for it.
29#[derive(Default, Debug, Clone)]
30pub struct FileHasher {
31    hasher: DefaultHasher,
32}
33
34impl FileHasher {
35    pub fn new() -> Self {
36        Self {
37            hasher: DefaultHasher::new(),
38        }
39    }
40
41    /// * Calculate the hash of the data from the `reader` with offset `from_byte` and length `length`, consumes it self
42    pub fn hash<R>(mut self, reader: &mut R, from_byte: u64, length: u64) -> io::Result<u64>
43    where
44        R: Read + Seek,
45    {
46        reader.seek(SeekFrom::Start(from_byte))?;
47        copy(reader, &mut self, length)?;
48        Ok(self.hasher.finish())
49    }
50
51    /// * If you are using its `Write` trait, call this function to get the hash.
52    pub fn finish(self) -> u64 {
53        self.hasher.finish()
54    }
55}
56
57impl Write for FileHasher {
58    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
59        self.hasher.write(buf);
60        Ok(buf.len())
61    }
62
63    fn flush(&mut self) -> io::Result<()> {
64        Ok(())
65    }
66}