Brian: yes, at the moment `#[deriving(Hash)]` does support more than SipHash. However this PR temporarily removes that feature to replace `#[allow(default_type_param_usage)]` with `#[feature(default_type_params)]`:
https://github.com/mozilla/rust/pull/12525 If we land that change, we could try two things. First, we could just turn on default_type_params permanently. Second, we could allow a syntax extension to check if a feature has been enabled in a crate. Brian, I know you were talking about this earlier on IRC, did you end up making a decision on what to do? György: Yep, there is. I went through approximately 13 iterations to converge on this design :) The reason why the `impl`'s need to know what kind of state they are dealing with is to support custom hashers. In most cases, people will want to compute a hash over the bytes of a value, so that value's hash impl needs to know that it can pass the value's bytes in with `state.write(...)`. Other values may actually have a hash baked into them, or want to use an integer value as a hash. These can just return the hash value by directly assigning the hash to the `*state` as I did in the example. While not cryptographically safe, this can be dramatically faster than using something like SipHash. Yet another value may want to use two completely different hashing algorithms depending depending on some property. Letting the `Hash`ee know about the state type allows for this level of flexibility. It also adds some type safety, in that it'll prevent you from accidentally passing a `Writer`-based hash state into a type that should only be used with a specific hasher. On Mon, Feb 24, 2014 at 9:35 PM, Niko Matsakis <[email protected]> wrote: > This looks very cool. > > > On Mon, Feb 24, 2014 at 11:31:19AM -0500, Erick Tryzelaar wrote: > > I'm happy to announce that Rust's new hashing framework has landed in: > > > > https://github.com/mozilla/rust/pull/11863 > > https://github.com/mozilla/rust/pull/12492 > > > > This PR has has changed how to declare a type is hashable. Here's a full > > example on how to hash a value using either the new `#[deriving(Hash)]` > or > > manual implementation. > > > > ``` > > use std::hash::{Hash, hash}; > > use std::hash::sip::SipState; > > > > #[deriving(Hash)] > > struct Foo { > > a: ~str, > > b: uint, > > c: bool, > > } > > > > struct Bar { > > a: ~str, > > b: uint, > > c: bool, > > } > > > > impl Hash for Bar { > > fn hash(&self, state: &mut SipState) { > > self.a.hash(state); > > self.b.hash(state); > > self.c.hash(state); > > } > > } > > > > fn main() { > > let foo = Foo { a: ~"hello world", b: 5, c: true }; > > println!("{}", hash(&foo)); > > > > let bar = Bar { a: ~"hello world", b: 5, c: true }; > > println!("{}", hash(&bar)); > > } > > ``` > > > > We also have experimental support for hashers that compute a value off a > > stream of bytes: > > > > ``` > > use std::hash::{Hash, Hasher}; > > use std::io::IoResult; > > > > #[deriving(Hash)] // automatically provides hashing from a stream of > bytes > > struct Foo { > > a: ~str, > > b: uint, > > c: bool, > > } > > > > struct Bar { > > a: ~str, > > b: uint, > > c: bool, > > } > > > > #[allow(default_type_param_usage)] > > impl<S: Writer> Hash<S> for Bar { > > fn hash(&self, state: &mut S) { > > self.a.hash(state); > > self.b.hash(state); > > self.c.hash(state); > > } > > } > > > > struct SumState { > > sum: u64, > > } > > > > impl Writer for SumState { > > fn write(&mut self, bytes: &[u8]) -> IoResult<()> { > > for byte in bytes.iter() { > > self.sum += *byte as u64; > > } > > Ok(()) > > } > > } > > > > struct SumHasher; > > > > #[allow(default_type_param_usage)] > > impl Hasher<SumState> for SumHasher { > > fn hash<T: Hash<SumState>>(&self, value: &T) -> u64 { > > let mut state = SumState { sum: 0 }; > > value.hash(&mut state); > > state.sum > > } > > } > > > > fn main() { > > let hasher = SumHasher; > > let foo = Foo { a: ~"hello world", b: 5, c: true }; > > println!("{}", hasher.hash(&foo)); > > let bar = Bar { a: ~"hello world", b: 5, c: true }; > > println!("{}", hasher.hash(&bar)); > > } > > ``` > > > > Finally, we also support completely custom hash computation: > > > > ``` > > use std::hash::{Hash, Hasher}; > > > > struct Foo { > > hash: u64 > > } > > > > #[allow(default_type_param_usage)] > > impl Hash<u64> for Foo { > > fn hash(&self, state: &mut u64) { > > *state = self.hash > > } > > } > > > > struct CustomHasher; > > > > #[allow(default_type_param_usage)] > > impl Hasher<u64> for CustomHasher { > > fn hash<T: Hash<u64>>(&self, value: &T) -> u64 { > > let mut state = 0; > > value.hash(&mut state); > > state > > } > > } > > > > fn main() { > > let hasher = CustomHasher; > > let foo = Foo { hash: 5 }; > > println!("{}", hasher.hash(&foo)); > > } > > ``` > > > > This may break over the next couple days/weeks as we figure out the right > > way to do this. Furthermore, HashMaps have not yet been updated to take > > advantage of the custom hashers, but that should be coming later on this > > week. > > > > I hope they work well for all of you. If you run into any trouble, please > > file bugs and cc @erickt on the ticket. > > > > Thanks, > > Erick > > > _______________________________________________ > > Rust-dev mailing list > > [email protected] > > https://mail.mozilla.org/listinfo/rust-dev > >
_______________________________________________ Rust-dev mailing list [email protected] https://mail.mozilla.org/listinfo/rust-dev
