diff --git a/src/deserialize/backend/json.rs b/src/deserialize/backend/json.rs index 4a962b0e..bb1b2bc2 100644 --- a/src/deserialize/backend/json.rs +++ b/src/deserialize/backend/json.rs @@ -128,14 +128,7 @@ impl<'de> Visitor<'de> for JsonValue { while let Some(key) = map.next_key::>()? { let pykey = get_unicode_key(&key); let pyval = map.next_value_seed(self)?; - let _ = unsafe { - pyo3_ffi::_PyDict_SetItem_KnownHash( - dict_ptr, - pykey, - pyval.as_ptr(), - str_hash!(pykey), - ) - }; + let _ = pydict_setitem!(dict_ptr, pykey, pyval.as_ptr()); reverse_pydict_incref!(pykey); reverse_pydict_incref!(pyval.as_ptr()); } diff --git a/src/deserialize/backend/yyjson.rs b/src/deserialize/backend/yyjson.rs index c5538b4b..509ecdec 100644 --- a/src/deserialize/backend/yyjson.rs +++ b/src/deserialize/backend/yyjson.rs @@ -230,12 +230,6 @@ fn populate_yy_array(list: *mut pyo3_ffi::PyObject, elem: *mut yyjson_val) { } } -macro_rules! add_to_dict { - ($dict:expr, $pykey:expr, $pyval:expr) => { - unsafe { pyo3_ffi::_PyDict_SetItem_KnownHash($dict, $pykey, $pyval, str_hash!($pykey)) } - }; -} - #[inline(never)] fn populate_yy_object(dict: *mut pyo3_ffi::PyObject, elem: *mut yyjson_val) { unsafe { @@ -257,7 +251,7 @@ fn populate_yy_object(dict: *mut pyo3_ffi::PyObject, elem: *mut yyjson_val) { next_val = next_key.add(1); if is_yyjson_tag!(val, TAG_ARRAY) { let pyval = ffi!(PyList_New(unsafe_yyjson_get_len(val) as isize)); - add_to_dict!(dict, pykey, pyval); + pydict_setitem!(dict, pykey, pyval.as_ptr()); reverse_pydict_incref!(pykey); reverse_pydict_incref!(pyval); if unsafe_yyjson_get_len(val) > 0 { @@ -265,7 +259,7 @@ fn populate_yy_object(dict: *mut pyo3_ffi::PyObject, elem: *mut yyjson_val) { } } else { let pyval = ffi!(_PyDict_NewPresized(unsafe_yyjson_get_len(val) as isize)); - add_to_dict!(dict, pykey, pyval); + pydict_setitem!(dict, pykey, pyval.as_ptr()); reverse_pydict_incref!(pykey); reverse_pydict_incref!(pyval); if unsafe_yyjson_get_len(val) > 0 { @@ -286,7 +280,7 @@ fn populate_yy_object(dict: *mut pyo3_ffi::PyObject, elem: *mut yyjson_val) { ElementType::Array => unreachable!(), ElementType::Object => unreachable!(), }; - add_to_dict!(dict, pykey, pyval.as_ptr()); + pydict_setitem!(dict, pykey, pyval.as_ptr()); reverse_pydict_incref!(pykey); reverse_pydict_incref!(pyval.as_ptr()); } diff --git a/src/deserialize/pyobject.rs b/src/deserialize/pyobject.rs index 9ad9b090..303c4028 100644 --- a/src/deserialize/pyobject.rs +++ b/src/deserialize/pyobject.rs @@ -22,6 +22,7 @@ pub fn get_unicode_key(key_str: &str) -> *mut pyo3_ffi::PyObject { || hash, || { let pyob = unicode_from_str(key_str); + #[cfg(feature = "setitem_knownhash")] hash_str(pyob); CachedKey::new(pyob) }, diff --git a/src/str/ffi.rs b/src/str/ffi.rs index 21841a88..188e7de1 100644 --- a/src/str/ffi.rs +++ b/src/str/ffi.rs @@ -1,19 +1,19 @@ // SPDX-License-Identifier: (Apache-2.0 OR MIT) -use core::ffi::c_void; use pyo3_ffi::*; // see unicodeobject.h for documentation +#[cfg(feature = "setitem_knownhash")] #[inline] pub fn hash_str(op: *mut PyObject) -> Py_hash_t { unsafe { - let data_ptr: *mut c_void = if (*op.cast::()).compact() == 1 + let data_ptr: *mut core::ffi::c_void = if (*op.cast::()).compact() == 1 && (*op.cast::()).ascii() == 1 { - (op as *mut PyASCIIObject).offset(1) as *mut c_void + (op as *mut PyASCIIObject).offset(1) as *mut core::ffi::c_void } else { - (op as *mut PyCompactUnicodeObject).offset(1) as *mut c_void + (op as *mut PyCompactUnicodeObject).offset(1) as *mut core::ffi::c_void }; let num_bytes = (*(op as *mut PyASCIIObject)).length * ((*(op as *mut PyASCIIObject)).kind()) as isize; diff --git a/src/util.rs b/src/util.rs index d0e37c43..592ee1e8 100644 --- a/src/util.rs +++ b/src/util.rs @@ -228,6 +228,32 @@ macro_rules! pydict_next { }; } +#[cfg(feature = "setitem_knownhash")] +macro_rules! pydict_setitem { + ($dict:expr, $pykey:expr, $pyval:expr) => { + #[cfg(not(Py_3_14))] + unsafe { + pyo3_ffi::_PyDict_SetItem_KnownHash($dict, $pykey, $pyval, str_hash!($pykey)) + } + #[cfg(Py_3_14)] + unsafe { + pyo3_ffi::_PyDict_SetItem_KnownHash_LockHeld( + $dict as *mut pyo3_ffi::PyDictObject, + $pykey, + $pyval, + str_hash!($pykey), + ) + } + }; +} + +#[cfg(not(feature = "setitem_knownhash"))] +macro_rules! pydict_setitem { + ($dict:expr, $pykey:expr, $pyval:expr) => { + unsafe { pyo3_ffi::PyDict_SetItem($dict, $pykey, $pyval) } + }; +} + macro_rules! reserve_minimum { ($writer:expr) => { $writer.reserve(64);