Rollup merge of #104060 - ink-feather-org:const_hash, r=fee1-dead
Make `Hash`, `Hasher` and `BuildHasher` `#[const_trait]` and make `Sip` const `Hasher` This PR enables using Hashes in const context. r? ``@fee1-dead``
This commit is contained in:
commit
150e0ec393
8 changed files with 129 additions and 55 deletions
|
@ -86,7 +86,8 @@
|
|||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
use crate::fmt;
|
||||
use crate::marker;
|
||||
use crate::intrinsics::const_eval_select;
|
||||
use crate::marker::{self, Destruct};
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(deprecated)]
|
||||
|
@ -183,6 +184,7 @@ mod sip;
|
|||
/// [impl]: ../../std/primitive.str.html#impl-Hash-for-str
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_diagnostic_item = "Hash"]
|
||||
#[const_trait]
|
||||
pub trait Hash {
|
||||
/// Feeds this value into the given [`Hasher`].
|
||||
///
|
||||
|
@ -234,13 +236,25 @@ pub trait Hash {
|
|||
/// [`hash`]: Hash::hash
|
||||
/// [`hash_slice`]: Hash::hash_slice
|
||||
#[stable(feature = "hash_slice", since = "1.3.0")]
|
||||
fn hash_slice<H: Hasher>(data: &[Self], state: &mut H)
|
||||
fn hash_slice<H: ~const Hasher>(data: &[Self], state: &mut H)
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
for piece in data {
|
||||
piece.hash(state);
|
||||
//FIXME(const_trait_impl): revert to only a for loop
|
||||
fn rt<T: Hash, H: Hasher>(data: &[T], state: &mut H) {
|
||||
for piece in data {
|
||||
piece.hash(state)
|
||||
}
|
||||
}
|
||||
const fn ct<T: ~const Hash, H: ~const Hasher>(data: &[T], state: &mut H) {
|
||||
let mut i = 0;
|
||||
while i < data.len() {
|
||||
data[i].hash(state);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
// SAFETY: same behavior, CT just uses while instead of for
|
||||
unsafe { const_eval_select((data, state), ct, rt) };
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -313,6 +327,7 @@ pub use macros::Hash;
|
|||
/// [`write_u8`]: Hasher::write_u8
|
||||
/// [`write_u32`]: Hasher::write_u32
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[const_trait]
|
||||
pub trait Hasher {
|
||||
/// Returns the hash value for the values written so far.
|
||||
///
|
||||
|
@ -558,7 +573,8 @@ pub trait Hasher {
|
|||
}
|
||||
|
||||
#[stable(feature = "indirect_hasher_impl", since = "1.22.0")]
|
||||
impl<H: Hasher + ?Sized> Hasher for &mut H {
|
||||
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
|
||||
impl<H: ~const Hasher + ?Sized> const Hasher for &mut H {
|
||||
fn finish(&self) -> u64 {
|
||||
(**self).finish()
|
||||
}
|
||||
|
@ -638,6 +654,7 @@ impl<H: Hasher + ?Sized> Hasher for &mut H {
|
|||
/// [`build_hasher`]: BuildHasher::build_hasher
|
||||
/// [`HashMap`]: ../../std/collections/struct.HashMap.html
|
||||
#[stable(since = "1.7.0", feature = "build_hasher")]
|
||||
#[const_trait]
|
||||
pub trait BuildHasher {
|
||||
/// Type of the hasher that will be created.
|
||||
#[stable(since = "1.7.0", feature = "build_hasher")]
|
||||
|
@ -698,9 +715,10 @@ pub trait BuildHasher {
|
|||
/// );
|
||||
/// ```
|
||||
#[unstable(feature = "build_hasher_simple_hash_one", issue = "86161")]
|
||||
fn hash_one<T: Hash>(&self, x: T) -> u64
|
||||
fn hash_one<T: ~const Hash + ~const Destruct>(&self, x: T) -> u64
|
||||
where
|
||||
Self: Sized,
|
||||
Self::Hasher: ~const Hasher + ~const Destruct,
|
||||
{
|
||||
let mut hasher = self.build_hasher();
|
||||
x.hash(&mut hasher);
|
||||
|
@ -764,7 +782,8 @@ impl<H> fmt::Debug for BuildHasherDefault<H> {
|
|||
}
|
||||
|
||||
#[stable(since = "1.7.0", feature = "build_hasher")]
|
||||
impl<H: Default + Hasher> BuildHasher for BuildHasherDefault<H> {
|
||||
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
|
||||
impl<H: ~const Default + Hasher> const BuildHasher for BuildHasherDefault<H> {
|
||||
type Hasher = H;
|
||||
|
||||
fn build_hasher(&self) -> H {
|
||||
|
@ -806,14 +825,15 @@ mod impls {
|
|||
macro_rules! impl_write {
|
||||
($(($ty:ident, $meth:ident),)*) => {$(
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Hash for $ty {
|
||||
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
|
||||
impl const Hash for $ty {
|
||||
#[inline]
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
fn hash<H: ~const Hasher>(&self, state: &mut H) {
|
||||
state.$meth(*self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn hash_slice<H: Hasher>(data: &[$ty], state: &mut H) {
|
||||
fn hash_slice<H: ~const Hasher>(data: &[$ty], state: &mut H) {
|
||||
let newlen = data.len() * mem::size_of::<$ty>();
|
||||
let ptr = data.as_ptr() as *const u8;
|
||||
// SAFETY: `ptr` is valid and aligned, as this macro is only used
|
||||
|
@ -842,33 +862,37 @@ mod impls {
|
|||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Hash for bool {
|
||||
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
|
||||
impl const Hash for bool {
|
||||
#[inline]
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
fn hash<H: ~const Hasher>(&self, state: &mut H) {
|
||||
state.write_u8(*self as u8)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Hash for char {
|
||||
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
|
||||
impl const Hash for char {
|
||||
#[inline]
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
fn hash<H: ~const Hasher>(&self, state: &mut H) {
|
||||
state.write_u32(*self as u32)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Hash for str {
|
||||
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
|
||||
impl const Hash for str {
|
||||
#[inline]
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
fn hash<H: ~const Hasher>(&self, state: &mut H) {
|
||||
state.write_str(self);
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "never_hash", since = "1.29.0")]
|
||||
impl Hash for ! {
|
||||
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
|
||||
impl const Hash for ! {
|
||||
#[inline]
|
||||
fn hash<H: Hasher>(&self, _: &mut H) {
|
||||
fn hash<H: ~const Hasher>(&self, _: &mut H) {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
@ -876,9 +900,10 @@ mod impls {
|
|||
macro_rules! impl_hash_tuple {
|
||||
() => (
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Hash for () {
|
||||
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
|
||||
impl const Hash for () {
|
||||
#[inline]
|
||||
fn hash<H: Hasher>(&self, _state: &mut H) {}
|
||||
fn hash<H: ~const Hasher>(&self, _state: &mut H) {}
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -886,10 +911,11 @@ mod impls {
|
|||
maybe_tuple_doc! {
|
||||
$($name)+ @
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<$($name: Hash),+> Hash for ($($name,)+) where last_type!($($name,)+): ?Sized {
|
||||
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
|
||||
impl<$($name: ~const Hash),+> const Hash for ($($name,)+) where last_type!($($name,)+): ?Sized {
|
||||
#[allow(non_snake_case)]
|
||||
#[inline]
|
||||
fn hash<S: Hasher>(&self, state: &mut S) {
|
||||
fn hash<S: ~const Hasher>(&self, state: &mut S) {
|
||||
let ($(ref $name,)+) = *self;
|
||||
$($name.hash(state);)+
|
||||
}
|
||||
|
@ -932,24 +958,27 @@ mod impls {
|
|||
impl_hash_tuple! { T B C D E F G H I J K L }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Hash> Hash for [T] {
|
||||
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
|
||||
impl<T: ~const Hash> const Hash for [T] {
|
||||
#[inline]
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
fn hash<H: ~const Hasher>(&self, state: &mut H) {
|
||||
state.write_length_prefix(self.len());
|
||||
Hash::hash_slice(self, state)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized + Hash> Hash for &T {
|
||||
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
|
||||
impl<T: ?Sized + ~const Hash> const Hash for &T {
|
||||
#[inline]
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
fn hash<H: ~const Hasher>(&self, state: &mut H) {
|
||||
(**self).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized + Hash> Hash for &mut T {
|
||||
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
|
||||
impl<T: ?Sized + ~const Hash> const Hash for &mut T {
|
||||
#[inline]
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
(**self).hash(state);
|
||||
|
|
|
@ -118,7 +118,7 @@ macro_rules! load_int_le {
|
|||
/// Safety: this performs unchecked indexing of `buf` at `start..start+len`, so
|
||||
/// that must be in-bounds.
|
||||
#[inline]
|
||||
unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 {
|
||||
const unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 {
|
||||
debug_assert!(len < 8);
|
||||
let mut i = 0; // current byte index (from LSB) in the output u64
|
||||
let mut out = 0;
|
||||
|
@ -138,7 +138,8 @@ unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 {
|
|||
out |= (unsafe { *buf.get_unchecked(start + i) } as u64) << (i * 8);
|
||||
i += 1;
|
||||
}
|
||||
debug_assert_eq!(i, len);
|
||||
//FIXME(fee1-dead): use debug_assert_eq
|
||||
debug_assert!(i == len);
|
||||
out
|
||||
}
|
||||
|
||||
|
@ -150,8 +151,9 @@ impl SipHasher {
|
|||
since = "1.13.0",
|
||||
note = "use `std::collections::hash_map::DefaultHasher` instead"
|
||||
)]
|
||||
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
|
||||
#[must_use]
|
||||
pub fn new() -> SipHasher {
|
||||
pub const fn new() -> SipHasher {
|
||||
SipHasher::new_with_keys(0, 0)
|
||||
}
|
||||
|
||||
|
@ -162,8 +164,9 @@ impl SipHasher {
|
|||
since = "1.13.0",
|
||||
note = "use `std::collections::hash_map::DefaultHasher` instead"
|
||||
)]
|
||||
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
|
||||
#[must_use]
|
||||
pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher {
|
||||
pub const fn new_with_keys(key0: u64, key1: u64) -> SipHasher {
|
||||
SipHasher(SipHasher24 { hasher: Hasher::new_with_keys(key0, key1) })
|
||||
}
|
||||
}
|
||||
|
@ -176,7 +179,8 @@ impl SipHasher13 {
|
|||
since = "1.13.0",
|
||||
note = "use `std::collections::hash_map::DefaultHasher` instead"
|
||||
)]
|
||||
pub fn new() -> SipHasher13 {
|
||||
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
|
||||
pub const fn new() -> SipHasher13 {
|
||||
SipHasher13::new_with_keys(0, 0)
|
||||
}
|
||||
|
||||
|
@ -187,14 +191,15 @@ impl SipHasher13 {
|
|||
since = "1.13.0",
|
||||
note = "use `std::collections::hash_map::DefaultHasher` instead"
|
||||
)]
|
||||
pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 {
|
||||
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
|
||||
pub const fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 {
|
||||
SipHasher13 { hasher: Hasher::new_with_keys(key0, key1) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Sip> Hasher<S> {
|
||||
#[inline]
|
||||
fn new_with_keys(key0: u64, key1: u64) -> Hasher<S> {
|
||||
const fn new_with_keys(key0: u64, key1: u64) -> Hasher<S> {
|
||||
let mut state = Hasher {
|
||||
k0: key0,
|
||||
k1: key1,
|
||||
|
@ -209,7 +214,7 @@ impl<S: Sip> Hasher<S> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn reset(&mut self) {
|
||||
const fn reset(&mut self) {
|
||||
self.length = 0;
|
||||
self.state.v0 = self.k0 ^ 0x736f6d6570736575;
|
||||
self.state.v1 = self.k1 ^ 0x646f72616e646f6d;
|
||||
|
@ -220,7 +225,8 @@ impl<S: Sip> Hasher<S> {
|
|||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl super::Hasher for SipHasher {
|
||||
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
|
||||
impl const super::Hasher for SipHasher {
|
||||
#[inline]
|
||||
fn write(&mut self, msg: &[u8]) {
|
||||
self.0.hasher.write(msg)
|
||||
|
@ -238,7 +244,8 @@ impl super::Hasher for SipHasher {
|
|||
}
|
||||
|
||||
#[unstable(feature = "hashmap_internals", issue = "none")]
|
||||
impl super::Hasher for SipHasher13 {
|
||||
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
|
||||
impl const super::Hasher for SipHasher13 {
|
||||
#[inline]
|
||||
fn write(&mut self, msg: &[u8]) {
|
||||
self.hasher.write(msg)
|
||||
|
@ -255,7 +262,7 @@ impl super::Hasher for SipHasher13 {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: Sip> super::Hasher for Hasher<S> {
|
||||
impl<S: ~const Sip> const super::Hasher for Hasher<S> {
|
||||
// Note: no integer hashing methods (`write_u*`, `write_i*`) are defined
|
||||
// for this type. We could add them, copy the `short_write` implementation
|
||||
// in librustc_data_structures/sip128.rs, and add `write_u*`/`write_i*`
|
||||
|
@ -335,7 +342,7 @@ impl<S: Sip> super::Hasher for Hasher<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: Sip> Clone for Hasher<S> {
|
||||
impl<S: Sip> const Clone for Hasher<S> {
|
||||
#[inline]
|
||||
fn clone(&self) -> Hasher<S> {
|
||||
Hasher {
|
||||
|
@ -359,6 +366,7 @@ impl<S: Sip> Default for Hasher<S> {
|
|||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[const_trait]
|
||||
trait Sip {
|
||||
fn c_rounds(_: &mut State);
|
||||
fn d_rounds(_: &mut State);
|
||||
|
@ -367,7 +375,7 @@ trait Sip {
|
|||
#[derive(Debug, Clone, Default)]
|
||||
struct Sip13Rounds;
|
||||
|
||||
impl Sip for Sip13Rounds {
|
||||
impl const Sip for Sip13Rounds {
|
||||
#[inline]
|
||||
fn c_rounds(state: &mut State) {
|
||||
compress!(state);
|
||||
|
@ -384,7 +392,7 @@ impl Sip for Sip13Rounds {
|
|||
#[derive(Debug, Clone, Default)]
|
||||
struct Sip24Rounds;
|
||||
|
||||
impl Sip for Sip24Rounds {
|
||||
impl const Sip for Sip24Rounds {
|
||||
#[inline]
|
||||
fn c_rounds(state: &mut State) {
|
||||
compress!(state);
|
||||
|
|
|
@ -112,6 +112,7 @@
|
|||
#![feature(const_float_bits_conv)]
|
||||
#![feature(const_float_classify)]
|
||||
#![feature(const_fmt_arguments_new)]
|
||||
#![feature(const_hash)]
|
||||
#![feature(const_heap)]
|
||||
#![feature(const_convert)]
|
||||
#![feature(const_index_range_slice_index)]
|
||||
|
|
|
@ -9,16 +9,19 @@ struct MyHasher {
|
|||
hash: u64,
|
||||
}
|
||||
|
||||
impl Default for MyHasher {
|
||||
impl const Default for MyHasher {
|
||||
fn default() -> MyHasher {
|
||||
MyHasher { hash: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl Hasher for MyHasher {
|
||||
impl const Hasher for MyHasher {
|
||||
fn write(&mut self, buf: &[u8]) {
|
||||
for byte in buf {
|
||||
self.hash += *byte as u64;
|
||||
// FIXME(const_trait_impl): change to for loop
|
||||
let mut i = 0;
|
||||
while i < buf.len() {
|
||||
self.hash += buf[i] as u64;
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
fn write_str(&mut self, s: &str) {
|
||||
|
@ -32,12 +35,25 @@ impl Hasher for MyHasher {
|
|||
|
||||
#[test]
|
||||
fn test_writer_hasher() {
|
||||
fn hash<T: Hash>(t: &T) -> u64 {
|
||||
const fn hash<T: ~const Hash>(t: &T) -> u64 {
|
||||
let mut s = MyHasher { hash: 0 };
|
||||
t.hash(&mut s);
|
||||
s.finish()
|
||||
}
|
||||
|
||||
const {
|
||||
// FIXME(fee1-dead): assert_eq
|
||||
assert!(hash(&()) == 0);
|
||||
assert!(hash(&5_u8) == 5);
|
||||
assert!(hash(&5_u16) == 5);
|
||||
assert!(hash(&5_u32) == 5);
|
||||
|
||||
assert!(hash(&'a') == 97);
|
||||
|
||||
let s: &str = "a";
|
||||
assert!(hash(&s) == 97 + 0xFF);
|
||||
};
|
||||
|
||||
assert_eq!(hash(&()), 0);
|
||||
|
||||
assert_eq!(hash(&5_u8), 5);
|
||||
|
@ -97,7 +113,7 @@ struct CustomHasher {
|
|||
output: u64,
|
||||
}
|
||||
|
||||
impl Hasher for CustomHasher {
|
||||
impl const Hasher for CustomHasher {
|
||||
fn finish(&self) -> u64 {
|
||||
self.output
|
||||
}
|
||||
|
@ -109,27 +125,29 @@ impl Hasher for CustomHasher {
|
|||
}
|
||||
}
|
||||
|
||||
impl Default for CustomHasher {
|
||||
impl const Default for CustomHasher {
|
||||
fn default() -> CustomHasher {
|
||||
CustomHasher { output: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Custom {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
impl const Hash for Custom {
|
||||
fn hash<H: ~const Hasher>(&self, state: &mut H) {
|
||||
state.write_u64(self.hash);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_custom_state() {
|
||||
fn hash<T: Hash>(t: &T) -> u64 {
|
||||
const fn hash<T: ~const Hash>(t: &T) -> u64 {
|
||||
let mut c = CustomHasher { output: 0 };
|
||||
t.hash(&mut c);
|
||||
c.finish()
|
||||
}
|
||||
|
||||
assert_eq!(hash(&Custom { hash: 5 }), 5);
|
||||
|
||||
const { assert!(hash(&Custom { hash: 6 }) == 6) };
|
||||
}
|
||||
|
||||
// FIXME: Instantiated functions with i128 in the signature is not supported in Emscripten.
|
||||
|
|
|
@ -8,7 +8,6 @@ use core::{mem, slice};
|
|||
struct Bytes<'a>(&'a [u8]);
|
||||
|
||||
impl<'a> Hash for Bytes<'a> {
|
||||
#[allow(unused_must_use)]
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
let Bytes(v) = *self;
|
||||
state.write(v);
|
||||
|
@ -24,6 +23,20 @@ fn hash<T: Hash>(x: &T) -> u64 {
|
|||
hash_with(SipHasher::new(), x)
|
||||
}
|
||||
|
||||
#[test]
|
||||
const fn test_const_sip() {
|
||||
let val1 = 0x45;
|
||||
let val2 = 0xfeed;
|
||||
|
||||
const fn const_hash<T: ~const Hash>(x: &T) -> u64 {
|
||||
let mut st = SipHasher::new();
|
||||
x.hash(&mut st);
|
||||
st.finish()
|
||||
}
|
||||
|
||||
assert!(const_hash(&(val1)) != const_hash(&(val2)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(unused_must_use)]
|
||||
fn test_siphash_1_3() {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#![feature(const_caller_location)]
|
||||
#![feature(const_cell_into_inner)]
|
||||
#![feature(const_convert)]
|
||||
#![feature(const_hash)]
|
||||
#![feature(const_heap)]
|
||||
#![feature(const_maybe_uninit_as_mut_ptr)]
|
||||
#![feature(const_maybe_uninit_assume_init_read)]
|
||||
|
|
|
@ -3161,14 +3161,16 @@ impl DefaultHasher {
|
|||
#[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
|
||||
#[inline]
|
||||
#[allow(deprecated)]
|
||||
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
|
||||
#[must_use]
|
||||
pub fn new() -> DefaultHasher {
|
||||
pub const fn new() -> DefaultHasher {
|
||||
DefaultHasher(SipHasher13::new_with_keys(0, 0))
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
|
||||
impl Default for DefaultHasher {
|
||||
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
|
||||
impl const Default for DefaultHasher {
|
||||
/// Creates a new `DefaultHasher` using [`new`].
|
||||
/// See its documentation for more.
|
||||
///
|
||||
|
@ -3180,7 +3182,8 @@ impl Default for DefaultHasher {
|
|||
}
|
||||
|
||||
#[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
|
||||
impl Hasher for DefaultHasher {
|
||||
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
|
||||
impl const Hasher for DefaultHasher {
|
||||
// The underlying `SipHasher13` doesn't override the other
|
||||
// `write_*` methods, so it's ok not to forward them here.
|
||||
|
||||
|
|
|
@ -352,6 +352,7 @@
|
|||
//
|
||||
// Only for const-ness:
|
||||
#![feature(const_collections_with_hasher)]
|
||||
#![feature(const_hash)]
|
||||
#![feature(const_io_structs)]
|
||||
#![feature(const_ip)]
|
||||
#![feature(const_ipv4)]
|
||||
|
|
Loading…
Add table
Reference in a new issue