diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index 16a701359..59a216b7b 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -250,12 +250,9 @@ fn builtin_format( format_spec: OptionalArg, vm: &VirtualMachine, ) -> PyResult { - let format_spec = format_spec.into_option().unwrap_or_else(|| { - PyString { - value: "".to_string(), - } - .into_ref(vm) - }); + let format_spec = format_spec + .into_option() + .unwrap_or_else(|| PyString::from("").into_ref(vm)); vm.call_method(&value, "__format__", vec![format_spec.into_object()])? .downcast() diff --git a/vm/src/obj/objstr.rs b/vm/src/obj/objstr.rs index c7a3fcbb0..f9e0d35d8 100644 --- a/vm/src/obj/objstr.rs +++ b/vm/src/obj/objstr.rs @@ -54,6 +54,7 @@ use unicode_categories::UnicodeCategories; pub struct PyString { // TODO: shouldn't be public pub value: String, + hash: Cell>, } impl PyString { @@ -64,8 +65,15 @@ impl PyString { impl From<&str> for PyString { fn from(s: &str) -> PyString { + s.to_string().into() + } +} + +impl From for PyString { + fn from(s: String) -> PyString { PyString { - value: s.to_string(), + value: s, + hash: Cell::default(), } } } @@ -80,16 +88,13 @@ impl fmt::Display for PyString { impl TryIntoRef for String { fn try_into_ref(self, vm: &VirtualMachine) -> PyResult> { - Ok(PyString { value: self }.into_ref(vm)) + Ok(PyString::from(self).into_ref(vm)) } } impl TryIntoRef for &str { fn try_into_ref(self, vm: &VirtualMachine) -> PyResult> { - Ok(PyString { - value: self.to_string(), - } - .into_ref(vm)) + Ok(PyString::from(self).into_ref(vm)) } } @@ -259,7 +264,14 @@ impl PyString { #[pymethod(name = "__hash__")] fn hash(&self, _vm: &VirtualMachine) -> pyhash::PyHash { - pyhash::hash_value(&self.value) + match self.hash.get() { + Some(hash) => hash, + None => { + let hash = pyhash::hash_value(&self.value); + self.hash.set(Some(hash)); + hash + } + } } #[pymethod(name = "__len__")] diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 3d9297dd4..56a9ad112 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -380,7 +380,7 @@ impl PyContext { } pub fn new_str(&self, s: String) -> PyObjectRef { - PyObject::new(objstr::PyString { value: s }, self.str_type(), None) + PyObject::new(objstr::PyString::from(s), self.str_type(), None) } pub fn new_bytes(&self, data: Vec) -> PyObjectRef {