From 13590693f15bdc8208e448adf1da5b828331aaac Mon Sep 17 00:00:00 2001 From: Fabio Valentini Date: Wed, 26 Jun 2024 19:58:54 +0200 Subject: [PATCH] backport support for Python 3.13 --- src/conversions/std/num.rs | 113 ++++++++++++++++++++++++++++--------- 1 file changed, 87 insertions(+), 26 deletions(-) diff --git a/src/conversions/std/num.rs b/src/conversions/std/num.rs index 3427942..9dd93cf 100644 --- a/src/conversions/std/num.rs +++ b/src/conversions/std/num.rs @@ -5,6 +5,8 @@ use crate::{ ToPyObject, }; use std::convert::TryFrom; +#[cfg(Py_3_13)] +use std::convert::TryInto; use std::num::{ NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, @@ -169,7 +171,7 @@ mod fast_128bit_int_conversion { // for 128bit Integers macro_rules! int_convert_128 { - ($rust_type: ty, $is_signed: expr) => { + ($rust_type: ty, $is_signed: literal) => { impl ToPyObject for $rust_type { #[inline] fn to_object(&self, py: Python<'_>) -> PyObject { @@ -178,18 +180,47 @@ mod fast_128bit_int_conversion { } impl IntoPy for $rust_type { fn into_py(self, py: Python<'_>) -> PyObject { - // Always use little endian - let bytes = self.to_le_bytes(); - unsafe { - PyObject::from_owned_ptr( - py, - ffi::_PyLong_FromByteArray( - bytes.as_ptr() as *const std::os::raw::c_uchar, - bytes.len(), - 1, - $is_signed, - ), - ) + #[cfg(not(Py_3_13))] + { + let bytes = self.to_le_bytes(); + unsafe { + PyObject::from_owned_ptr( + py, + ffi::_PyLong_FromByteArray( + bytes.as_ptr().cast(), + bytes.len(), + 1, + $is_signed.into(), + ), + ) + } + } + #[cfg(Py_3_13)] + { + let bytes = self.to_ne_bytes(); + if $is_signed { + unsafe { + PyObject::from_owned_ptr( + py, + ffi::PyLong_FromNativeBytes( + bytes.as_ptr().cast(), + bytes.len(), + ffi::Py_ASNATIVEBYTES_NATIVE_ENDIAN, + ), + ) + } + } else { + unsafe { + PyObject::from_owned_ptr( + py, + ffi::PyLong_FromUnsignedNativeBytes( + bytes.as_ptr().cast(), + bytes.len(), + ffi::Py_ASNATIVEBYTES_NATIVE_ENDIAN, + ), + ) + } + } } } @@ -204,17 +235,47 @@ mod fast_128bit_int_conversion { let num = unsafe { PyObject::from_owned_ptr_or_err(ob.py(), ffi::PyNumber_Index(ob.as_ptr()))? }; - let mut buffer = [0; std::mem::size_of::<$rust_type>()]; - crate::err::error_on_minusone(ob.py(), unsafe { - ffi::_PyLong_AsByteArray( - num.as_ptr() as *mut ffi::PyLongObject, - buffer.as_mut_ptr(), - buffer.len(), - 1, - $is_signed, - ) - })?; - Ok(<$rust_type>::from_le_bytes(buffer)) + let mut buffer = [0u8; std::mem::size_of::<$rust_type>()]; + #[cfg(not(Py_3_13))] + { + crate::err::error_on_minusone(ob.py(), unsafe { + ffi::_PyLong_AsByteArray( + num.as_ptr() as *mut ffi::PyLongObject, + buffer.as_mut_ptr(), + buffer.len(), + 1, + $is_signed.into(), + ) + })?; + Ok(<$rust_type>::from_le_bytes(buffer)) + } + #[cfg(Py_3_13)] + { + let mut flags = ffi::Py_ASNATIVEBYTES_NATIVE_ENDIAN; + if !$is_signed { + flags |= ffi::Py_ASNATIVEBYTES_UNSIGNED_BUFFER + | ffi::Py_ASNATIVEBYTES_REJECT_NEGATIVE; + } + let actual_size: usize = unsafe { + ffi::PyLong_AsNativeBytes( + num.as_ptr(), + buffer.as_mut_ptr().cast(), + buffer + .len() + .try_into() + .expect("length of buffer fits in Py_ssize_t"), + flags, + ) + } + .try_into() + .map_err(|_| PyErr::fetch(ob.py()))?; + if actual_size as usize > buffer.len() { + return Err(crate::exceptions::PyOverflowError::new_err( + "Python int larger than 128 bits", + )); + } + Ok(<$rust_type>::from_ne_bytes(buffer)) + } } #[cfg(feature = "experimental-inspect")] @@ -225,8 +286,8 @@ mod fast_128bit_int_conversion { }; } - int_convert_128!(i128, 1); - int_convert_128!(u128, 0); + int_convert_128!(i128, true); + int_convert_128!(u128, false); } // For ABI3 we implement the conversion manually. -- 2.45.2