3

I was attempting to use twox-hash to generate a hash for a file, as it seemed to be the fastest hash implementation around and security is not a concern for this implementation.

To get it to work with a reader, I implemented a wrapper struct that implemented the Write trait and directly called XxHash::write from the Hash trait. Is there a more elegant or standard way of doing this?

#[derive(Deref)]
struct HashWriter<T: Hasher>(T);

impl<T: Hasher> std::io::Write for HashWriter<T> {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        self.0.write(buf);
        Ok(buf.len())
    }

    fn flush(&mut self) -> std::io::Result<()> {
        Ok(())
    }
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
spease
  • 686
  • 6
  • 15

1 Answers1

4

That's what I would do, although I'd also implement write_all as it can be equally as simple:

use std::{hash::Hasher, io};

struct HashWriter<T: Hasher>(T);

impl<T: Hasher> io::Write for HashWriter<T> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf);
        Ok(buf.len())
    }

    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
        self.write(buf).map(|_| ())
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

You can then use it like:

use std::fs::File;
use twox_hash::XxHash64;

fn main() {
    let mut f = File::open("/etc/hosts").expect("Unable to open file");

    let hasher = XxHash64::with_seed(0);
    let mut hw = HashWriter(hasher);

    io::copy(&mut f, &mut hw).expect("Unable to copy data");

    let hasher = hw.0;
    println!("{}", hasher.finish());
}

Disclaimer: I am the author / porter of twox-hash.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • Any reason why you didn't implement `Write` directly? – Stefan Jan 31 '18 at 09:27
  • Good point about write_all. Is there a particular reason that this isn't integrated into the std hash library so you can use a reader/writer with any hash? – spease Feb 01 '18 at 21:00
  • @Stefan just because it doesn't really feel like the "right" thing to do for a hasher. – Shepmaster Feb 01 '18 at 23:43
  • @spease If you cannot find an existing one, I'd say you should publish your shim to crates.io. It can wrap any type that implements `Hasher` and be generally useful. I don't know the reason, but having easily accessible crates lowers the rationale to have it in the standard library. – Shepmaster Feb 01 '18 at 23:44