1use std::hash::{Hash, Hasher};
27
28use num_bigint::BigInt;
29use num_traits::FromPrimitive as _;
30
31use crate::int::Int;
32use crate::object::Object;
33use crate::text::Str;
34
35pub const MODULUS: u64 = (1 << 61) - 1;
37
38const BITS: u32 = 61;
40
41const INF: i64 = 314_159;
43
44const NONE: i64 = 0xFCA8_6420;
47
48const ELLIPSIS: i64 = 0x1CE1_1195;
51const NOT_IMPLEMENTED: i64 = 0x2B0E_9C7A;
52
53const XXPRIME_1: u64 = 11_400_714_785_074_694_791;
55const XXPRIME_2: u64 = 14_029_467_366_897_019_727;
56const XXPRIME_5: u64 = 2_870_177_450_012_600_261;
57
58#[derive(Debug, Clone, Copy, PartialEq, Eq)]
60pub struct Unhashable {
61 pub type_name: &'static str,
64}
65
66impl Unhashable {
67 #[must_use]
69 pub fn message(&self) -> String {
70 format!("unhashable type: '{}'", self.type_name)
71 }
72}
73
74pub fn hash(object: &Object) -> Result<i64, Unhashable> {
80 match object {
81 Object::None => Ok(NONE),
82 Object::Ellipsis => Ok(ELLIPSIS),
83 Object::NotImplemented => Ok(NOT_IMPLEMENTED),
84 Object::Bool(value) => Ok(i64::from(*value)),
86 Object::Int(value) => Ok(int(value)),
87 Object::Float(value) => Ok(float(*value)),
88 Object::Str(value) => Ok(text(value)),
89 Object::Bytes(value) => Ok(blob(value)),
90 Object::Tuple(items) => tuple(items),
91 Object::Slice(value) => lanes(value.parts().into_iter(), 3),
96 Object::Native(value) => Ok(value
105 .hash()
106 .unwrap_or_else(|| address(std::ptr::from_ref(value.as_ref()).cast::<()>()))),
107 Object::List(_) => Err(Unhashable { type_name: "list" }),
115 Object::Dict(_) => Err(Unhashable { type_name: "dict" }),
116 Object::Set(_) => Err(Unhashable { type_name: "set" }),
117 }
118}
119
120fn address(pointer: *const ()) -> i64 {
124 let rotated = pointer.addr().rotate_right(4);
125 settle(rotated.cast_signed() as i64)
126}
127
128fn int(value: &Int) -> i64 {
134 let reduced: i128 = match value {
137 Int::Small(n) => i128::from(*n) % i128::from(MODULUS),
139 Int::Big(n) => (n.as_ref() % BigInt::from(MODULUS))
140 .try_into()
141 .expect("a remainder mod 2^61-1 is far inside an i128"),
142 };
143 let reduced = i64::try_from(reduced).expect("a remainder mod 2^61-1 fits in an i64");
144 settle(reduced)
145}
146
147#[expect(
155 clippy::cast_possible_truncation,
156 clippy::cast_possible_wrap,
157 clippy::cast_precision_loss,
158 clippy::cast_sign_loss,
159 reason = "every cast in here is exact by construction, and the comment \
160 next to each one says what makes it exact"
161)]
162fn float(value: f64) -> i64 {
163 if !value.is_finite() {
164 return if value.is_infinite() {
167 if value > 0.0 { INF } else { -INF }
168 } else {
169 0
170 };
171 }
172 let (mut mantissa, mut exponent) = frexp(value);
173 let sign = if mantissa < 0.0 {
174 mantissa = -mantissa;
175 -1
176 } else {
177 1
178 };
179
180 let mut x: u64 = 0;
181 while mantissa != 0.0 {
182 x = ((x << 28) & MODULUS) | (x >> (BITS - 28));
183 mantissa *= 268_435_456.0; exponent -= 28;
185 let digit = mantissa as u64;
188 mantissa -= digit as f64;
189 x += digit;
190 if x >= MODULUS {
191 x -= MODULUS;
192 }
193 }
194
195 let bits = BITS as i32;
199 let exponent = if exponent >= 0 {
200 exponent % bits
201 } else {
202 bits - 1 - ((-1 - exponent) % bits)
203 } as u32;
204 x = ((x << exponent) & MODULUS) | (x >> (BITS - exponent));
205
206 settle((x as i64) * sign)
208}
209
210fn frexp(value: f64) -> (f64, i32) {
213 if value == 0.0 {
214 return (value, 0);
216 }
217 let bits = value.to_bits();
218 let biased = ((bits >> 52) & 0x7ff) as i32;
219 if biased == 0 {
220 let (mantissa, exponent) = frexp(value * f64::from_bits(0x43f0_0000_0000_0000));
223 return (mantissa, exponent - 64);
224 }
225 let mantissa = f64::from_bits((bits & !(0x7ffu64 << 52)) | (1022u64 << 52));
228 (mantissa, biased - 1022)
229}
230
231fn tuple(items: &[Object]) -> Result<i64, Unhashable> {
233 lanes(items.iter(), items.len())
234}
235
236#[expect(
239 clippy::cast_possible_wrap,
240 clippy::cast_sign_loss,
241 clippy::decimal_bitwise_operands,
242 reason = "the arithmetic is unsigned and wrapping on purpose, and the odd \
243 constant is written the way CPython writes it so the two can be \
244 compared by eye"
245)]
246fn lanes<'a>(items: impl Iterator<Item = &'a Object>, len: usize) -> Result<i64, Unhashable> {
247 let mut acc = XXPRIME_5;
248 for item in items {
249 let lane = hash(item)? as u64;
250 acc = acc.wrapping_add(lane.wrapping_mul(XXPRIME_2));
251 acc = acc.rotate_left(31);
252 acc = acc.wrapping_mul(XXPRIME_1);
253 }
254 acc = acc.wrapping_add((len as u64) ^ (XXPRIME_5 ^ 3_527_539));
257 if acc == u64::MAX {
259 return Ok(1_546_275_796);
260 }
261 Ok(acc as i64)
262}
263
264#[expect(
269 clippy::cast_possible_wrap,
270 reason = "a hash is a number, and which half of the range it lands in is \
271 not information anyone is entitled to"
272)]
273fn text(value: &Str) -> i64 {
274 let mut hasher = std::hash::DefaultHasher::new();
275 match value {
276 Str::Utf8(s) => {
277 0u8.hash(&mut hasher);
278 s.hash(&mut hasher);
279 }
280 Str::Wide(w) => {
281 1u8.hash(&mut hasher);
282 w.hash(&mut hasher);
283 }
284 }
285 settle(hasher.finish() as i64)
286}
287
288#[expect(clippy::cast_possible_wrap, reason = "the same as for a string")]
291fn blob(value: &[u8]) -> i64 {
292 let mut hasher = std::hash::DefaultHasher::new();
293 2u8.hash(&mut hasher);
294 value.hash(&mut hasher);
295 settle(hasher.finish() as i64)
296}
297
298const fn settle(value: i64) -> i64 {
301 if value == -1 { -2 } else { value }
302}
303
304#[derive(Debug, Clone)]
316pub struct Key {
317 object: Object,
318 hash: i64,
319}
320
321impl Key {
322 pub fn new(object: Object) -> Result<Self, Unhashable> {
328 let hash = hash(&object)?;
329 Ok(Key { object, hash })
330 }
331
332 #[must_use]
334 pub const fn object(&self) -> &Object {
335 &self.object
336 }
337
338 #[must_use]
340 pub fn into_object(self) -> Object {
341 self.object
342 }
343
344 #[must_use]
346 pub const fn hash(&self) -> i64 {
347 self.hash
348 }
349}
350
351impl Hash for Key {
352 fn hash<H: Hasher>(&self, state: &mut H) {
353 state.write_i64(self.hash);
354 }
355}
356
357impl PartialEq for Key {
358 fn eq(&self, other: &Self) -> bool {
364 self.object.same_value(&other.object)
365 }
366}
367
368impl Eq for Key {}
369
370#[expect(
373 clippy::cast_possible_truncation,
374 reason = "the cast is guarded by the range check on the line above it, and \
375 both ends of that range are exactly representable"
376)]
377pub(crate) fn int_eq_float(int: &Int, float: f64) -> bool {
378 if !float.is_finite() || float.fract() != 0.0 {
381 return false;
382 }
383 if let Int::Small(n) = int {
384 if (-9_223_372_036_854_775_808.0..9_223_372_036_854_775_808.0).contains(&float) {
386 return *n == float as i64;
387 }
388 }
389 BigInt::from_f64(float).is_some_and(|value| value == int.to_big())
391}
392
393#[cfg(test)]
394#[expect(
395 clippy::unreadable_literal,
396 clippy::approx_constant,
397 reason = "these are the numbers a CPython 3.14 printed, kept in the form it \
398 printed them so that a reader can check them against it"
399)]
400mod tests {
401 use super::*;
402
403 fn h(object: &Object) -> i64 {
404 hash(object).expect("expected this to be hashable")
405 }
406
407 #[test]
410 fn an_integer_hashes_as_its_value_modulo_the_prime() {
411 for (value, expected) in [
412 (0i64, 0i64),
413 (1, 1),
414 (2, 2),
415 (7, 7),
416 (2305843009213693950, 2305843009213693950),
417 (2305843009213693951, 0),
419 (2305843009213693952, 1),
420 (4611686018427387904, 2),
421 (-2, -2),
422 ] {
423 assert_eq!(h(&Object::int(value)), expected, "hash({value})");
424 }
425 }
426
427 #[test]
430 fn the_one_hash_nothing_is_allowed_to_have() {
431 assert_eq!(h(&Object::int(-1)), -2);
432 assert_eq!(h(&Object::Float(-1.0)), -2);
433 assert_eq!(h(&Object::int(-2)), -2);
435 }
436
437 #[test]
438 fn a_big_integer_hashes_the_same_way_a_small_one_does() {
439 for (digits, expected) in [
440 ("100000000000000000000", 848750603811160107i64),
441 ("-100000000000000000000", -848750603811160107),
442 ("1208925819614629174706176", 524288),
443 ("-1208925819614629174706176", -524288),
444 (
445 "1606938044258990275541962092341162602522202993782792835313721",
446 143417,
447 ),
448 (
449 "-1606938044258990275541962092341162602522202993782792835313721",
450 -143417,
451 ),
452 ] {
453 let (text, sign) = digits
454 .strip_prefix('-')
455 .map_or((digits, 1), |rest| (rest, -1));
456 let value = Int::parse(text, 10).expect("expected this to parse");
457 let value = if sign < 0 { value.neg() } else { value };
458 assert_eq!(h(&Object::Int(value)), expected, "hash({digits})");
459 }
460 }
461
462 #[test]
463 fn a_float_hashes_as_its_value_too() {
464 for (value, expected) in [
465 (0.0f64, 0i64),
466 (-0.0, 0),
467 (1.0, 1),
468 (1024.0, 1024),
469 (0.5, 1152921504606846976),
470 (1.5, 1152921504606846977),
471 (-1.5, -1152921504606846977),
472 (-2.5, -1152921504606846978),
473 (0.1, 230584300921369408),
474 (-0.1, -230584300921369408),
475 (1e16, 10000000000000000),
476 (1e300, 1224995262755759164),
477 (-1e300, -1224995262755759164),
478 (1e-300, 482449582752280463),
479 (3.14159265358979, 326490430436033539),
480 (f64::MAX, 2234066890152476671),
481 (f64::MIN_POSITIVE, 32768),
482 (5e-324, 16777216),
485 ] {
486 assert_eq!(h(&Object::Float(value)), expected, "hash({value:?})");
487 }
488 }
489
490 #[test]
491 fn an_infinity_hashes_to_the_number_it_always_has() {
492 assert_eq!(h(&Object::Float(f64::INFINITY)), 314159);
493 assert_eq!(h(&Object::Float(f64::NEG_INFINITY)), -314159);
494 }
495
496 #[test]
499 fn the_same_number_in_three_types_has_one_hash() {
500 assert_eq!(h(&Object::int(1)), h(&Object::Float(1.0)));
501 assert_eq!(h(&Object::int(1)), h(&Object::Bool(true)));
502 assert_eq!(h(&Object::int(0)), h(&Object::Bool(false)));
503 let big = Int::parse("1208925819614629174706176", 10).expect("expected this to parse");
505 assert_eq!(h(&Object::Int(big)), h(&Object::Float(2.0f64.powi(80))));
506 }
507
508 #[test]
509 fn a_tuple_hashes_the_way_cpython_hashes_one() {
510 let t = |items: Vec<Object>| h(&Object::tuple(items));
511 assert_eq!(t(vec![]), 5740354900026072187);
512 assert_eq!(t(vec![Object::int(1)]), -6644214454873602895);
513 assert_eq!(t(vec![Object::int(0)]), -8753497827991233192);
514 assert_eq!(t(vec![Object::int(-1)]), 8078679518589016365);
515 assert_eq!(
516 t(vec![Object::int(1), Object::int(2)]),
517 -3550055125485641917
518 );
519 assert_eq!(
520 t(vec![Object::int(1), Object::int(2), Object::int(3)]),
521 529344067295497451
522 );
523 assert_eq!(
524 t(vec![
525 Object::tuple(vec![Object::int(1), Object::int(2)]),
526 Object::int(3)
527 ]),
528 -333907151259015829
529 );
530 assert_eq!(t((0..20).map(Object::int).collect()), -9217304902224717415);
531 }
532
533 #[test]
534 fn a_list_has_no_hash_and_neither_does_a_tuple_holding_one() {
535 let refused = hash(&Object::list(vec![])).expect_err("a list has no hash");
536 assert_eq!(refused.message(), "unhashable type: 'list'");
537 let nested = Object::tuple(vec![Object::int(1), Object::list(vec![])]);
540 assert_eq!(
541 hash(&nested).expect_err("a tuple holding a list has no hash"),
542 refused
543 );
544 }
545
546 #[test]
547 fn equal_strings_hash_equally_and_different_ones_usually_do_not() {
548 assert_eq!(h(&Object::str("hello")), h(&Object::str("hello")));
549 assert_ne!(h(&Object::str("hello")), h(&Object::str("hellp")));
550 assert_ne!(
553 h(&Object::str("abc")),
554 h(&Object::Bytes(std::rc::Rc::from(&b"abc"[..])))
555 );
556 }
557
558 #[test]
559 fn a_key_is_the_hash_and_pythons_equality_rather_than_rusts() {
560 let key = |object| Key::new(object).expect("expected this to be hashable");
561 assert_eq!(key(Object::int(1)), key(Object::Float(1.0)));
562 assert_eq!(key(Object::int(1)), key(Object::Bool(true)));
563 assert_eq!(key(Object::int(0)), key(Object::Bool(false)));
564 assert_ne!(key(Object::int(1)), key(Object::int(2)));
565 assert_ne!(key(Object::str("1")), key(Object::int(1)));
566 assert_eq!(key(Object::int(1)).hash(), 1);
567
568 let refused = Key::new(Object::list(vec![])).expect_err("a list is not a key");
569 assert_eq!(refused.message(), "unhashable type: 'list'");
570 }
571
572 #[test]
580 fn a_nan_can_be_a_key_and_can_be_found_again() {
581 let nan = Object::Float(f64::NAN);
582 let key = Key::new(nan.clone()).expect("expected this to be hashable");
583 let same = Key::new(nan).expect("expected this to be hashable");
584 assert_eq!(key, same);
585 let other = Key::new(Object::Float(1.0)).expect("expected this to be hashable");
587 assert_ne!(key, other);
588 assert!(!Object::Float(f64::NAN).equals(&Object::Float(f64::NAN)));
589 }
590
591 #[test]
592 fn an_integer_and_a_float_are_equal_when_they_are_the_same_number() {
593 assert!(int_eq_float(&Int::Small(1), 1.0));
594 assert!(!int_eq_float(&Int::Small(1), 1.5));
595 assert!(!int_eq_float(&Int::Small(1), f64::NAN));
596 assert!(!int_eq_float(&Int::Small(1), f64::INFINITY));
597 assert!(int_eq_float(
598 &Int::Small(i64::MIN),
599 -9_223_372_036_854_775_808.0
600 ));
601 let big = Int::parse("1208925819614629174706176", 10).expect("expected this to parse");
604 assert!(int_eq_float(&big, 2.0f64.powi(80)));
605 assert!(!int_eq_float(&big.add(&Int::Small(1)), 2.0f64.powi(80)));
606 }
607}