From 444540b87efa53dd7d0998ff23870eaf7e6959ec Mon Sep 17 00:00:00 2001 From: Bas Schoenmaeckers Date: Sun, 17 May 2026 17:38:42 +0200 Subject: [PATCH 1/4] Add integer c-api support --- crates/capi/src/lib.rs | 1 + crates/capi/src/longobject.rs | 83 +++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 crates/capi/src/longobject.rs diff --git a/crates/capi/src/lib.rs b/crates/capi/src/lib.rs index ebabc1521e9..62e7797a27b 100644 --- a/crates/capi/src/lib.rs +++ b/crates/capi/src/lib.rs @@ -10,6 +10,7 @@ extern crate alloc; pub mod abstract_; pub mod import; +pub mod longobject; pub mod object; pub mod pyerrors; pub mod pylifecycle; diff --git a/crates/capi/src/longobject.rs b/crates/capi/src/longobject.rs new file mode 100644 index 00000000000..b8dcd08b90f --- /dev/null +++ b/crates/capi/src/longobject.rs @@ -0,0 +1,83 @@ +use crate::PyObject; +use crate::pystate::with_vm; +use core::ffi::{c_long, c_longlong, c_ulong, c_ulonglong}; +use rustpython_vm::PyResult; +use rustpython_vm::builtins::PyInt; + +#[unsafe(no_mangle)] +pub extern "C" fn PyLong_FromLong(value: c_long) -> *mut PyObject { + with_vm(|vm| vm.ctx.new_int(value)) +} + +#[unsafe(no_mangle)] +pub extern "C" fn PyLong_FromLongLong(value: c_longlong) -> *mut PyObject { + with_vm(|vm| vm.ctx.new_int(value)) +} + +#[unsafe(no_mangle)] +pub extern "C" fn PyLong_FromSsize_t(value: isize) -> *mut PyObject { + with_vm(|vm| vm.ctx.new_int(value)) +} + +#[unsafe(no_mangle)] +pub extern "C" fn PyLong_FromSize_t(value: usize) -> *mut PyObject { + with_vm(|vm| vm.ctx.new_int(value)) +} + +#[unsafe(no_mangle)] +pub extern "C" fn PyLong_FromUnsignedLong(value: c_ulong) -> *mut PyObject { + with_vm(|vm| vm.ctx.new_int(value)) +} + +#[unsafe(no_mangle)] +pub extern "C" fn PyLong_FromUnsignedLongLong(value: c_ulonglong) -> *mut PyObject { + with_vm(|vm| vm.ctx.new_int(value)) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyLong_AsLong(obj: *mut PyObject) -> c_long { + with_vm::, _>(|vm| { + unsafe { &*obj } + .to_owned() + .try_index(vm)? + .as_bigint() + .try_into() + .map_err(|_| vm.new_overflow_error("Python int too large to convert to C long")) + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyLong_AsUnsignedLongLong(obj: *mut PyObject) -> c_longlong { + with_vm::, _>(|vm| { + unsafe { &*obj } + .to_owned() + .try_downcast::(vm)? + .as_bigint() + .try_into() + .map_err(|_| vm.new_overflow_error("Python int too large to convert to C long long")) + }) +} + +#[cfg(false)] +mod tests { + use pyo3::prelude::*; + use pyo3::types::PyInt; + + #[test] + fn test_py_int_u32() { + Python::attach(|py| { + let number = PyInt::new(py, 123); + assert!(number.is_instance_of::()); + assert_eq!(number.extract::().unwrap(), 123); + }) + } + + #[test] + fn test_py_int_u64() { + Python::attach(|py| { + let number = PyInt::new(py, 123u64); + assert!(number.is_instance_of::()); + assert_eq!(number.extract::().unwrap(), 123); + }) + } +} From 901319a977c37751689cd92948901044a85543cd Mon Sep 17 00:00:00 2001 From: Bas Schoenmaeckers Date: Sun, 17 May 2026 18:16:00 +0200 Subject: [PATCH 2/4] Fix `PyLong_AsUnsignedLongLong` return value --- crates/capi/src/longobject.rs | 4 ++-- crates/capi/src/util.rs | 10 +++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/crates/capi/src/longobject.rs b/crates/capi/src/longobject.rs index b8dcd08b90f..40ac6c58c55 100644 --- a/crates/capi/src/longobject.rs +++ b/crates/capi/src/longobject.rs @@ -47,8 +47,8 @@ pub unsafe extern "C" fn PyLong_AsLong(obj: *mut PyObject) -> c_long { } #[unsafe(no_mangle)] -pub unsafe extern "C" fn PyLong_AsUnsignedLongLong(obj: *mut PyObject) -> c_longlong { - with_vm::, _>(|vm| { +pub unsafe extern "C" fn PyLong_AsUnsignedLongLong(obj: *mut PyObject) -> c_ulonglong { + with_vm::, _>(|vm| { unsafe { &*obj } .to_owned() .try_downcast::(vm)? diff --git a/crates/capi/src/util.rs b/crates/capi/src/util.rs index 6137ca9029f..9119581902a 100644 --- a/crates/capi/src/util.rs +++ b/crates/capi/src/util.rs @@ -1,6 +1,6 @@ use crate::PyObject; use core::convert::Infallible; -use core::ffi::{c_char, c_double, c_int, c_long, c_void}; +use core::ffi::{c_char, c_double, c_int, c_long, c_ulonglong, c_void}; use rustpython_vm::{PyObjectRef, PyRef, PyResult, VirtualMachine}; pub(crate) trait FfiResult { @@ -93,6 +93,14 @@ impl FfiResult for c_long { } } +impl FfiResult for c_ulonglong { + const ERR_VALUE: Self = Self::MAX; + + fn into_output(self, _vm: &VirtualMachine) -> Self { + self + } +} + impl FfiResult for c_double { const ERR_VALUE: Self = -1.0; From 365c5d4430b75ab957a5c8b433db805fb7572779 Mon Sep 17 00:00:00 2001 From: Bas Schoenmaeckers Date: Sun, 17 May 2026 20:23:43 +0200 Subject: [PATCH 3/4] Fix error message --- crates/capi/src/longobject.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/capi/src/longobject.rs b/crates/capi/src/longobject.rs index 40ac6c58c55..fdfdb319a82 100644 --- a/crates/capi/src/longobject.rs +++ b/crates/capi/src/longobject.rs @@ -54,7 +54,9 @@ pub unsafe extern "C" fn PyLong_AsUnsignedLongLong(obj: *mut PyObject) -> c_ulon .try_downcast::(vm)? .as_bigint() .try_into() - .map_err(|_| vm.new_overflow_error("Python int too large to convert to C long long")) + .map_err(|_| { + vm.new_overflow_error("Python int too large to convert to C unsigned long long") + }) }) } From fc76d83815ed910b09b33b87a3ca1265545a1176 Mon Sep 17 00:00:00 2001 From: Bas Schoenmaeckers Date: Mon, 18 May 2026 10:29:44 +0200 Subject: [PATCH 4/4] Add type check functions --- crates/capi/src/longobject.rs | 4 ++++ crates/capi/src/object.rs | 1 + 2 files changed, 5 insertions(+) diff --git a/crates/capi/src/longobject.rs b/crates/capi/src/longobject.rs index fdfdb319a82..8c9fe5e1acb 100644 --- a/crates/capi/src/longobject.rs +++ b/crates/capi/src/longobject.rs @@ -1,9 +1,13 @@ use crate::PyObject; +use crate::object::define_py_check; use crate::pystate::with_vm; use core::ffi::{c_long, c_longlong, c_ulong, c_ulonglong}; use rustpython_vm::PyResult; use rustpython_vm::builtins::PyInt; +define_py_check!(fn PyLong_Check, types.int_type); +define_py_check!(exact fn PyLong_CheckExact, types.int_type); + #[unsafe(no_mangle)] pub extern "C" fn PyLong_FromLong(value: c_long) -> *mut PyObject { with_vm(|vm| vm.ctx.new_int(value)) diff --git a/crates/capi/src/object.rs b/crates/capi/src/object.rs index f71475049f8..89995f8e908 100644 --- a/crates/capi/src/object.rs +++ b/crates/capi/src/object.rs @@ -33,6 +33,7 @@ macro_rules! define_py_check { }; } +pub(crate) use define_py_check; define_py_check!(fn PyType_Check, types.type_type); define_py_check!(exact fn PyType_CheckExact, types.type_type);