// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. /*! * Generic hashing support. * * This module provides a generic way to compute the hash of a value. The * simplest way to make a type hashable is to use `#[deriving(Hash)]`: * * # Example * * ```rust * use std::hash; * use std::hash::Hash; * * #[deriving(Hash)] * struct Person { * id: uint, * name: ~str, * phone: u64, * } * * let person1 = Person { id: 5, name: ~"Janet", phone: 555_666_7777 }; * let person2 = Person { id: 5, name: ~"Bob", phone: 555_666_7777 }; * * assert!(hash::hash(&person1) != hash::hash(&person2)); * ``` * * If you need more control over how a value is hashed, you need to implement * the trait `Hash`: * * ```rust * use std::hash; * use std::hash::Hash; * use std::hash::sip::SipState; * * struct Person { * id: uint, * name: ~str, * phone: u64, * } * * impl Hash for Person { * fn hash(&self, state: &mut SipState) { * self.id.hash(state); * self.phone.hash(state); * } * } * * let person1 = Person { id: 5, name: ~"Janet", phone: 555_666_7777 }; * let person2 = Person { id: 5, name: ~"Bob", phone: 555_666_7777 }; * * assert!(hash::hash(&person1) == hash::hash(&person2)); * ``` */ #[allow(unused_must_use)]; use container::Container; use io::Writer; use iter::Iterator; use ops::Deref; use option::{Option, Some, None}; use rc::Rc; use str::{Str, StrSlice}; use vec::{Vector, ImmutableVector}; use vec_ng::Vec; /// Reexport the `sip::hash` function as our default hasher. pub use hash = self::sip::hash; pub mod sip; /// A trait that represents a hashable type. The `S` type parameter is an /// abstract hash state that is used by the `Hash` to compute the hash. /// It defaults to `std::hash::sip::SipState`. pub trait Hash { /// Compute a hash of the value. fn hash(&self, state: &mut S); } /// A trait that computes a hash for a value. The main users of this trait are /// containers like `HashMap`, which need a generic way hash multiple types. pub trait Hasher { /// Compute a hash of the value. fn hash>(&self, value: &T) -> u64; } ////////////////////////////////////////////////////////////////////////////// macro_rules! impl_hash( ( $( $ty:ty => $method:ident;)* ) => ( $( impl Hash for $ty { #[inline] fn hash(&self, state: &mut S) { state.$method(*self); } } )* ) ) impl_hash!( u8 => write_u8; u16 => write_le_u16; u32 => write_le_u32; u64 => write_le_u64; uint => write_le_uint; i8 => write_i8; i16 => write_le_i16; i32 => write_le_i32; i64 => write_le_i64; int => write_le_int; ) impl Hash for bool { #[inline] fn hash(&self, state: &mut S) { (*self as u8).hash(state); } } impl Hash for char { #[inline] fn hash(&self, state: &mut S) { (*self as u32).hash(state); } } impl<'a, S: Writer> Hash for &'a str { #[inline] fn hash(&self, state: &mut S) { state.write(self.as_bytes()); state.write_u8(0xFF); } } impl Hash for ~str { #[inline] fn hash(&self, state: &mut S) { self.as_slice().hash(state); } } macro_rules! impl_hash_tuple( () => ( impl Hash for () { #[inline] fn hash(&self, state: &mut S) { state.write([]); } } ); ($A:ident $($B:ident)*) => ( impl< S: Writer, $A: Hash $(, $B: Hash)* > Hash for ($A, $($B),*) { #[inline] fn hash(&self, state: &mut S) { match *self { (ref $A, $(ref $B),*) => { $A.hash(state); $( $B.hash(state); )* } } } } impl_hash_tuple!($($B)*) ); ) impl_hash_tuple!(a0 a1 a2 a3 a4 a5 a6 a7) impl<'a, S: Writer, T: Hash> Hash for &'a [T] { #[inline] fn hash(&self, state: &mut S) { self.len().hash(state); for elt in self.iter() { elt.hash(state); } } } impl<'a, S: Writer, T: Hash> Hash for &'a mut [T] { #[inline] fn hash(&self, state: &mut S) { self.as_slice().hash(state); } } impl> Hash for ~[T] { #[inline] fn hash(&self, state: &mut S) { self.as_slice().hash(state); } } impl> Hash for Vec { #[inline] fn hash(&self, state: &mut S) { self.as_slice().hash(state); } } impl<'a, S: Writer, T: Hash> Hash for &'a T { #[inline] fn hash(&self, state: &mut S) { (**self).hash(state); } } impl<'a, S: Writer, T: Hash> Hash for &'a mut T { #[inline] fn hash(&self, state: &mut S) { (**self).hash(state); } } impl> Hash for ~T { #[inline] fn hash(&self, state: &mut S) { (**self).hash(state); } } impl> Hash for @T { #[inline] fn hash(&self, state: &mut S) { (**self).hash(state); } } impl> Hash for Rc { #[inline] fn hash(&self, state: &mut S) { self.deref().hash(state); } } impl> Hash for Option { #[inline] fn hash(&self, state: &mut S) { match *self { Some(ref x) => { 0u8.hash(state); x.hash(state); } None => { 1u8.hash(state); } } } } impl Hash for *T { #[inline] fn hash(&self, state: &mut S) { // NB: raw-pointer Hash does _not_ dereference // to the target; it just gives you the pointer-bytes. (*self as uint).hash(state); } } impl Hash for *mut T { #[inline] fn hash(&self, state: &mut S) { // NB: raw-pointer Hash does _not_ dereference // to the target; it just gives you the pointer-bytes. (*self as uint).hash(state); } } ////////////////////////////////////////////////////////////////////////////// #[cfg(test)] mod tests { use cast; use io::{IoResult, Writer}; use iter::{Iterator}; use option::{Some, None}; use result::Ok; use vec::ImmutableVector; use super::{Hash, Hasher}; struct MyWriterHasher; impl Hasher for MyWriterHasher { fn hash>(&self, value: &T) -> u64 { let mut state = MyWriter { hash: 0 }; value.hash(&mut state); state.hash } } struct MyWriter { hash: u64, } impl Writer for MyWriter { // Most things we'll just add up the bytes. fn write(&mut self, buf: &[u8]) -> IoResult<()> { for byte in buf.iter() { self.hash += *byte as u64; } Ok(()) } } #[test] fn test_writer_hasher() { let hasher = MyWriterHasher; assert_eq!(hasher.hash(&()), 0); assert_eq!(hasher.hash(&5u8), 5); assert_eq!(hasher.hash(&5u16), 5); assert_eq!(hasher.hash(&5u32), 5); assert_eq!(hasher.hash(&5u64), 5); assert_eq!(hasher.hash(&5u), 5); assert_eq!(hasher.hash(&5i8), 5); assert_eq!(hasher.hash(&5i16), 5); assert_eq!(hasher.hash(&5i32), 5); assert_eq!(hasher.hash(&5i64), 5); assert_eq!(hasher.hash(&5i), 5); assert_eq!(hasher.hash(&false), 0); assert_eq!(hasher.hash(&true), 1); assert_eq!(hasher.hash(&'a'), 97); assert_eq!(hasher.hash(& &"a"), 97 + 0xFF); assert_eq!(hasher.hash(& &[1u8, 2u8, 3u8]), 9); unsafe { let ptr: *int = cast::transmute(5); assert_eq!(hasher.hash(&ptr), 5); } unsafe { let ptr: *mut int = cast::transmute(5); assert_eq!(hasher.hash(&ptr), 5); } } struct Custom { hash: u64 } impl Hash for Custom { fn hash(&self, state: &mut u64) { *state = self.hash; } } #[test] fn test_custom_state() { let custom = Custom { hash: 5 }; let mut state = 0; custom.hash(&mut state); assert_eq!(state, 5); } }