auto merge of #11863 : erickt/rust/hash, r=acrichto

This PR merges `IterBytes` and `Hash` into a trait that allows for generic non-stream-based hashing. It makes use of @eddyb's default type parameter support in order to have a similar usage to the old `Hash` framework.

Fixes #8038.

Todo:

- [x] Better documentation
- [ ] Benchmark
- [ ] Parameterize `HashMap` on a `Hasher`.
This commit is contained in:
bors 2014-02-22 15:01:58 -08:00
commit 22d3669b9e
41 changed files with 1191 additions and 17 deletions

View File

@ -119,7 +119,8 @@ for (trait, supers, errs) in [('Rand', [], 1),
('Clone', [], 1), ('DeepClone', ['Clone'], 1),
('Eq', [], 2), ('Ord', [], 8),
('TotalEq', [], 1), ('TotalOrd', ['TotalEq'], 1),
('Show', [], 1)]:
('Show', [], 1),
('Hash', [], 1)]:
traits[trait] = (ALL, supers, errs)
for (trait, (types, super_traits, error_count)) in traits.items():

View File

@ -11,6 +11,7 @@
#[allow(missing_doc)];
use std::cmp;
use std::hash_old::Hash;
use std::hashmap;
use std::io;
use std::mem;

View File

@ -27,6 +27,7 @@ use middle::typeck;
use middle::astencode::vtable_decoder_helpers;
use std::u64;
use std::hash_old::Hash;
use std::io;
use std::io::extensions::u64_from_be_bytes;
use std::option;

View File

@ -26,6 +26,7 @@ use middle;
use serialize::Encodable;
use std::cast;
use std::cell::{Cell, RefCell};
use std::hash_old::Hash;
use std::hashmap::{HashMap, HashSet};
use std::io::MemWriter;
use std::str;

View File

@ -4916,7 +4916,7 @@ pub fn trait_method_of_method(tcx: ctxt,
/// Creates a hash of the type `t` which will be the same no matter what crate
/// context it's calculated within. This is used by the `type_id` intrinsic.
pub fn hash_crate_independent(tcx: ctxt, t: t, local_hash: ~str) -> u64 {
use std::hash::{SipState, Streaming};
use std::hash_old::{SipState, Streaming};
let mut hash = SipState::new(0, 0);
let region = |_hash: &mut SipState, r: Region| {

View File

@ -14,6 +14,7 @@
Core encoding and decoding interfaces.
*/
use std::hash_old::Hash;
use std::hashmap::{HashMap, HashSet};
use std::rc::Rc;
use std::trie::{TrieMap, TrieSet};

369
src/libstd/hash/mod.rs Normal file
View File

@ -0,0 +1,369 @@
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 option::{Option, Some, None};
use rc::Rc;
use str::{Str, StrSlice};
use vec::{Vector, ImmutableVector};
/// 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<S = sip::SipState> {
/// 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<S> {
/// Compute a hash of the value.
fn hash<T: Hash<S>>(&self, value: &T) -> u64;
}
//////////////////////////////////////////////////////////////////////////////
macro_rules! impl_hash(
( $( $ty:ty => $method:ident;)* ) => (
$(
impl<S: Writer> Hash<S> 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<S: Writer> Hash<S> for bool {
#[inline]
fn hash(&self, state: &mut S) {
(*self as u8).hash(state);
}
}
impl<S: Writer> Hash<S> for char {
#[inline]
fn hash(&self, state: &mut S) {
(*self as u32).hash(state);
}
}
impl<'a, S: Writer> Hash<S> for &'a str {
#[inline]
fn hash(&self, state: &mut S) {
state.write(self.as_bytes());
state.write_u8(0xFF);
}
}
impl<S: Writer> Hash<S> for ~str {
#[inline]
fn hash(&self, state: &mut S) {
self.as_slice().hash(state);
}
}
macro_rules! impl_hash_tuple(
() => (
impl<S: Writer> Hash<S> for () {
#[inline]
fn hash(&self, state: &mut S) {
state.write([]);
}
}
);
($A:ident $($B:ident)*) => (
impl<
S: Writer,
$A: Hash<S> $(, $B: Hash<S>)*
> Hash<S> 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<S>> Hash<S> 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<S>> Hash<S> for &'a mut [T] {
#[inline]
fn hash(&self, state: &mut S) {
self.as_slice().hash(state);
}
}
impl<S: Writer, T: Hash<S>> Hash<S> for ~[T] {
#[inline]
fn hash(&self, state: &mut S) {
self.as_slice().hash(state);
}
}
impl<'a, S: Writer, T: Hash<S>> Hash<S> for &'a T {
#[inline]
fn hash(&self, state: &mut S) {
(**self).hash(state);
}
}
impl<'a, S: Writer, T: Hash<S>> Hash<S> for &'a mut T {
#[inline]
fn hash(&self, state: &mut S) {
(**self).hash(state);
}
}
impl<S: Writer, T: Hash<S>> Hash<S> for ~T {
#[inline]
fn hash(&self, state: &mut S) {
(**self).hash(state);
}
}
impl<S: Writer, T: Hash<S>> Hash<S> for @T {
#[inline]
fn hash(&self, state: &mut S) {
(**self).hash(state);
}
}
impl<S: Writer, T: Hash<S>> Hash<S> for Rc<T> {
#[inline]
fn hash(&self, state: &mut S) {
self.borrow().hash(state);
}
}
impl<S: Writer, T: Hash<S>> Hash<S> for Option<T> {
#[inline]
fn hash(&self, state: &mut S) {
match *self {
Some(ref x) => {
0u8.hash(state);
x.hash(state);
}
None => {
1u8.hash(state);
}
}
}
}
impl<S: Writer, T> Hash<S> 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<S: Writer, T> Hash<S> 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<MyWriter> for MyWriterHasher {
fn hash<T: Hash<MyWriter>>(&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<u64> 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);
}
}

519
src/libstd/hash/sip.rs Normal file
View File

@ -0,0 +1,519 @@
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
/*!
* Implementation of SipHash 2-4
*
* See: http://131002.net/siphash/
*
* Consider this as a main "general-purpose" hash for all hashtables: it
* runs at good speed (competitive with spooky and city) and permits
* strong _keyed_ hashing. Key your hashtables from a strong RNG,
* such as `rand::Rng`.
*
* Although the SipHash algorithm is considered to be cryptographically
* strong, this implementation has not been reviewed for such purposes.
* As such, all cryptographic uses of this implementation are strongly
* discouraged.
*/
use container::Container;
use io::{IoResult, Writer};
use iter::Iterator;
use result::Ok;
use vec::ImmutableVector;
use super::{Hash, Hasher};
/// `SipState` computes a SipHash 2-4 hash over a stream of bytes.
pub struct SipState {
priv k0: u64,
priv k1: u64,
priv length: uint, // how many bytes we've processed
priv v0: u64, // hash state
priv v1: u64,
priv v2: u64,
priv v3: u64,
priv tail: [u8, ..8], // unprocessed bytes
priv ntail: uint, // how many bytes in tail are valid
}
// sadly, these macro definitions can't appear later,
// because they're needed in the following defs;
// this design could be improved.
macro_rules! u8to64_le (
($buf:expr, $i:expr) =>
($buf[0+$i] as u64 |
$buf[1+$i] as u64 << 8 |
$buf[2+$i] as u64 << 16 |
$buf[3+$i] as u64 << 24 |
$buf[4+$i] as u64 << 32 |
$buf[5+$i] as u64 << 40 |
$buf[6+$i] as u64 << 48 |
$buf[7+$i] as u64 << 56)
)
macro_rules! rotl (
($x:expr, $b:expr) =>
(($x << $b) | ($x >> (64 - $b)))
)
macro_rules! compress (
($v0:expr, $v1:expr, $v2:expr, $v3:expr) =>
({
$v0 += $v1; $v1 = rotl!($v1, 13); $v1 ^= $v0;
$v0 = rotl!($v0, 32);
$v2 += $v3; $v3 = rotl!($v3, 16); $v3 ^= $v2;
$v0 += $v3; $v3 = rotl!($v3, 21); $v3 ^= $v0;
$v2 += $v1; $v1 = rotl!($v1, 17); $v1 ^= $v2;
$v2 = rotl!($v2, 32);
})
)
impl SipState {
/// Create a `SipState` that is keyed off the provided keys.
#[inline]
pub fn new(key0: u64, key1: u64) -> SipState {
let mut state = SipState {
k0: key0,
k1: key1,
length: 0,
v0: 0,
v1: 0,
v2: 0,
v3: 0,
tail: [ 0, 0, 0, 0, 0, 0, 0, 0 ],
ntail: 0,
};
state.reset();
state
}
/// Reset the state back to it's initial state.
#[inline]
pub fn reset(&mut self) {
self.length = 0;
self.v0 = self.k0 ^ 0x736f6d6570736575;
self.v1 = self.k1 ^ 0x646f72616e646f6d;
self.v2 = self.k0 ^ 0x6c7967656e657261;
self.v3 = self.k1 ^ 0x7465646279746573;
self.ntail = 0;
}
/// Return the computed hash.
#[inline]
pub fn result(&self) -> u64 {
let mut v0 = self.v0;
let mut v1 = self.v1;
let mut v2 = self.v2;
let mut v3 = self.v3;
let mut b : u64 = (self.length as u64 & 0xff) << 56;
if self.ntail > 0 { b |= self.tail[0] as u64 << 0; }
if self.ntail > 1 { b |= self.tail[1] as u64 << 8; }
if self.ntail > 2 { b |= self.tail[2] as u64 << 16; }
if self.ntail > 3 { b |= self.tail[3] as u64 << 24; }
if self.ntail > 4 { b |= self.tail[4] as u64 << 32; }
if self.ntail > 5 { b |= self.tail[5] as u64 << 40; }
if self.ntail > 6 { b |= self.tail[6] as u64 << 48; }
v3 ^= b;
compress!(v0, v1, v2, v3);
compress!(v0, v1, v2, v3);
v0 ^= b;
v2 ^= 0xff;
compress!(v0, v1, v2, v3);
compress!(v0, v1, v2, v3);
compress!(v0, v1, v2, v3);
compress!(v0, v1, v2, v3);
v0 ^ v1 ^ v2 ^ v3
}
}
impl Writer for SipState {
#[inline]
fn write(&mut self, msg: &[u8]) -> IoResult<()> {
let length = msg.len();
self.length += length;
let mut needed = 0u;
if self.ntail != 0 {
needed = 8 - self.ntail;
if length < needed {
let mut t = 0;
while t < length {
self.tail[self.ntail+t] = msg[t];
t += 1;
}
self.ntail += length;
return Ok(());
}
let mut t = 0;
while t < needed {
self.tail[self.ntail+t] = msg[t];
t += 1;
}
let m = u8to64_le!(self.tail, 0);
self.v3 ^= m;
compress!(self.v0, self.v1, self.v2, self.v3);
compress!(self.v0, self.v1, self.v2, self.v3);
self.v0 ^= m;
self.ntail = 0;
}
// Buffered tail is now flushed, process new input.
let len = length - needed;
let end = len & (!0x7);
let left = len & 0x7;
let mut i = needed;
while i < end {
let mi = u8to64_le!(msg, i);
self.v3 ^= mi;
compress!(self.v0, self.v1, self.v2, self.v3);
compress!(self.v0, self.v1, self.v2, self.v3);
self.v0 ^= mi;
i += 8;
}
let mut t = 0u;
while t < left {
self.tail[t] = msg[i+t];
t += 1
}
self.ntail = left;
Ok(())
}
}
/// `Sip` computes the SipHash algorithm from a stream of bytes.
pub struct SipHasher {
priv state: SipState,
}
impl SipHasher {
/// Create a `Sip`.
#[inline]
pub fn new() -> SipHasher {
SipHasher::new_with_keys(0, 0)
}
/// Create a `Sip` that is keyed off the provided keys.
#[inline]
pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher {
SipHasher {
state: SipState::new(key0, key1),
}
}
}
impl Hasher<SipState> for SipHasher {
#[inline]
fn hash<T: Hash<SipState>>(&self, value: &T) -> u64 {
let mut state = self.state; // implicitly copy the state.
value.hash(&mut state);
state.result()
}
}
/// Hash a value using the SipHash algorithm.
#[inline]
pub fn hash<T: Hash<SipState>>(value: &T) -> u64 {
hash_with_keys(0, 0, value)
}
/// Hash a value with the SipHash algorithm with the provided keys.
#[inline]
pub fn hash_with_keys<T: Hash<SipState>>(k0: u64, k1: u64, value: &T) -> u64 {
let mut state = SipState::new(k0, k1);
value.hash(&mut state);
state.result()
}
#[cfg(test)]
mod tests {
extern crate test;
use io::Writer;
use iter::Iterator;
use num::ToStrRadix;
use option::{Some, None};
use str::{Str, OwnedStr};
use vec::{Vector, ImmutableVector, OwnedVector};
use self::test::BenchHarness;
use super::super::Hash;
use super::{SipState, hash, hash_with_keys};
// Hash just the bytes of the slice, without length prefix
struct Bytes<'a>(&'a [u8]);
impl<'a, S: Writer> Hash<S> for Bytes<'a> {
#[allow(unused_must_use)]
fn hash(&self, state: &mut S) {
let Bytes(v) = *self;
state.write(v);
}
}
#[test]
#[allow(unused_must_use)]
fn test_siphash() {
let vecs : [[u8, ..8], ..64] = [
[ 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, ],
[ 0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74, ],
[ 0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d, ],
[ 0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85, ],
[ 0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf, ],
[ 0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18, ],
[ 0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb, ],
[ 0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab, ],
[ 0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93, ],
[ 0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e, ],
[ 0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a, ],
[ 0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4, ],
[ 0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75, ],
[ 0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14, ],
[ 0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7, ],
[ 0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1, ],
[ 0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f, ],
[ 0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69, ],
[ 0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b, ],
[ 0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb, ],
[ 0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe, ],
[ 0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0, ],
[ 0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93, ],
[ 0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8, ],
[ 0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8, ],
[ 0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc, ],
[ 0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17, ],
[ 0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f, ],
[ 0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde, ],
[ 0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6, ],
[ 0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad, ],
[ 0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32, ],
[ 0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71, ],
[ 0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7, ],
[ 0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12, ],
[ 0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15, ],
[ 0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31, ],
[ 0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02, ],
[ 0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca, ],
[ 0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a, ],
[ 0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e, ],
[ 0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad, ],
[ 0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18, ],
[ 0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4, ],
[ 0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9, ],
[ 0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9, ],
[ 0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb, ],
[ 0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0, ],
[ 0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6, ],
[ 0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7, ],
[ 0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee, ],
[ 0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1, ],
[ 0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a, ],
[ 0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81, ],
[ 0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f, ],
[ 0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24, ],
[ 0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7, ],
[ 0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea, ],
[ 0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60, ],
[ 0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66, ],
[ 0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c, ],
[ 0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f, ],
[ 0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5, ],
[ 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, ]
];
let k0 = 0x_07_06_05_04_03_02_01_00_u64;
let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08_u64;
let mut buf : ~[u8] = ~[];
let mut t = 0;
let mut state_inc = SipState::new(k0, k1);
let mut state_full = SipState::new(k0, k1);
fn to_hex_str(r: &[u8, ..8]) -> ~str {
let mut s = ~"";
for b in r.iter() {
s.push_str((*b as uint).to_str_radix(16u));
}
s
}
fn result_bytes(h: u64) -> ~[u8] {
~[(h >> 0) as u8,
(h >> 8) as u8,
(h >> 16) as u8,
(h >> 24) as u8,
(h >> 32) as u8,
(h >> 40) as u8,
(h >> 48) as u8,
(h >> 56) as u8,
]
}
fn result_str(h: u64) -> ~str {
let r = result_bytes(h);
let mut s = ~"";
for b in r.iter() {
s.push_str((*b as uint).to_str_radix(16u));
}
s
}
while t < 64 {
debug!("siphash test {}", t);
let vec = u8to64_le!(vecs[t], 0);
let out = hash_with_keys(k0, k1, &Bytes(buf.as_slice()));
debug!("got {:?}, expected {:?}", out, vec);
assert_eq!(vec, out);
state_full.reset();
state_full.write(buf);
let f = result_str(state_full.result());
let i = result_str(state_inc.result());
let v = to_hex_str(&vecs[t]);
debug!("{}: ({}) => inc={} full={}", t, v, i, f);
assert!(f == i && f == v);
buf.push(t as u8);
state_inc.write_u8(t);
t += 1;
}
}
#[test] #[cfg(target_arch = "arm")]
fn test_hash_uint() {
let val = 0xdeadbeef_deadbeef_u64;
assert!(hash(&(val as u64)) != hash(&(val as uint)));
assert_eq!(hash(&(val as u32)), hash(&(val as uint)));
}
#[test] #[cfg(target_arch = "x86_64")]
fn test_hash_uint() {
let val = 0xdeadbeef_deadbeef_u64;
assert_eq!(hash(&(val as u64)), hash(&(val as uint)));
assert!(hash(&(val as u32)) != hash(&(val as uint)));
}
#[test] #[cfg(target_arch = "x86")]
fn test_hash_uint() {
let val = 0xdeadbeef_deadbeef_u64;
assert!(hash(&(val as u64)) != hash(&(val as uint)));
assert_eq!(hash(&(val as u32)), hash(&(val as uint)));
}
#[test]
fn test_hash_idempotent() {
let val64 = 0xdeadbeef_deadbeef_u64;
assert_eq!(hash(&val64), hash(&val64));
let val32 = 0xdeadbeef_u32;
assert_eq!(hash(&val32), hash(&val32));
}
#[test]
fn test_hash_no_bytes_dropped_64() {
let val = 0xdeadbeef_deadbeef_u64;
assert!(hash(&val) != hash(&zero_byte(val, 0)));
assert!(hash(&val) != hash(&zero_byte(val, 1)));
assert!(hash(&val) != hash(&zero_byte(val, 2)));
assert!(hash(&val) != hash(&zero_byte(val, 3)));
assert!(hash(&val) != hash(&zero_byte(val, 4)));
assert!(hash(&val) != hash(&zero_byte(val, 5)));
assert!(hash(&val) != hash(&zero_byte(val, 6)));
assert!(hash(&val) != hash(&zero_byte(val, 7)));
fn zero_byte(val: u64, byte: uint) -> u64 {
assert!(byte < 8);
val & !(0xff << (byte * 8))
}
}
#[test]
fn test_hash_no_bytes_dropped_32() {
let val = 0xdeadbeef_u32;
assert!(hash(&val) != hash(&zero_byte(val, 0)));
assert!(hash(&val) != hash(&zero_byte(val, 1)));
assert!(hash(&val) != hash(&zero_byte(val, 2)));
assert!(hash(&val) != hash(&zero_byte(val, 3)));
fn zero_byte(val: u32, byte: uint) -> u32 {
assert!(byte < 4);
val & !(0xff << (byte * 8))
}
}
#[test]
fn test_hash_no_concat_alias() {
let s = ("aa", "bb");
let t = ("aabb", "");
let u = ("a", "abb");
assert!(s != t && t != u);
assert!(hash(&s) != hash(&t) && hash(&s) != hash(&u));
let v = (&[1u8], &[0u8, 0], &[0u8]);
let w = (&[1u8, 0, 0, 0], &[], &[]);
assert!(v != w);
assert!(hash(&v) != hash(&w));
}
#[bench]
fn bench_str(bh: &mut BenchHarness) {
let s = "foo";
bh.iter(|| {
assert_eq!(hash(&s), 16262950014981195938);
})
}
struct Compound {
x: u8,
y: u16,
z: ~str,
}
impl<S: Writer> Hash<S> for Compound {
#[inline]
fn hash(&self, state: &mut S) {
self.x.hash(state);
self.y.hash(state);
self.z.hash(state);
}
}
#[bench]
fn bench_compound_1(bh: &mut BenchHarness) {
let compound = Compound {
x: 1,
y: 2,
z: ~"foobarbaz",
};
bh.iter(|| {
assert_eq!(hash(&compound), 3581836382593270478);
})
}
}

View File

@ -36,7 +36,7 @@ use to_bytes::IterBytes;
use vec::ImmutableVector;
// Alias `SipState` to `State`.
pub use State = hash::SipState;
pub use State = hash_old::SipState;
/**
* Types that can meaningfully be hashed should implement this.
@ -298,9 +298,13 @@ impl Streaming for SipState {
#[cfg(test)]
mod tests {
use super::*;
use prelude::*;
use super::SipState;
use super::{Hash, Streaming, SipState};
use iter::Iterator;
use num::ToStrRadix;
use option::Some;
use str::OwnedStr;
use to_bytes::IterBytes;
use vec::{Vector, OwnedVector, ImmutableVector};
// Hash just the bytes of the slice, without length prefix
struct Bytes<'a>(&'a [u8]);

View File

@ -57,7 +57,7 @@ use clone::Clone;
use cmp::{Eq, Equiv, max};
use default::Default;
use fmt;
use hash::Hash;
use hash_old::Hash;
use iter;
use iter::{Iterator, FromIterator, Extendable};
use iter::{FilterMap, Chain, Repeat, Zip};

View File

@ -54,6 +54,10 @@
#[feature(macro_rules, globs, asm, managed_boxes, thread_local, link_args, simd)];
// Turn on default type parameters.
#[feature(default_type_params)];
#[allow(default_type_param_usage)];
// Don't link to std. We are std.
#[no_std];
@ -141,6 +145,7 @@ pub mod iter;
pub mod to_str;
pub mod to_bytes;
pub mod clone;
pub mod hash_old;
pub mod hash;
pub mod container;
pub mod default;
@ -213,6 +218,7 @@ mod std {
pub use cmp;
pub use comm;
pub use fmt;
pub use hash;
pub use io;
pub use kinds;
pub use local_data;

View File

@ -45,7 +45,6 @@ pub use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater, Equiv}
pub use container::{Container, Mutable, Map, MutableMap, Set, MutableSet};
pub use default::Default;
pub use from_str::FromStr;
pub use hash::Hash;
pub use iter::{FromIterator, Extendable};
pub use iter::{Iterator, DoubleEndedIterator, RandomAccessIterator, CloneableIterator};
pub use iter::{OrdIterator, MutableDoubleEndedIterator, ExactSize};
@ -62,7 +61,7 @@ pub use tuple::{Tuple1, Tuple2, Tuple3, Tuple4};
pub use tuple::{Tuple5, Tuple6, Tuple7, Tuple8};
pub use tuple::{Tuple9, Tuple10, Tuple11, Tuple12};
pub use vec::{ImmutableEqVector, ImmutableTotalOrdVector, ImmutableCloneableVector};
pub use vec::{OwnedVector, OwnedCloneableVector,OwnedEqVector};
pub use vec::{OwnedVector, OwnedCloneableVector, OwnedEqVector};
pub use vec::{MutableVector, MutableTotalOrdVector};
pub use vec::{Vector, VectorVector, CloneableVector, ImmutableVector};

View File

@ -18,7 +18,7 @@ use option::{Some, None};
use str::OwnedStr;
use hashmap::HashMap;
use hashmap::HashSet;
use hash::Hash;
use hash_old::Hash;
use iter::Iterator;
use cmp::Eq;
use vec::ImmutableVector;

View File

@ -242,6 +242,9 @@ pub trait AstBuilder {
fn view_use(&self, sp: Span,
vis: ast::Visibility, vp: ~[@ast::ViewPath]) -> ast::ViewItem;
fn view_use_simple(&self, sp: Span, vis: ast::Visibility, path: ast::Path) -> ast::ViewItem;
fn view_use_simple_(&self, sp: Span, vis: ast::Visibility,
ident: ast::Ident, path: ast::Path) -> ast::ViewItem;
fn view_use_list(&self, sp: Span, vis: ast::Visibility,
path: ~[ast::Ident], imports: &[ast::Ident]) -> ast::ViewItem;
fn view_use_glob(&self, sp: Span,
@ -900,6 +903,20 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
}
}
fn view_use_simple(&self, sp: Span, vis: ast::Visibility, path: ast::Path) -> ast::ViewItem {
let last = path.segments.last().unwrap().identifier;
self.view_use_simple_(sp, vis, last, path)
}
fn view_use_simple_(&self, sp: Span, vis: ast::Visibility,
ident: ast::Ident, path: ast::Path) -> ast::ViewItem {
self.view_use(sp, vis,
~[@respan(sp,
ast::ViewPathSimple(ident,
path,
ast::DUMMY_NODE_ID))])
}
fn view_use_list(&self, sp: Span, vis: ast::Visibility,
path: ~[ast::Ident], imports: &[ast::Ident]) -> ast::ViewItem {
let imports = imports.map(|id| {

View File

@ -21,6 +21,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt,
push: |@Item|) {
let trait_def = TraitDef {
span: span,
attributes: ~[],
path: Path::new(~["std", "clone", "Clone"]),
additional_bounds: ~[],
generics: LifetimeBounds::empty(),
@ -48,6 +49,7 @@ pub fn expand_deriving_deep_clone(cx: &mut ExtCtxt,
push: |@Item|) {
let trait_def = TraitDef {
span: span,
attributes: ~[],
path: Path::new(~["std", "clone", "DeepClone"]),
additional_bounds: ~[],
generics: LifetimeBounds::empty(),

View File

@ -47,6 +47,7 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt,
let trait_def = TraitDef {
span: span,
attributes: ~[],
path: Path::new(~["std", "cmp", "Eq"]),
additional_bounds: ~[],
generics: LifetimeBounds::empty(),

View File

@ -37,6 +37,7 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt,
let trait_def = TraitDef {
span: span,
attributes: ~[],
path: Path::new(~["std", "cmp", "Ord"]),
additional_bounds: ~[],
generics: LifetimeBounds::empty(),

View File

@ -26,6 +26,7 @@ pub fn expand_deriving_totaleq(cx: &mut ExtCtxt,
let trait_def = TraitDef {
span: span,
attributes: ~[],
path: Path::new(~["std", "cmp", "TotalEq"]),
additional_bounds: ~[],
generics: LifetimeBounds::empty(),

View File

@ -23,6 +23,7 @@ pub fn expand_deriving_totalord(cx: &mut ExtCtxt,
push: |@Item|) {
let trait_def = TraitDef {
span: span,
attributes: ~[],
path: Path::new(~["std", "cmp", "TotalOrd"]),
additional_bounds: ~[],
generics: LifetimeBounds::empty(),

View File

@ -28,6 +28,7 @@ pub fn expand_deriving_decodable(cx: &mut ExtCtxt,
push: |@Item|) {
let trait_def = TraitDef {
span: span,
attributes: ~[],
path: Path::new_(~["serialize", "Decodable"], None,
~[~Literal(Path::new_local("__D"))], true),
additional_bounds: ~[],

View File

@ -21,6 +21,7 @@ pub fn expand_deriving_default(cx: &mut ExtCtxt,
push: |@Item|) {
let trait_def = TraitDef {
span: span,
attributes: ~[],
path: Path::new(~["std", "default", "Default"]),
additional_bounds: ~[],
generics: LifetimeBounds::empty(),

View File

@ -95,6 +95,7 @@ pub fn expand_deriving_encodable(cx: &mut ExtCtxt,
push: |@Item|) {
let trait_def = TraitDef {
span: span,
attributes: ~[],
path: Path::new_(~["serialize", "Encodable"], None,
~[~Literal(Path::new_local("__E"))], true),
additional_bounds: ~[],

View File

@ -196,6 +196,8 @@ pub struct TraitDef<'a> {
/// The span for the current #[deriving(Foo)] header.
span: Span,
attributes: ~[ast::Attribute],
/// Path of the trait, including any type parameters
path: Path<'a>,
@ -355,7 +357,8 @@ impl<'a> TraitDef<'a> {
*/
fn create_derived_impl(&self,
cx: &mut ExtCtxt,
type_ident: Ident, generics: &Generics,
type_ident: Ident,
generics: &Generics,
methods: ~[@ast::Method]) -> @ast::Item {
let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
@ -408,7 +411,7 @@ impl<'a> TraitDef<'a> {
cx.item(
self.span,
ident,
~[doc_attr],
vec::append(~[doc_attr], self.attributes),
ast::ItemImpl(trait_generics, opt_trait_ref,
self_type, methods.map(|x| *x)))
}

View File

@ -0,0 +1,97 @@
// Copyright 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use ast::{MetaItem, Item, Expr, MutMutable};
use codemap::Span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
use ext::deriving::generic::*;
use parse::token::InternedString;
pub fn expand_deriving_hash(cx: &mut ExtCtxt,
span: Span,
mitem: @MetaItem,
item: @Item,
push: |@Item|) {
let allow_default_type_param_usage = cx.attribute(
span,
cx.meta_list(
span,
InternedString::new("allow"),
~[cx.meta_word(span, InternedString::new("default_type_param_usage"))]));
let hash_trait_def = TraitDef {
span: span,
attributes: ~[allow_default_type_param_usage],
path: Path::new_(~["std", "hash", "Hash"], None,
~[~Literal(Path::new_local("__H"))], true),
additional_bounds: ~[],
generics: LifetimeBounds {
lifetimes: ~[],
bounds: ~[("__H", ~[Path::new(~["std", "io", "Writer"])])],
},
methods: ~[
MethodDef {
name: "hash",
generics: LifetimeBounds::empty(),
explicit_self: borrowed_explicit_self(),
args: ~[Ptr(~Literal(Path::new_local("__H")),
Borrowed(None, MutMutable))],
ret_ty: nil_ty(),
inline: true,
const_nonmatching: false,
combine_substructure: hash_substructure
}
]
};
hash_trait_def.expand(cx, mitem, item, push);
}
fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> @Expr {
let state_expr = match substr.nonself_args {
[state_expr] => state_expr,
_ => cx.span_bug(trait_span, "incorrect number of arguments in `deriving(Hash)`")
};
let hash_ident = substr.method_ident;
let call_hash = |span, thing_expr| {
let expr = cx.expr_method_call(span, thing_expr, hash_ident, ~[state_expr]);
cx.stmt_expr(expr)
};
let mut stmts = ~[];
let fields = match *substr.fields {
Struct(ref fs) => fs,
EnumMatching(index, variant, ref fs) => {
// Determine the discriminant. We will feed this value to the byte
// iteration function.
let discriminant = match variant.node.disr_expr {
Some(d) => d,
None => cx.expr_uint(trait_span, index)
};
stmts.push(call_hash(trait_span, discriminant));
fs
}
_ => cx.span_bug(trait_span, "impossible substructure in `deriving(Hash)`")
};
for &FieldInfo { self_, span, .. } in fields.iter() {
stmts.push(call_hash(span, self_));
}
if stmts.len() == 0 {
cx.span_bug(trait_span, "#[deriving(Hash)] needs at least one field");
}
cx.expr_block(cx.block(trait_span, stmts, None))
}

View File

@ -22,6 +22,7 @@ pub fn expand_deriving_iter_bytes(cx: &mut ExtCtxt,
push: |@Item|) {
let trait_def = TraitDef {
span: span,
attributes: ~[],
path: Path::new(~["std", "to_bytes", "IterBytes"]),
additional_bounds: ~[],
generics: LifetimeBounds::empty(),

View File

@ -26,6 +26,7 @@ pub mod clone;
pub mod iter_bytes;
pub mod encodable;
pub mod decodable;
pub mod hash;
pub mod rand;
pub mod to_str;
pub mod show;
@ -74,6 +75,7 @@ pub fn expand_meta_deriving(cx: &mut ExtCtxt,
"DeepClone" => expand!(clone::expand_deriving_deep_clone),
"IterBytes" => expand!(iter_bytes::expand_deriving_iter_bytes),
"Hash" => expand!(hash::expand_deriving_hash),
"Encodable" => expand!(encodable::expand_deriving_encodable),
"Decodable" => expand!(decodable::expand_deriving_decodable),

View File

@ -23,6 +23,7 @@ pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt,
push: |@Item|) {
let trait_def = TraitDef {
span: span,
attributes: ~[],
path: Path::new(~["std", "num", "FromPrimitive"]),
additional_bounds: ~[],
generics: LifetimeBounds::empty(),

View File

@ -23,6 +23,7 @@ pub fn expand_deriving_rand(cx: &mut ExtCtxt,
push: |@Item|) {
let trait_def = TraitDef {
span: span,
attributes: ~[],
path: Path::new(~["std", "rand", "Rand"]),
additional_bounds: ~[],
generics: LifetimeBounds::empty(),

View File

@ -31,6 +31,7 @@ pub fn expand_deriving_show(cx: &mut ExtCtxt,
let trait_def = TraitDef {
span: span,
attributes: ~[],
path: Path::new(~["std", "fmt", "Show"]),
additional_bounds: ~[],
generics: LifetimeBounds::empty(),

View File

@ -24,6 +24,7 @@ pub fn expand_deriving_to_str(cx: &mut ExtCtxt,
push: |@Item|) {
let trait_def = TraitDef {
span: span,
attributes: ~[],
path: Path::new(~["std", "to_str", "ToStr"]),
additional_bounds: ~[],
generics: LifetimeBounds::empty(),

View File

@ -21,6 +21,7 @@ pub fn expand_deriving_zero(cx: &mut ExtCtxt,
push: |@Item|) {
let trait_def = TraitDef {
span: span,
attributes: ~[],
path: Path::new(~["std", "num", "Zero"]),
additional_bounds: ~[],
generics: LifetimeBounds::empty(),

View File

@ -17,6 +17,7 @@ use ast::Name;
use std::cast;
use std::cell::RefCell;
use std::cmp::Equiv;
use std::hash_old::Hash;
use std::hashmap::HashMap;
use std::rc::Rc;

View File

@ -308,7 +308,7 @@ impl Uuid {
}
/// Return an array of 16 octets containing the UUID data
pub fn to_bytes<'a>(&'a self) -> &'a [u8] {
pub fn as_bytes<'a>(&'a self) -> &'a [u8] {
self.bytes.as_slice()
}
@ -739,9 +739,9 @@ mod test {
}
#[test]
fn test_to_bytes() {
fn test_as_bytes() {
let u = Uuid::new_v4();
let ub = u.to_bytes();
let ub = u.as_bytes();
assert!(ub.len() == 16);
assert!(! ub.iter().all(|&b| b == 0));
@ -754,7 +754,7 @@ mod test {
let u = Uuid::from_bytes(b_in.clone()).unwrap();
let b_out = u.to_bytes();
let b_out = u.as_bytes();
assert!(b_in == b_out);
}
@ -779,7 +779,7 @@ mod test {
fn test_rand_rand() {
let mut rng = rand::rng();
let u: ~Uuid = rand::Rand::rand(&mut rng);
let ub = u.to_bytes();
let ub = u.as_bytes();
assert!(ub.len() == 16);
assert!(! ub.iter().all(|&b| b == 0));

View File

@ -0,0 +1,27 @@
// Copyright 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
#[feature(struct_variant)];
extern crate extra;
use std::hash::Hash;
struct Error;
#[deriving(Hash)]
enum Enum {
A {
x: Error //~ ERROR
}
}
fn main() {}

View File

@ -0,0 +1,27 @@
// Copyright 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
#[feature(struct_variant)];
extern crate extra;
use std::hash::Hash;
struct Error;
#[deriving(Hash)]
enum Enum {
A(
Error //~ ERROR
)
}
fn main() {}

View File

@ -0,0 +1,25 @@
// Copyright 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
#[feature(struct_variant)];
extern crate extra;
use std::hash::Hash;
struct Error;
#[deriving(Hash)]
struct Struct {
x: Error //~ ERROR
}
fn main() {}

View File

@ -0,0 +1,25 @@
// Copyright 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
#[feature(struct_variant)];
extern crate extra;
use std::hash::Hash;
struct Error;
#[deriving(Hash)]
struct Struct(
Error //~ ERROR
);
fn main() {}

View File

@ -0,0 +1,28 @@
// Copyright 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-fast
use std::hash;
use std::hash::Hash;
#[deriving(Hash)]
struct Person {
id: uint,
name: ~str,
phone: uint,
}
fn main() {
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(&person1));
assert!(hash::hash(&person1) != hash::hash(&person2));
}

View File

@ -10,6 +10,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::hash_old::Hash;
#[deriving(Eq)]
#[deriving(Clone)]
#[deriving(IterBytes)]

View File

@ -10,6 +10,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::hash_old::Hash;
#[deriving(Eq, Clone, IterBytes)]
struct Foo {
bar: uint,

View File

@ -15,6 +15,7 @@
extern crate other1 = "typeid-intrinsic";
extern crate other2 = "typeid-intrinsic2";
use std::hash_old::Hash;
use std::unstable::intrinsics;
use std::unstable::intrinsics::TypeId;