diff --git a/src/ffi/unicodeobject.rs b/src/ffi/unicodeobject.rs index 165e7aff2ed..de51d816012 100644 --- a/src/ffi/unicodeobject.rs +++ b/src/ffi/unicodeobject.rs @@ -143,14 +143,16 @@ extern "C" { #[cfg_attr(PyPy, link_name = "PyPyUnicode_FromOrdinal")] pub fn PyUnicode_FromOrdinal(ordinal: c_int) -> *mut PyObject; pub fn PyUnicode_ClearFreeList() -> c_int; - #[cfg(not(Py_LIMITED_API))] + #[cfg(any(not(Py_LIMITED_API), Py_3_10))] #[cfg(Py_3_7)] + #[cfg_attr(PyPy, link_name = "PyPyUnicode_AsUTF8AndSize")] pub fn PyUnicode_AsUTF8AndSize(unicode: *mut PyObject, size: *mut Py_ssize_t) -> *const c_char; #[cfg(not(Py_3_7))] #[cfg_attr(PyPy, link_name = "PyPyUnicode_AsUTF8AndSize")] pub fn PyUnicode_AsUTF8AndSize(unicode: *mut PyObject, size: *mut Py_ssize_t) -> *mut c_char; #[cfg(not(Py_LIMITED_API))] #[cfg(Py_3_7)] + #[cfg_attr(PyPy, link_name = "PyPyUnicode_AsUTF8")] pub fn PyUnicode_AsUTF8(unicode: *mut PyObject) -> *const c_char; #[cfg(not(Py_3_7))] #[cfg_attr(PyPy, link_name = "PyPyUnicode_AsUTF8")] diff --git a/src/types/string.rs b/src/types/string.rs index ee5d3314504..18b05c99f00 100644 --- a/src/types/string.rs +++ b/src/types/string.rs @@ -44,27 +44,26 @@ impl PyString { /// (containing unpaired surrogates). #[inline] pub fn to_str(&self) -> PyResult<&str> { - #[cfg(not(Py_LIMITED_API))] - unsafe { - let mut size: ffi::Py_ssize_t = 0; - let data = ffi::PyUnicode_AsUTF8AndSize(self.as_ptr(), &mut size) as *const u8; - if data.is_null() { - Err(PyErr::fetch(self.py())) - } else { - let slice = std::slice::from_raw_parts(data, size as usize); - Ok(std::str::from_utf8_unchecked(slice)) + let utf8_slice = { + cfg_if::cfg_if! { + if #[cfg(any(not(Py_LIMITED_API), Py_3_10))] { + // PyUnicode_AsUTF8AndSize only available on limited API from Python 3.10 and up. + let mut size: ffi::Py_ssize_t = 0; + let data = unsafe { ffi::PyUnicode_AsUTF8AndSize(self.as_ptr(), &mut size) }; + if data.is_null() { + return Err(PyErr::fetch(self.py())); + } else { + unsafe { std::slice::from_raw_parts(data as *const u8, size as usize) } + } + } else { + let bytes = unsafe { + self.py().from_owned_ptr_or_err::(ffi::PyUnicode_AsUTF8String(self.as_ptr()))? + }; + bytes.as_bytes() + } } - } - #[cfg(Py_LIMITED_API)] - unsafe { - let data = ffi::PyUnicode_AsUTF8String(self.as_ptr()); - if data.is_null() { - Err(PyErr::fetch(self.py())) - } else { - let bytes = self.py().from_owned_ptr::(data); - Ok(std::str::from_utf8_unchecked(bytes.as_bytes())) - } - } + }; + Ok(unsafe { std::str::from_utf8_unchecked(utf8_slice) }) } /// Converts the `PyString` into a Rust string.