diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 7e28cda..4bfd554 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -46,6 +46,8 @@ jobs: run: cargo check --features serde - name: test serde run: cargo test --features serde + - name: check specialize + run: cargo check --features nightly-specialize linux_arm7: name: Linux ARMv7 runs-on: ubuntu-latest @@ -153,4 +155,4 @@ jobs: - uses: dtolnay/rust-toolchain@master with: toolchain: nightly - - run: cargo build --manifest-path=no_std_test/Cargo.toml \ No newline at end of file + - run: cargo build --manifest-path=no_std_test/Cargo.toml diff --git a/Cargo.toml b/Cargo.toml index f4bdf53..3df1f92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,6 +47,9 @@ atomic-polyfill = [ "dep:portable-atomic", "once_cell/critical-section"] # Nightly-only support for AES intrinsics on 32-bit ARM nightly-arm-aes = [] +# Nightly-only support for impls that work with `min_specialization` +nightly-specialize = [] + [[bench]] name = "ahash" path = "tests/bench.rs" @@ -75,9 +78,6 @@ lto = 'fat' debug-assertions = false codegen-units = 1 -[build-dependencies] -version_check = "0.9.4" - [dependencies] const-random = { version = "0.1.17", optional = true } serde = { version = "1.0.117", optional = true } diff --git a/build.rs b/build.rs index a136b36..c1a015d 100644 --- a/build.rs +++ b/build.rs @@ -4,9 +4,6 @@ use std::env; fn main() { println!("cargo:rerun-if-changed=build.rs"); - if let Some(true) = version_check::supports_feature("specialize") { - println!("cargo:rustc-cfg=feature=\"specialize\""); - } let arch = env::var("CARGO_CFG_TARGET_ARCH").expect("CARGO_CFG_TARGET_ARCH was not set"); if arch.eq_ignore_ascii_case("x86_64") || arch.eq_ignore_ascii_case("aarch64") diff --git a/src/aes_hash.rs b/src/aes_hash.rs index daf3ae4..0747f64 100644 --- a/src/aes_hash.rs +++ b/src/aes_hash.rs @@ -94,7 +94,7 @@ impl AHasher { } #[inline] - #[cfg(feature = "specialize")] + #[cfg(feature = "nightly-specialize")] fn short_finish(&self) -> u64 { let combined = aesenc(self.sum, self.enc); let result: [u64; 2] = aesdec(combined, combined).convert(); @@ -214,14 +214,14 @@ impl Hasher for AHasher { } } -#[cfg(feature = "specialize")] +#[cfg(feature = "nightly-specialize")] pub(crate) struct AHasherU64 { pub(crate) buffer: u64, pub(crate) pad: u64, } /// A specialized hasher for only primitives under 64 bits. -#[cfg(feature = "specialize")] +#[cfg(feature = "nightly-specialize")] impl Hasher for AHasherU64 { #[inline] fn finish(&self) -> u64 { @@ -264,11 +264,11 @@ impl Hasher for AHasherU64 { } } -#[cfg(feature = "specialize")] +#[cfg(feature = "nightly-specialize")] pub(crate) struct AHasherFixed(pub AHasher); /// A specialized hasher for fixed size primitives larger than 64 bits. -#[cfg(feature = "specialize")] +#[cfg(feature = "nightly-specialize")] impl Hasher for AHasherFixed { #[inline] fn finish(&self) -> u64 { @@ -311,12 +311,12 @@ impl Hasher for AHasherFixed { } } -#[cfg(feature = "specialize")] +#[cfg(feature = "nightly-specialize")] pub(crate) struct AHasherStr(pub AHasher); /// A specialized hasher for strings /// Note that the other types don't panic because the hash impl for String tacks on an unneeded call. (As does vec) -#[cfg(feature = "specialize")] +#[cfg(feature = "nightly-specialize")] impl Hasher for AHasherStr { #[inline] fn finish(&self) -> u64 { diff --git a/src/fallback_hash.rs b/src/fallback_hash.rs index bc5cbfe..a460872 100644 --- a/src/fallback_hash.rs +++ b/src/fallback_hash.rs @@ -115,7 +115,7 @@ impl AHasher { } #[inline] - #[cfg(feature = "specialize")] + #[cfg(feature = "nightly-specialize")] fn short_finish(&self) -> u64 { folded_multiply(self.buffer, self.pad) } @@ -199,14 +199,14 @@ impl Hasher for AHasher { } } -#[cfg(feature = "specialize")] +#[cfg(feature = "nightly-specialize")] pub(crate) struct AHasherU64 { pub(crate) buffer: u64, pub(crate) pad: u64, } /// A specialized hasher for only primitives under 64 bits. -#[cfg(feature = "specialize")] +#[cfg(feature = "nightly-specialize")] impl Hasher for AHasherU64 { #[inline] fn finish(&self) -> u64 { @@ -250,11 +250,11 @@ impl Hasher for AHasherU64 { } } -#[cfg(feature = "specialize")] +#[cfg(feature = "nightly-specialize")] pub(crate) struct AHasherFixed(pub AHasher); /// A specialized hasher for fixed size primitives larger than 64 bits. -#[cfg(feature = "specialize")] +#[cfg(feature = "nightly-specialize")] impl Hasher for AHasherFixed { #[inline] fn finish(&self) -> u64 { @@ -297,12 +297,12 @@ impl Hasher for AHasherFixed { } } -#[cfg(feature = "specialize")] +#[cfg(feature = "nightly-specialize")] pub(crate) struct AHasherStr(pub AHasher); /// A specialized hasher for a single string /// Note that the other types don't panic because the hash impl for String tacks on an unneeded call. (As does vec) -#[cfg(feature = "specialize")] +#[cfg(feature = "nightly-specialize")] impl Hasher for AHasherStr { #[inline] fn finish(&self) -> u64 { diff --git a/src/hash_quality_test.rs b/src/hash_quality_test.rs index f85e18a..92f209c 100644 --- a/src/hash_quality_test.rs +++ b/src/hash_quality_test.rs @@ -407,7 +407,7 @@ mod fallback_tests { #[test] fn fallback_keys_affect_every_byte() { //For fallback second key is not used in every hash. - #[cfg(all(not(feature = "specialize"), feature = "folded_multiply"))] + #[cfg(all(not(feature = "nightly-specialize"), feature = "folded_multiply"))] test_keys_affect_every_byte(0, |a, b| AHasher::new_with_keys(a ^ b, a)); test_keys_affect_every_byte("", |a, b| AHasher::new_with_keys(a ^ b, a)); test_keys_affect_every_byte((0, 0), |a, b| AHasher::new_with_keys(a ^ b, a)); @@ -504,7 +504,7 @@ mod aes_tests { #[test] fn aes_keys_affect_every_byte() { - #[cfg(not(feature = "specialize"))] + #[cfg(not(feature = "nightly-specialize"))] test_keys_affect_every_byte(0, AHasher::test_with_keys); test_keys_affect_every_byte("", AHasher::test_with_keys); test_keys_affect_every_byte((0, 0), AHasher::test_with_keys); diff --git a/src/lib.rs b/src/lib.rs index 7b88324..e1ba30a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -97,7 +97,7 @@ Note the import of [HashMapExt]. This is needed for the constructor. #![deny(clippy::correctness, clippy::complexity, clippy::perf)] #![allow(clippy::pedantic, clippy::cast_lossless, clippy::unreadable_literal)] #![cfg_attr(all(not(test), not(feature = "std")), no_std)] -#![cfg_attr(feature = "specialize", feature(min_specialization))] +#![cfg_attr(feature = "nightly-specialize", feature(min_specialization))] #![cfg_attr(feature = "nightly-arm-aes", feature(stdarch_arm_neon_intrinsics))] #[macro_use] @@ -262,42 +262,42 @@ pub(crate) trait BuildHasherExt: BuildHasher { impl BuildHasherExt for B { #[inline] - #[cfg(feature = "specialize")] + #[cfg(feature = "nightly-specialize")] default fn hash_as_u64(&self, value: &T) -> u64 { let mut hasher = self.build_hasher(); value.hash(&mut hasher); hasher.finish() } #[inline] - #[cfg(not(feature = "specialize"))] + #[cfg(not(feature = "nightly-specialize"))] fn hash_as_u64(&self, value: &T) -> u64 { let mut hasher = self.build_hasher(); value.hash(&mut hasher); hasher.finish() } #[inline] - #[cfg(feature = "specialize")] + #[cfg(feature = "nightly-specialize")] default fn hash_as_fixed_length(&self, value: &T) -> u64 { let mut hasher = self.build_hasher(); value.hash(&mut hasher); hasher.finish() } #[inline] - #[cfg(not(feature = "specialize"))] + #[cfg(not(feature = "nightly-specialize"))] fn hash_as_fixed_length(&self, value: &T) -> u64 { let mut hasher = self.build_hasher(); value.hash(&mut hasher); hasher.finish() } #[inline] - #[cfg(feature = "specialize")] + #[cfg(feature = "nightly-specialize")] default fn hash_as_str(&self, value: &T) -> u64 { let mut hasher = self.build_hasher(); value.hash(&mut hasher); hasher.finish() } #[inline] - #[cfg(not(feature = "specialize"))] + #[cfg(not(feature = "nightly-specialize"))] fn hash_as_str(&self, value: &T) -> u64 { let mut hasher = self.build_hasher(); value.hash(&mut hasher); diff --git a/src/random_state.rs b/src/random_state.rs index 096e0a7..cae6c58 100644 --- a/src/random_state.rs +++ b/src/random_state.rs @@ -11,7 +11,7 @@ cfg_if::cfg_if! { } } cfg_if::cfg_if! { - if #[cfg(feature = "specialize")]{ + if #[cfg(feature = "nightly-specialize")]{ use crate::BuildHasherExt; } } @@ -458,14 +458,14 @@ impl BuildHasher for RandomState { /// implementation of [`Hash`]. The way to create a combined hash of /// multiple values is to call [`Hash::hash`] multiple times using the same /// [`Hasher`], not to call this method repeatedly and combine the results. - #[cfg(feature = "specialize")] + #[cfg(feature = "nightly-specialize")] #[inline] fn hash_one(&self, x: T) -> u64 { RandomState::hash_one(self, x) } } -#[cfg(feature = "specialize")] +#[cfg(feature = "nightly-specialize")] impl BuildHasherExt for RandomState { #[inline] fn hash_as_u64(&self, value: &T) -> u64 { diff --git a/src/specialize.rs b/src/specialize.rs index acdf7d1..7173d3c 100644 --- a/src/specialize.rs +++ b/src/specialize.rs @@ -7,11 +7,11 @@ extern crate alloc; #[cfg(feature = "std")] extern crate std as alloc; -#[cfg(feature = "specialize")] +#[cfg(feature = "nightly-specialize")] use crate::BuildHasherExt; -#[cfg(feature = "specialize")] +#[cfg(feature = "nightly-specialize")] use alloc::string::String; -#[cfg(feature = "specialize")] +#[cfg(feature = "nightly-specialize")] use alloc::vec::Vec; /// Provides a way to get an optimized hasher for a given data type. @@ -21,7 +21,7 @@ pub(crate) trait CallHasher { fn get_hash(value: &H, build_hasher: &B) -> u64; } -#[cfg(not(feature = "specialize"))] +#[cfg(not(feature = "nightly-specialize"))] impl CallHasher for T where T: Hash + ?Sized, @@ -34,7 +34,7 @@ where } } -#[cfg(feature = "specialize")] +#[cfg(feature = "nightly-specialize")] impl CallHasher for T where T: Hash + ?Sized, @@ -49,7 +49,7 @@ where macro_rules! call_hasher_impl_u64 { ($typ:ty) => { - #[cfg(feature = "specialize")] + #[cfg(feature = "nightly-specialize")] impl CallHasher for $typ { #[inline] fn get_hash(value: &H, build_hasher: &B) -> u64 { @@ -77,7 +77,7 @@ call_hasher_impl_u64!(&i64); macro_rules! call_hasher_impl_fixed_length{ ($typ:ty) => { - #[cfg(feature = "specialize")] + #[cfg(feature = "nightly-specialize")] impl CallHasher for $typ { #[inline] fn get_hash(value: &H, build_hasher: &B) -> u64 { @@ -96,7 +96,7 @@ call_hasher_impl_fixed_length!(&i128); call_hasher_impl_fixed_length!(&usize); call_hasher_impl_fixed_length!(&isize); -#[cfg(feature = "specialize")] +#[cfg(feature = "nightly-specialize")] impl CallHasher for [u8] { #[inline] fn get_hash(value: &H, build_hasher: &B) -> u64 { @@ -104,7 +104,7 @@ impl CallHasher for [u8] { } } -#[cfg(feature = "specialize")] +#[cfg(feature = "nightly-specialize")] impl CallHasher for Vec { #[inline] fn get_hash(value: &H, build_hasher: &B) -> u64 { @@ -112,7 +112,7 @@ impl CallHasher for Vec { } } -#[cfg(feature = "specialize")] +#[cfg(feature = "nightly-specialize")] impl CallHasher for str { #[inline] fn get_hash(value: &H, build_hasher: &B) -> u64 { @@ -120,7 +120,7 @@ impl CallHasher for str { } } -#[cfg(all(feature = "specialize"))] +#[cfg(all(feature = "nightly-specialize"))] impl CallHasher for String { #[inline] fn get_hash(value: &H, build_hasher: &B) -> u64 { @@ -134,7 +134,7 @@ mod test { use crate::*; #[test] - #[cfg(feature = "specialize")] + #[cfg(feature = "nightly-specialize")] pub fn test_specialized_invoked() { let build_hasher = RandomState::with_seeds(1, 2, 3, 4); let shortened = u64::get_hash(&0, &build_hasher); @@ -186,7 +186,7 @@ mod test { str::get_hash(&"test", &build_hasher), String::get_hash(&"test".to_string(), &build_hasher) ); - #[cfg(feature = "specialize")] + #[cfg(feature = "nightly-specialize")] assert_eq!( str::get_hash(&"test", &build_hasher), <[u8]>::get_hash("test".as_bytes(), &build_hasher) @@ -206,7 +206,7 @@ mod test { str::get_hash(&&"test", &build_hasher), String::get_hash(&"test".to_string(), &build_hasher) ); - #[cfg(feature = "specialize")] + #[cfg(feature = "nightly-specialize")] assert_eq!( str::get_hash(&&"test", &build_hasher), <[u8]>::get_hash(&"test".to_string().into_bytes(), &build_hasher) diff --git a/tests/bench.rs b/tests/bench.rs index 2d000c0..c22ff61 100644 --- a/tests/bench.rs +++ b/tests/bench.rs @@ -1,4 +1,4 @@ -#![cfg_attr(feature = "specialize", feature(build_hasher_simple_hash_one))] +#![cfg_attr(feature = "nightly-specialize", feature(build_hasher_simple_hash_one))] use ahash::{AHasher, RandomState}; use criterion::*; diff --git a/tests/map_tests.rs b/tests/map_tests.rs index 97fdbee..26f44ae 100644 --- a/tests/map_tests.rs +++ b/tests/map_tests.rs @@ -1,4 +1,4 @@ -#![cfg_attr(feature = "specialize", feature(build_hasher_simple_hash_one))] +#![cfg_attr(feature = "nightly-specialize", feature(build_hasher_simple_hash_one))] use std::hash::{BuildHasher, Hash, Hasher}; @@ -151,13 +151,13 @@ fn check_for_collisions(build_hasher: &B, items: &[H], ); } -#[cfg(feature = "specialize")] +#[cfg(feature = "nightly-specialize")] #[allow(unused)] // False positive fn hash(b: &H, build_hasher: &B) -> u64 { build_hasher.hash_one(b) } -#[cfg(not(feature = "specialize"))] +#[cfg(not(feature = "nightly-specialize"))] #[allow(unused)] // False positive fn hash(b: &H, build_hasher: &B) -> u64 { let mut hasher = build_hasher.build_hasher();