1use std::{
4 hash::{BuildHasherDefault, Hasher},
5 marker::PhantomData,
6 num::{
7 NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroIsize, NonZeroU8, NonZeroU16,
8 NonZeroU32, NonZeroU64, NonZeroUsize,
9 },
10};
11
12mod sealed {
13 pub trait SealedInteger {}
14}
15
16#[derive(Debug, Default, Clone, Copy)]
18pub struct IntHasher<T: IsInteger>(u64, PhantomData<T>);
19
20pub type BuildIntHasher<T> = BuildHasherDefault<IntHasher<T>>;
24
25pub type IntHashSet<T> = std::collections::HashSet<T, BuildIntHasher<T>>;
36
37pub type IntHashMap<K, V> = std::collections::HashMap<K, V, BuildIntHasher<K>>;
48
49pub trait IsInteger: sealed::SealedInteger {}
69
70macro_rules! impl_is_integer {
71 ( $($integer:ty),+ $(,)? ) => {
72 $(
73 impl sealed::SealedInteger for $integer {}
74 impl IsInteger for $integer {}
75 )+
76 };
77}
78
79impl_is_integer!(
80 u8,
81 u16,
82 u32,
83 u64,
84 usize,
85 i8,
86 i16,
87 i32,
88 i64,
89 isize,
90 NonZeroU8,
91 NonZeroU16,
92 NonZeroU32,
93 NonZeroU64,
94 NonZeroUsize,
95 NonZeroI8,
96 NonZeroI16,
97 NonZeroI32,
98 NonZeroI64,
99 NonZeroIsize,
100);
101
102impl<T: IsInteger> Hasher for IntHasher<T> {
103 fn write(&mut self, _: &[u8]) {
104 panic!("Invalid use of IntHasher")
105 }
106
107 fn write_u8(&mut self, n: u8) {
108 self.0 = u64::from(n)
109 }
110 fn write_u16(&mut self, n: u16) {
111 self.0 = u64::from(n)
112 }
113 fn write_u32(&mut self, n: u32) {
114 self.0 = u64::from(n)
115 }
116 fn write_u64(&mut self, n: u64) {
117 self.0 = n
118 }
119 fn write_usize(&mut self, n: usize) {
120 self.0 = n as u64
121 }
122
123 fn write_i8(&mut self, n: i8) {
124 self.0 = n as u64
125 }
126 fn write_i16(&mut self, n: i16) {
127 self.0 = n as u64
128 }
129 fn write_i32(&mut self, n: i32) {
130 self.0 = n as u64
131 }
132 fn write_i64(&mut self, n: i64) {
133 self.0 = n as u64
134 }
135 fn write_isize(&mut self, n: isize) {
136 self.0 = n as u64
137 }
138
139 fn finish(&self) -> u64 {
140 self.0
141 }
142}
143
144#[cfg(test)]
145mod tests {
146 use super::*;
147
148 #[test]
149 fn test_hashset() {
150 let mut int_hashset =
151 IntHashSet::<u32>::with_capacity_and_hasher(1, BuildIntHasher::default());
152 assert!(int_hashset.insert(2));
153 assert!(int_hashset.insert(3));
154 assert!(int_hashset.capacity() >= 2);
155 }
156
157 #[test]
158 fn test_hashmap() {
159 let mut int_hashmap =
160 IntHashMap::<i16, String>::with_capacity_and_hasher(1, BuildIntHasher::default());
161 assert!(int_hashmap.insert(2, "test2".to_string()).is_none());
162 assert!(int_hashmap.insert(3, "test3".to_string()).is_none());
163 assert!(int_hashmap.capacity() >= 2);
164 }
165}