Skip to content

Commit

Permalink
force index call for PyLong_AsUnsignedLongLong
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelcolvin committed Jan 15, 2024
1 parent d29ab94 commit d13e735
Showing 1 changed file with 11 additions and 5 deletions.
16 changes: 11 additions & 5 deletions src/conversions/std/num.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,15 @@ macro_rules! int_fits_larger_int {

macro_rules! extract_int {
($obj:ident, $error_val:expr, $pylong_as:expr) => {
extract_int!($obj, $error_val, $pylong_as, false)
};

($obj:ident, $error_val:expr, $pylong_as:expr, $force_index_call: literal) => {
// with python 3.8+ PyLong_AsLong takes care of calling PyNumber_Index itself
// hence no need for the slow `PyNumber_Index` path
// `PyLong_AsUnsignedLongLong` does not call `__index__`, hence the `force_index_call` argument
// see https:/PyO3/pyo3/pull/3742 for detials.
if cfg!(Py_3_8) {
if cfg!(Py_3_8) && !$force_index_call {
err_if_invalid_value($obj.py(), $error_val, unsafe { $pylong_as($obj.as_ptr()) })
} else if let Ok(long) = $obj.downcast::<crate::types::PyLong>() {
// with 3.7 we have to do the `PyNumber_Index` check ourselves
Expand All @@ -71,7 +76,7 @@ macro_rules! extract_int {
}

macro_rules! int_convert_u64_or_i64 {
($rust_type:ty, $pylong_from_ll_or_ull:expr, $pylong_as_ll_or_ull:expr) => {
($rust_type:ty, $pylong_from_ll_or_ull:expr, $pylong_as_ll_or_ull:expr, $force_index_call:literal) => {
impl ToPyObject for $rust_type {
#[inline]
fn to_object(&self, py: Python<'_>) -> PyObject {
Expand All @@ -91,7 +96,7 @@ macro_rules! int_convert_u64_or_i64 {
}
impl<'source> FromPyObject<'source> for $rust_type {
fn extract(obj: &'source PyAny) -> PyResult<$rust_type> {
extract_int!(obj, !0, $pylong_as_ll_or_ull)
extract_int!(obj, !0, $pylong_as_ll_or_ull, $force_index_call)
}

#[cfg(feature = "experimental-inspect")]
Expand Down Expand Up @@ -152,7 +157,7 @@ int_fits_c_long!(i64);

// manual implementation for i64 on systems with 32-bit long
#[cfg(any(target_pointer_width = "32", target_os = "windows"))]
int_convert_u64_or_i64!(i64, ffi::PyLong_FromLongLong, ffi::PyLong_AsLongLong);
int_convert_u64_or_i64!(i64, ffi::PyLong_FromLongLong, ffi::PyLong_AsLongLong, false);

#[cfg(all(target_pointer_width = "64", not(target_os = "windows")))]
int_fits_c_long!(isize);
Expand All @@ -165,7 +170,8 @@ int_fits_larger_int!(usize, u64);
int_convert_u64_or_i64!(
u64,
ffi::PyLong_FromUnsignedLongLong,
ffi::PyLong_AsUnsignedLongLong
ffi::PyLong_AsUnsignedLongLong,
true
);

#[cfg(not(Py_LIMITED_API))]
Expand Down

0 comments on commit d13e735

Please sign in to comment.