diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 33ca80ba37259..1168b0e52becb 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -892,6 +892,10 @@ impl Hash for Arc { fn hash(&self, state: &mut H) { (**self).hash(state) } + + fn hash_end(&self, state: &mut H) { + (**self).hash_end(state) + } } #[cfg(test)] diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index e85b7d2d4969f..9373225ec2f9e 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -373,6 +373,10 @@ impl Hash for Box { fn hash(&self, state: &mut H) { (**self).hash(state); } + + fn hash_end(&self, state: &mut H) { + (**self).hash_end(state); + } } impl Box { diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index c78ebdf4340ee..44168640535d8 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -82,6 +82,7 @@ #![feature(core_slice_ext)] #![feature(custom_attribute)] #![feature(fundamental)] +// #![feature(hash_end)] #![feature(lang_items)] #![feature(no_std)] #![feature(nonzero)] diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index d695c0edd1dc8..48d2a8181e8ee 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -678,6 +678,10 @@ impl Hash for Rc { fn hash(&self, state: &mut H) { (**self).hash(state); } + + fn hash_end(&self, state: &mut H) { + (**self).hash_end(state); + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcollections/borrow.rs b/src/libcollections/borrow.rs index bd1864b28cdd3..3f6559caeb530 100644 --- a/src/libcollections/borrow.rs +++ b/src/libcollections/borrow.rs @@ -232,6 +232,11 @@ impl<'a, B: ?Sized> Hash for Cow<'a, B> where B: Hash + ToOwned fn hash(&self, state: &mut H) { Hash::hash(&**self, state) } + + #[inline] + fn hash_end(&self, state: &mut H) { + Hash::hash_end(&**self, state) + } } /// Trait for moving into a `Cow`. diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index 59ffc1bd36f82..20ac08d7ce896 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -889,6 +889,11 @@ impl<'a, K: Ord + Copy, V: Copy> Extend<(&'a K, &'a V)> for BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] impl Hash for BTreeMap { fn hash(&self, state: &mut H) { + self.len().hash(state); + self.hash_end(state); + } + + fn hash_end(&self, state: &mut H) { for elt in self { elt.hash(state); } diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 4292c200fbe2f..d53d67e530672 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -45,6 +45,7 @@ #![feature(core_str_ext)] #![feature(fmt_internals)] #![feature(fmt_radix)] +// #![feature(hash_end)] #![feature(heap_api)] #![feature(iter_order)] #![feature(iter_arith)] diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index fca7d3b26fc2e..bf1f0b216a166 100644 --- a/src/libcollections/linked_list.rs +++ b/src/libcollections/linked_list.rs @@ -963,6 +963,10 @@ impl fmt::Debug for LinkedList { impl Hash for LinkedList { fn hash(&self, state: &mut H) { self.len().hash(state); + self.hash_end(state); + } + + fn hash_end(&self, state: &mut H) { for elt in self { elt.hash(state); } diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 0815a2c4de9cf..e375cd5f0818f 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1033,6 +1033,11 @@ impl hash::Hash for String { fn hash(&self, hasher: &mut H) { (**self).hash(hasher) } + + #[inline] + fn hash_end(&self, hasher: &mut H) { + (**self).hash_end(hasher) + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index d374c0959f357..d1ea9e2141b97 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1098,6 +1098,11 @@ impl Hash for Vec { fn hash(&self, state: &mut H) { Hash::hash(&**self, state) } + + #[inline] + fn hash_end(&self, state: &mut H) { + Hash::hash_end(&**self, state) + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index d438c27a96fa0..3eea3a83dd192 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -1696,6 +1696,10 @@ impl Ord for VecDeque { impl Hash for VecDeque { fn hash(&self, state: &mut H) { self.len().hash(state); + self.hash_end(state); + } + + fn hash_end(&self, state: &mut H) { for elt in self { elt.hash(state); } diff --git a/src/libcore/array.rs b/src/libcore/array.rs index c986914440de0..dfa2a96153663 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -106,6 +106,10 @@ macro_rules! array_impls { fn hash(&self, state: &mut H) { Hash::hash(&self[..], state) } + + fn hash_end(&self, state: &mut H) { + Hash::hash_end(&self[..], state) + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 4e038f455e1be..fbe0e9836f4f3 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -107,6 +107,17 @@ pub trait Hash { piece.hash(state); } } + + // FIXME: This should be unstable, but doing so breaks deriving + // #[unstable(feature = "hash_end", reason = "recently added", issue = "0")] + + /// Feeds this value into the state given, assuming it will be the last + /// value fed before finishing the hash. This means that there is no need + /// to write a size or sentinel to separate this value from what follows. + #[stable(feature = "rust1", since = "1.0.0")] + fn hash_end(&self, state: &mut H) { + self.hash(state); + } } /// A trait which represents the ability to hash an arbitrary stream of bytes. @@ -246,6 +257,10 @@ mod impls { state.write(self.as_bytes()); state.write_u8(0xff) } + + fn hash_end(&self, state: &mut H) { + state.write(self.as_bytes()); + } } macro_rules! impl_hash_tuple { @@ -256,13 +271,21 @@ mod impls { } ); - ( $($name:ident)+) => ( + ( $last:ident $($name:ident)*) => ( #[stable(feature = "rust1", since = "1.0.0")] - impl<$($name: Hash),*> Hash for ($($name,)*) { + impl<$($name: Hash,)* $last: Hash> Hash for ($($name,)*$last,) { #[allow(non_snake_case)] fn hash(&self, state: &mut S) { - let ($(ref $name,)*) = *self; + let ($(ref $name,)* ref $last,) = *self; + $($name.hash(state);)* + $last.hash(state); + } + + #[allow(non_snake_case)] + fn hash_end(&self, state: &mut S) { + let ($(ref $name,)* ref $last,) = *self; $($name.hash(state);)* + $last.hash_end(state); } } ); @@ -288,6 +311,10 @@ mod impls { self.len().hash(state); Hash::hash_slice(self, state) } + + fn hash_end(&self, state: &mut H) { + Hash::hash_slice(self, state) + } } @@ -296,6 +323,10 @@ mod impls { fn hash(&self, state: &mut H) { (**self).hash(state); } + + fn hash_end(&self, state: &mut H) { + (**self).hash_end(state); + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -303,6 +334,10 @@ mod impls { fn hash(&self, state: &mut H) { (**self).hash(state); } + + fn hash_end(&self, state: &mut H) { + (**self).hash_end(state); + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcoretest/hash/mod.rs b/src/libcoretest/hash/mod.rs index 4ea42644ecdfd..929d83c7a9d22 100644 --- a/src/libcoretest/hash/mod.rs +++ b/src/libcoretest/hash/mod.rs @@ -41,6 +41,12 @@ fn test_writer_hasher() { s.finish() } + fn hash_end(t: &T) -> u64 { + let mut s = MyHasher { hash: 0 }; + t.hash_end(&mut s); + s.finish() + } + assert_eq!(hash(&()), 0); assert_eq!(hash(&5_u8), 5); @@ -78,6 +84,13 @@ fn test_writer_hasher() { let ptr = 5_usize as *mut i32; assert_eq!(hash(&ptr), 5); + + assert_eq!(hash_end(&5_u32), 5); + assert_eq!(hash_end(&s), 97); + assert_eq!(hash_end(&("a", "b")), 97 + 98 + 0xFF); + assert_eq!(hash_end(&(42u8, "a")), 42 + 97); + assert_eq!(hash_end(&("a", 42u8)), 97 + 0xFF + 42); + assert_eq!(hash_end(&&s), 97); } struct Custom { hash: u64 } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index e08dc2acbc088..bc4f224469626 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -36,6 +36,7 @@ #![feature(dynamic_lib)] #![feature(enumset)] #![feature(fs_canonicalize)] +// #![feature(hash_end)] #![feature(hashmap_hasher)] #![feature(into_cow)] #![feature(iter_cmp)] diff --git a/src/librustc/middle/ty/context.rs b/src/librustc/middle/ty/context.rs index 830232cf373b8..1724c8d136036 100644 --- a/src/librustc/middle/ty/context.rs +++ b/src/librustc/middle/ty/context.rs @@ -692,6 +692,10 @@ impl<'tcx> Hash for InternedTy<'tcx> { fn hash(&self, s: &mut H) { self.ty.sty.hash(s) } + + fn hash_end(&self, s: &mut H) { + self.ty.sty.hash_end(s) + } } impl<'tcx> Borrow> for InternedTy<'tcx> { diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index e8796dd10b4f8..da016ed372115 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -148,7 +148,7 @@ pub fn make_hash(hash_state: &S, t: &T) -> SafeHash where T: Hash, S: HashState { let mut state = hash_state.hasher(); - t.hash(&mut state); + t.hash_end(&mut state); // We need to avoid 0 in order to prevent collisions with // EMPTY_HASH. We can maintain our precious uniform distribution // of initial indexes by unconditionally setting the MSB, diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 7409d9b45d28e..7e315ea98f866 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -211,6 +211,11 @@ impl Hash for OsString { fn hash(&self, state: &mut H) { (&**self).hash(state) } + + #[inline] + fn hash_end(&self, state: &mut H) { + (&**self).hash_end(state) + } } impl OsStr { @@ -348,6 +353,11 @@ impl Hash for OsStr { fn hash(&self, state: &mut H) { self.bytes().hash(state) } + + #[inline] + fn hash_end(&self, state: &mut H) { + self.bytes().hash(state) + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index a624b3521267a..4233f039fc306 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -222,6 +222,7 @@ #![feature(core_simd)] #![feature(drain)] #![feature(fnbox)] +// #![feature(hash_end)] #![feature(heap_api)] #![feature(int_error_internals)] #![feature(into_cow)] diff --git a/src/libsyntax/ext/deriving/hash.rs b/src/libsyntax/ext/deriving/hash.rs index 96be774ebdcf7..2c9f345b7c5a0 100644 --- a/src/libsyntax/ext/deriving/hash.rs +++ b/src/libsyntax/ext/deriving/hash.rs @@ -42,14 +42,30 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt, vec![path_std!(cx, core::hash::Hasher)])], }, explicit_self: borrowed_explicit_self(), - args: vec!(Ptr(Box::new(Literal(arg)), Borrowed(None, MutMutable))), + args: vec!(Ptr(Box::new(Literal(arg.clone())), Borrowed(None, MutMutable))), ret_ty: nil_ty(), attributes: vec![], is_unsafe: false, combine_substructure: combine_substructure(Box::new(|a, b, c| { - hash_substructure(a, b, c) + hash_substructure(a, b, c, false) })) - } + }, + MethodDef { + name: "hash_end", + generics: LifetimeBounds { + lifetimes: Vec::new(), + bounds: vec![("__H", + vec![path_std!(cx, core::hash::Hasher)])], + }, + explicit_self: borrowed_explicit_self(), + args: vec!(Ptr(Box::new(Literal(arg.clone())), Borrowed(None, MutMutable))), + ret_ty: nil_ty(), + attributes: vec![], + is_unsafe: false, + combine_substructure: combine_substructure(Box::new(|a, b, c| { + hash_substructure(a, b, c, true) + })) + }, ), associated_types: Vec::new(), }; @@ -57,14 +73,17 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt, hash_trait_def.expand(cx, mitem, item, push); } -fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P { +fn hash_substructure(cx: &mut ExtCtxt, + trait_span: Span, + substr: &Substructure, + is_end: bool) -> P { let state_expr = match (substr.nonself_args.len(), substr.nonself_args.get(0)) { (1, Some(o_f)) => o_f, _ => cx.span_bug(trait_span, "incorrect number of arguments in `derive(Hash)`") }; - let call_hash = |span, thing_expr| { + let call_hash = |span, thing_expr, use_end| { let hash_path = { - let strs = cx.std_path(&["hash", "Hash", "hash"]); + let strs = cx.std_path(&["hash", "Hash", if use_end { "hash_end" } else { "hash" }]); cx.expr_path(cx.path_global(span, strs)) }; @@ -84,15 +103,15 @@ fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) None => cx.expr_usize(trait_span, index) }; - stmts.push(call_hash(trait_span, discriminant)); + stmts.push(call_hash(trait_span, discriminant, false)); fs } _ => cx.span_bug(trait_span, "impossible substructure in `derive(Hash)`") }; - for &FieldInfo { ref self_, span, .. } in fields { - stmts.push(call_hash(span, self_.clone())); + for (index, &FieldInfo { ref self_, span, .. }) in fields.iter().enumerate() { + stmts.push(call_hash(span, self_.clone(), is_end && index == fields.len() - 1)); } cx.expr_block(cx.block(trait_span, stmts, None)) diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index f3b2c79a7dd04..0e86834287849 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -28,6 +28,7 @@ #![feature(associated_consts)] #![feature(drain)] #![feature(filling_drop)] +// #![feature(hash_end)] #![feature(libc)] #![feature(ref_slice)] #![feature(rustc_private)] diff --git a/src/libsyntax/util/interner.rs b/src/libsyntax/util/interner.rs index 6e9c161293de2..2b4320579090a 100644 --- a/src/libsyntax/util/interner.rs +++ b/src/libsyntax/util/interner.rs @@ -19,7 +19,7 @@ use std::cell::RefCell; use std::cmp::Ordering; use std::collections::HashMap; use std::fmt; -use std::hash::Hash; +use std::hash::{Hash,Hasher}; use std::ops::Deref; use std::rc::Rc; @@ -92,11 +92,21 @@ impl Interner { } } -#[derive(Clone, PartialEq, Hash, PartialOrd)] +#[derive(Clone, PartialEq, PartialOrd)] pub struct RcStr { string: Rc, } +impl Hash for RcStr { + fn hash(&self, s: &mut H) { + self.string.hash(s); + } + + fn hash_end(&self, s: &mut H) { + self.string.hash_end(s); + } +} + impl RcStr { pub fn new(string: &str) -> RcStr { RcStr {