pub trait Hasher {
Show 16 methods
fn finish(&self) -> u64;
fn write(&mut self, bytes: &[u8]);
fn write_u8(&mut self, i: u8) { ... }
fn write_u16(&mut self, i: u16) { ... }
fn write_u32(&mut self, i: u32) { ... }
fn write_u64(&mut self, i: u64) { ... }
fn write_u128(&mut self, i: u128) { ... }
fn write_usize(&mut self, i: usize) { ... }
fn write_i8(&mut self, i: i8) { ... }
fn write_i16(&mut self, i: i16) { ... }
fn write_i32(&mut self, i: i32) { ... }
fn write_i64(&mut self, i: i64) { ... }
fn write_i128(&mut self, i: i128) { ... }
fn write_isize(&mut self, i: isize) { ... }
fn write_length_prefix(&mut self, len: usize) { ... }
fn write_str(&mut self, s: &str) { ... }
}
Expand description
A trait for hashing an arbitrary stream of bytes.
Instances of Hasher
usually represent state that is changed while hashing
data.
Hasher
provides a fairly basic interface for retrieving the generated hash
(with finish
), and writing integers as well as slices of bytes into an
instance (with write
and write_u8
etc.). Most of the time, Hasher
instances are used in conjunction with the Hash
trait.
This trait provides no guarantees about how the various write_*
methods are
defined and implementations of Hash
should not assume that they work one
way or another. You cannot assume, for example, that a write_u32
call is
equivalent to four calls of write_u8
. Nor can you assume that adjacent
write
calls are merged, so it’s possible, for example, that
hasher.write(&[1, 2]);
hasher.write(&[3, 4, 5, 6]);
Runand
hasher.write(&[1, 2, 3, 4]);
hasher.write(&[5, 6]);
Runend up producing different hashes.
Thus to produce the same hash value, Hash
implementations must ensure
for equivalent items that exactly the same sequence of calls is made – the
same methods with the same parameters in the same order.
Examples
use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;
let mut hasher = DefaultHasher::new();
hasher.write_u32(1989);
hasher.write_u8(11);
hasher.write_u8(9);
hasher.write(b"Huh?");
println!("Hash is {:x}!", hasher.finish());
RunRequired Methods
Returns the hash value for the values written so far.
Despite its name, the method does not reset the hasher’s internal
state. Additional write
s will continue from the current value.
If you need to start a fresh hash value, you will have to create
a new hasher.
Examples
use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;
let mut hasher = DefaultHasher::new();
hasher.write(b"Cool!");
println!("Hash is {:x}!", hasher.finish());
RunWrites some data into this Hasher
.
Examples
use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;
let mut hasher = DefaultHasher::new();
let data = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];
hasher.write(&data);
println!("Hash is {:x}!", hasher.finish());
RunNote to Implementers
You generally should not do length-prefixing as part of implementing
this method. It’s up to the Hash
implementation to call
Hasher::write_length_prefix
before sequences that need it.
Provided Methods
1.26.0 · sourcefn write_u128(&mut self, i: u128)
fn write_u128(&mut self, i: u128)
Writes a single u128
into this hasher.
1.3.0 · sourcefn write_usize(&mut self, i: usize)
fn write_usize(&mut self, i: usize)
Writes a single usize
into this hasher.
1.26.0 · sourcefn write_i128(&mut self, i: i128)
fn write_i128(&mut self, i: i128)
Writes a single i128
into this hasher.
1.3.0 · sourcefn write_isize(&mut self, i: isize)
fn write_isize(&mut self, i: isize)
Writes a single isize
into this hasher.
sourcefn write_length_prefix(&mut self, len: usize)
fn write_length_prefix(&mut self, len: usize)
hasher_prefixfree_extras
#96762)Writes a length prefix into this hasher, as part of being prefix-free.
If you’re implementing Hash
for a custom collection, call this before
writing its contents to this Hasher
. That way
(collection![1, 2, 3], collection![4, 5])
and
(collection![1, 2], collection![3, 4, 5])
will provide different
sequences of values to the Hasher
The impl<T> Hash for [T]
includes a call to this method, so if you’re
hashing a slice (or array or vector) via its Hash::hash
method,
you should not call this yourself.
This method is only for providing domain separation. If you want to
hash a usize
that represents part of the data, then it’s important
that you pass it to Hasher::write_usize
instead of to this method.
Examples
#![feature(hasher_prefixfree_extras)]
use std::hash::{Hash, Hasher};
impl<T: Hash> Hash for MyCollection<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write_length_prefix(self.len());
for elt in self {
elt.hash(state);
}
}
}
RunNote to Implementers
If you’ve decided that your Hasher
is willing to be susceptible to
Hash-DoS attacks, then you might consider skipping hashing some or all
of the len
provided in the name of increased performance.
hasher_prefixfree_extras
#96762)Writes a single str
into this hasher.
If you’re implementing Hash
, you generally do not need to call this,
as the impl Hash for str
does, so you should prefer that instead.
This includes the domain separator for prefix-freedom, so you should
not call Self::write_length_prefix
before calling this.
Note to Implementers
There are at least two reasonable default ways to implement this. Which one will be the default is not yet decided, so for now you probably want to override it specifically.
The general answer
It’s always correct to implement this with a length prefix:
fn write_str(&mut self, s: &str) {
self.write_length_prefix(s.len());
self.write(s.as_bytes());
}
RunAnd, if your Hasher
works in usize
chunks, this is likely a very
efficient way to do it, as anything more complicated may well end up
slower than just running the round with the length.
If your Hasher
works byte-wise
One nice thing about str
being UTF-8 is that the b'\xFF'
byte
never happens. That means that you can append that to the byte stream
being hashed and maintain prefix-freedom:
fn write_str(&mut self, s: &str) {
self.write(s.as_bytes());
self.write_u8(0xff);
}
RunThis does require that your implementation not add extra padding, and
thus generally requires that you maintain a buffer, running a round
only once that buffer is full (or finish
is called).
That’s because if write
pads data out to a fixed chunk size, it’s
likely that it does it in such a way that "a"
and "a\x00"
would
end up hashing the same sequence of things, introducing conflicts.