diff --git a/vm/src/obj/objbytes.rs b/vm/src/obj/objbytes.rs index 98defeff0..3c904a81b 100644 --- a/vm/src/obj/objbytes.rs +++ b/vm/src/obj/objbytes.rs @@ -5,8 +5,10 @@ use super::super::pyobject::{ use super::super::vm::VirtualMachine; use super::objint; use super::objtype; +use num_bigint::ToBigInt; use num_traits::ToPrimitive; use std::cell::Ref; +use std::hash::{Hash, Hasher}; use std::ops::Deref; // Binary data support @@ -14,6 +16,7 @@ use std::ops::Deref; pub fn init(context: &PyContext) { let ref bytes_type = context.bytes_type; bytes_type.set_attr("__eq__", context.new_rustfunc(bytes_eq)); + bytes_type.set_attr("__hash__", context.new_rustfunc(bytes_hash)); bytes_type.set_attr("__new__", context.new_rustfunc(bytes_new)); bytes_type.set_attr("__repr__", context.new_rustfunc(bytes_repr)); } @@ -64,6 +67,15 @@ fn bytes_eq(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Ok(vm.ctx.new_bool(result)) } +fn bytes_hash(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(zelf, Some(vm.ctx.bytes_type()))]); + let data = get_value(zelf); + let mut hasher = std::collections::hash_map::DefaultHasher::new(); + data.hash(&mut hasher); + let hash = hasher.finish(); + Ok(vm.ctx.new_int(hash.to_bigint().unwrap())) +} + pub fn get_value<'a>(obj: &'a PyObjectRef) -> impl Deref> + 'a { Ref::map(obj.borrow(), |py_obj| { if let PyObjectKind::Bytes { ref value } = py_obj.kind { diff --git a/vm/src/obj/objint.rs b/vm/src/obj/objint.rs index 4ac548693..d62b3f121 100644 --- a/vm/src/obj/objint.rs +++ b/vm/src/obj/objint.rs @@ -8,10 +8,10 @@ use super::objstr; use super::objtype; use num_bigint::{BigInt, ToBigInt}; use num_traits::{Pow, Signed, ToPrimitive, Zero}; +use std::hash::{Hash, Hasher}; // This proxy allows for easy switching between types. -// TODO: maybe this is a good idea: -// type IntType = BigInt; +type IntType = BigInt; fn int_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(int, Some(vm.ctx.int_type()))]); @@ -47,7 +47,7 @@ pub fn to_int( vm: &mut VirtualMachine, obj: &PyObjectRef, base: u32, -) -> Result { +) -> Result { let val = if objtype::isinstance(obj, &vm.ctx.int_type()) { get_value(obj) } else if objtype::isinstance(obj, &vm.ctx.float_type()) { @@ -75,7 +75,7 @@ pub fn to_int( } // Retrieve inner int value: -pub fn get_value(obj: &PyObjectRef) -> BigInt { +pub fn get_value(obj: &PyObjectRef) -> IntType { if let PyObjectKind::Integer { value } = &obj.borrow().kind { value.clone() } else { @@ -171,9 +171,11 @@ fn int_ge(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { fn int_hash(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(zelf, Some(vm.ctx.int_type()))]); - - // TODO: how to hash int? - Ok(zelf.clone()) + let value = BigInt::from_pyobj(zelf); + let mut hasher = std::collections::hash_map::DefaultHasher::new(); + value.hash(&mut hasher); + let hash = hasher.finish(); + Ok(vm.ctx.new_int(hash.to_bigint().unwrap())) } fn int_abs(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { diff --git a/vm/src/obj/objstr.rs b/vm/src/obj/objstr.rs index 7a6c7e780..267c8abc3 100644 --- a/vm/src/obj/objstr.rs +++ b/vm/src/obj/objstr.rs @@ -7,6 +7,7 @@ use super::objsequence::PySliceableSequence; use super::objtype; use num_bigint::ToBigInt; use num_traits::ToPrimitive; +use std::hash::{Hash, Hasher}; pub fn init(context: &PyContext) { let ref str_type = context.str_type; @@ -15,6 +16,7 @@ pub fn init(context: &PyContext) { str_type.set_attr("__contains__", context.new_rustfunc(str_contains)); str_type.set_attr("__getitem__", context.new_rustfunc(str_getitem)); str_type.set_attr("__gt__", context.new_rustfunc(str_gt)); + str_type.set_attr("__hash__", context.new_rustfunc(str_hash)); str_type.set_attr("__len__", context.new_rustfunc(str_len)); str_type.set_attr("__mul__", context.new_rustfunc(str_mul)); str_type.set_attr("__new__", context.new_rustfunc(str_new)); @@ -124,6 +126,15 @@ fn str_add(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } } +fn str_hash(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(zelf, Some(vm.ctx.str_type()))]); + let value = get_value(zelf); + let mut hasher = std::collections::hash_map::DefaultHasher::new(); + value.hash(&mut hasher); + let hash = hasher.finish(); + Ok(vm.ctx.new_int(hash.to_bigint().unwrap())) +} + fn str_len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(s, Some(vm.ctx.str_type()))]); let sv = get_value(s); diff --git a/vm/src/obj/objtuple.rs b/vm/src/obj/objtuple.rs index 9a7b64395..a171a2c3a 100644 --- a/vm/src/obj/objtuple.rs +++ b/vm/src/obj/objtuple.rs @@ -9,7 +9,7 @@ use super::objsequence::{get_elements, get_item, seq_equal}; use super::objstr; use super::objtype; use num_bigint::ToBigInt; -use num_traits::ToPrimitive; +use std::hash::{Hash, Hasher}; fn tuple_eq(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!( @@ -30,22 +30,14 @@ fn tuple_eq(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { fn tuple_hash(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(zelf, Some(vm.ctx.tuple_type()))]); - - let mut x: usize = 0x345678; let elements = get_elements(zelf); - let len: usize = elements.len(); - let mut mult = 0xf4243; - - for elem in elements.iter() { - let y: usize = objint::get_value(&vm.call_method(elem, "__hash__", vec![])?) - .to_usize() - .unwrap(); - x = (x ^ y) * mult; - mult = mult + 82520 + len * 2; + let mut hasher = std::collections::hash_map::DefaultHasher::new(); + for element in elements.iter() { + let element_hash = objint::get_value(&vm.call_method(element, "__hash__", vec![])?); + element_hash.hash(&mut hasher); } - x += 97531; - - Ok(vm.ctx.new_int(x.to_bigint().unwrap())) + let hash = hasher.finish(); + Ok(vm.ctx.new_int(hash.to_bigint().unwrap())) } fn tuple_iter(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {