Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
7f623ee
add `PyLong*` API (3.14+)
chirizxc May 5, 2026
59a6818
add newsfragments
chirizxc May 5, 2026
dce9996
cargo fmt
chirizxc May 5, 2026
5e4018e
try fix
chirizxc May 5, 2026
035b40e
fix typo (inr -> int)
chirizxc May 5, 2026
f2cebdc
try fix (x2)
chirizxc May 5, 2026
0fb6575
fix clippy
chirizxc May 5, 2026
05bfe1f
try fix clippy
chirizxc May 5, 2026
ebbb7da
add bench int 128
chirizxc May 5, 2026
003647a
add tests
chirizxc May 5, 2026
66b00a1
digits_ptr -> ptr
chirizxc May 5, 2026
b8b9597
review
chirizxc May 5, 2026
a089d89
cargo fmt
chirizxc May 5, 2026
e55d67e
fix
chirizxc May 5, 2026
a937d91
sync 3.14 (https://github.com/python/cpython/commit/af65a8be0c4f28a4b…
chirizxc May 6, 2026
5e049e5
add `PyLong_Is*`
chirizxc May 6, 2026
9ad8e5d
remove PyUnstable_Long_IsCompact
chirizxc May 7, 2026
e2c2caa
bench new line
chirizxc May 7, 2026
bf00a58
PyLong_FromUnicodeObject
chirizxc May 7, 2026
14d54f3
remove #[cfg(not(Py_LIMITED_API))]
chirizxc May 7, 2026
64248a1
review
chirizxc May 7, 2026
884cd64
add 6016.changed.md
chirizxc May 7, 2026
9618b36
update
chirizxc May 7, 2026
4d4a0b0
update
chirizxc May 7, 2026
d96ca58
update
chirizxc May 7, 2026
9976b33
fix
chirizxc May 7, 2026
f35bb45
fix
chirizxc May 7, 2026
4a4855d
review
chirizxc May 9, 2026
44861bd
review (x2)
chirizxc May 9, 2026
dd7f0dc
review (x3)
chirizxc May 9, 2026
e66b19c
add #[inline]
chirizxc May 9, 2026
e12e97b
update
chirizxc May 9, 2026
66d063b
review
chirizxc May 10, 2026
7fc518a
review (x2)
chirizxc May 10, 2026
1cf84fe
fix
chirizxc May 10, 2026
2bbc163
fix
chirizxc May 10, 2026
bd7af65
fmt
chirizxc May 10, 2026
23af4f1
review
chirizxc May 10, 2026
3d182b3
Merge branch 'main' into PyLongWriter
chirizxc May 10, 2026
a3041cf
review
chirizxc May 11, 2026
84818b3
Merge branch 'main' into PyLongWriter
chirizxc May 12, 2026
ac81af8
std -> core
chirizxc May 12, 2026
70d3985
std -> core (x2)
chirizxc May 12, 2026
3fdcb06
review
chirizxc May 12, 2026
2c6528a
review (x2)
chirizxc May 12, 2026
c2f8c9a
Update pyo3-ffi/src/cpython/longintrepr.rs
chirizxc May 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions newsfragments/6016.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added FFI wrappers for [PEP 757](https://peps.python.org/pep-0757/) `PyLong` import / export API on Python 3.14.
55 changes: 55 additions & 0 deletions pyo3-ffi/src/cpython/longintrepr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use crate::{PyObject, Py_ssize_t};
use core::ffi::{c_int, c_void};

use crate::Py_uintptr_t;

// skipped PyLong_BASE
// skipped PyLong_MASK
// skipped _PyLong_New
// skipped _PyLong_Copy
// skipped _PyLong_FromDigits
// skipped _PyLong_SIGN_MASK
// skipped _PyLong_NON_SIZE_BITS
// skipped PyUnstable_Long_IsCompact
// skipped PyUnstable_Long_CompactValue

#[derive(Copy, Clone)]
#[repr(C)]
pub struct PyLongLayout {
pub bits_per_digit: u8,
pub digit_size: u8,
pub digits_order: i8,
pub digit_endianness: i8,
}

extern_libpython! {
pub fn PyLong_GetNativeLayout() -> *const PyLongLayout;
}

#[repr(C)]
pub struct PyLongExport {
pub value: i64,
pub negative: u8,
pub ndigits: Py_ssize_t,
pub digits: *const c_void,
_reserved: Py_uintptr_t,
}

extern_libpython! {
pub fn PyLong_Export(obj: *mut PyObject, export_long: *mut PyLongExport) -> c_int;
pub fn PyLong_FreeExport(export_long: *mut PyLongExport);
}

opaque_struct!(pub PyLongWriter);

extern_libpython! {
pub fn PyLongWriter_Create(
negative: c_int,
ndigits: Py_ssize_t,
digits: *mut *mut c_void,
) -> *mut PyLongWriter;

pub fn PyLongWriter_Finish(writer: *mut PyLongWriter) -> *mut PyObject;

pub fn PyLongWriter_Discard(writer: *mut PyLongWriter);
}
62 changes: 18 additions & 44 deletions pyo3-ffi/src/cpython/longobject.rs
Original file line number Diff line number Diff line change
@@ -1,57 +1,31 @@
use crate::longobject::*;
use crate::object::*;
#[cfg(Py_3_13)]
use crate::pyport::Py_ssize_t;
#[cfg(Py_3_13)]
use core::ffi::c_void;
use crate::{longobject::*, object::*};
use core::ffi::{c_int, c_uchar};
use libc::size_t;

#[cfg(Py_3_13)]
// skipped _PyLong_CAST

extern_libpython! {
#[cfg(Py_3_13)]
pub fn PyLong_FromUnicodeObject(u: *mut PyObject, base: c_int) -> *mut PyObject;
Comment thread
chirizxc marked this conversation as resolved.
}

#[cfg(Py_3_13)]
pub const Py_ASNATIVEBYTES_DEFAULTS: c_int = -1;
#[cfg(Py_3_13)]
pub const Py_ASNATIVEBYTES_BIG_ENDIAN: c_int = 0;
#[cfg(Py_3_13)]
pub const Py_ASNATIVEBYTES_LITTLE_ENDIAN: c_int = 1;
#[cfg(Py_3_13)]
pub const Py_ASNATIVEBYTES_NATIVE_ENDIAN: c_int = 3;
#[cfg(Py_3_13)]
pub const Py_ASNATIVEBYTES_UNSIGNED_BUFFER: c_int = 4;
#[cfg(Py_3_13)]
pub const Py_ASNATIVEBYTES_REJECT_NEGATIVE: c_int = 8;

extern_libpython! {
// skipped _PyLong_Sign
// skipped PyUnstable_Long_IsCompact
Comment thread
chirizxc marked this conversation as resolved.
// skipped PyUnstable_Long_CompactValue

#[cfg(Py_3_13)]
pub fn PyLong_AsNativeBytes(
v: *mut PyObject,
buffer: *mut c_void,
n_bytes: Py_ssize_t,
flags: c_int,
) -> Py_ssize_t;
#[cfg(Py_3_14)]
pub fn PyLong_IsPositive(obj: *mut PyObject) -> c_int;
#[cfg(Py_3_14)]
pub fn PyLong_IsNegative(obj: *mut PyObject) -> c_int;
#[cfg(Py_3_14)]
pub fn PyLong_IsZero(obj: *mut PyObject) -> c_int;

#[cfg(Py_3_13)]
pub fn PyLong_FromNativeBytes(
buffer: *const c_void,
n_bytes: size_t,
flags: c_int,
) -> *mut PyObject;
// skipped PyLong_GetSign

#[cfg(Py_3_13)]
pub fn PyLong_FromUnsignedNativeBytes(
buffer: *const c_void,
n_bytes: size_t,
flags: c_int,
) -> *mut PyObject;
// skipped _PyLong_Sign

// skipped PyUnstable_Long_IsCompact
// skipped PyUnstable_Long_CompactValue
#[cfg_attr(PyPy, link_name = "_PyPyLong_NumBits")]
#[cfg(not(Py_3_13))]
#[doc(hidden)]
pub fn _PyLong_NumBits(obj: *mut PyObject) -> size_t;

#[cfg_attr(PyPy, link_name = "_PyPyLong_FromByteArray")]
pub fn _PyLong_FromByteArray(
Expand Down
4 changes: 4 additions & 0 deletions pyo3-ffi/src/cpython/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ pub(crate) mod initconfig;
pub(crate) mod listobject;
#[cfg(Py_3_13)]
pub(crate) mod lock;
#[cfg(Py_3_14)]
pub(crate) mod longintrepr;
pub(crate) mod longobject;
pub(crate) mod marshal;
#[cfg(all(Py_3_9, not(PyPy)))]
Expand Down Expand Up @@ -71,6 +73,8 @@ pub use self::initconfig::*;
pub use self::listobject::*;
#[cfg(Py_3_13)]
pub use self::lock::*;
#[cfg(Py_3_14)]
pub use self::longintrepr::*;
pub use self::longobject::*;
pub use self::marshal::*;
#[cfg(all(Py_3_9, not(PyPy)))]
Expand Down
1 change: 0 additions & 1 deletion pyo3-ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,6 @@ mod import;
mod intrcheck;
mod iterobject;
mod listobject;
// skipped longintrepr.h
mod longobject;
mod memoryobject;
mod methodobject;
Expand Down
86 changes: 60 additions & 26 deletions pyo3-ffi/src/longobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,66 @@ extern_libpython! {
pub fn PyLong_AsUnsignedLong(arg1: *mut PyObject) -> c_ulong;
#[cfg_attr(PyPy, link_name = "PyPyLong_AsUnsignedLongMask")]
pub fn PyLong_AsUnsignedLongMask(arg1: *mut PyObject) -> c_ulong;
// skipped non-limited _PyLong_AsInt

// skipped non-limited PyLong_AsInt

#[cfg(Py_3_14)]
pub fn PyLong_FromInt32(arg1: i32) -> *mut PyObject;
#[cfg(Py_3_14)]
pub fn PyLong_FromUInt32(arg1: u32) -> *mut PyObject;
#[cfg(Py_3_14)]
pub fn PyLong_FromInt64(arg1: i64) -> *mut PyObject;
#[cfg(Py_3_14)]
pub fn PyLong_FromUInt64(arg1: u64) -> *mut PyObject;

#[cfg(Py_3_14)]
pub fn PyLong_AsInt32(arg1: *mut PyObject, arg2: *mut i32) -> c_int;
#[cfg(Py_3_14)]
pub fn PyLong_AsUInt32(arg1: *mut PyObject, arg2: *mut u32) -> c_int;
#[cfg(Py_3_14)]
pub fn PyLong_AsInt64(arg1: *mut PyObject, arg2: *mut i64) -> c_int;
#[cfg(Py_3_14)]
pub fn PyLong_AsUInt64(arg1: *mut PyObject, arg2: *mut u64) -> c_int;
}

#[cfg(any(Py_3_14, all(Py_3_13, not(Py_LIMITED_API))))]
pub const Py_ASNATIVEBYTES_DEFAULTS: c_int = -1;
#[cfg(any(Py_3_14, all(Py_3_13, not(Py_LIMITED_API))))]
pub const Py_ASNATIVEBYTES_BIG_ENDIAN: c_int = 0;
#[cfg(any(Py_3_14, all(Py_3_13, not(Py_LIMITED_API))))]
pub const Py_ASNATIVEBYTES_LITTLE_ENDIAN: c_int = 1;
#[cfg(any(Py_3_14, all(Py_3_13, not(Py_LIMITED_API))))]
pub const Py_ASNATIVEBYTES_NATIVE_ENDIAN: c_int = 3;
#[cfg(any(Py_3_14, all(Py_3_13, not(Py_LIMITED_API))))]
pub const Py_ASNATIVEBYTES_UNSIGNED_BUFFER: c_int = 4;
#[cfg(any(Py_3_14, all(Py_3_13, not(Py_LIMITED_API))))]
pub const Py_ASNATIVEBYTES_REJECT_NEGATIVE: c_int = 8;
#[cfg(any(Py_3_14, all(Py_3_13, not(Py_LIMITED_API))))]
pub const Py_ASNATIVEBYTES_ALLOW_INDEX: c_int = 16;

extern_libpython! {
#[cfg(any(Py_3_14, all(Py_3_13, not(Py_LIMITED_API))))]
pub fn PyLong_AsNativeBytes(
v: *mut PyObject,
buffer: *mut c_void,
n_bytes: Py_ssize_t,
flags: c_int,
) -> Py_ssize_t;

#[cfg(any(Py_3_14, all(Py_3_13, not(Py_LIMITED_API))))]
pub fn PyLong_FromNativeBytes(
buffer: *const c_void,
n_bytes: size_t,
flags: c_int,
) -> *mut PyObject;

#[cfg(any(Py_3_14, all(Py_3_13, not(Py_LIMITED_API))))]
pub fn PyLong_FromUnsignedNativeBytes(
buffer: *const c_void,
n_bytes: size_t,
flags: c_int,
) -> *mut PyObject;
Comment thread
chirizxc marked this conversation as resolved.

pub fn PyLong_GetInfo() -> *mut PyObject;
// skipped PyLong_AS_LONG

Expand All @@ -54,15 +113,6 @@ extern_libpython! {
// skipped _Py_PARSE_INTPTR
// skipped _Py_PARSE_UINTPTR

// skipped non-limited _PyLong_UnsignedShort_Converter
// skipped non-limited _PyLong_UnsignedInt_Converter
// skipped non-limited _PyLong_UnsignedLong_Converter
// skipped non-limited _PyLong_UnsignedLongLong_Converter
// skipped non-limited _PyLong_Size_t_Converter

// skipped non-limited _PyLong_DigitValue
// skipped non-limited _PyLong_Frexp

#[cfg_attr(PyPy, link_name = "PyPyLong_AsDouble")]
pub fn PyLong_AsDouble(arg1: *mut PyObject) -> c_double;
#[cfg_attr(PyPy, link_name = "PyPyLong_FromVoidPtr")]
Expand All @@ -89,23 +139,7 @@ extern_libpython! {
) -> *mut PyObject;
}

#[cfg(not(Py_LIMITED_API))]
extern_libpython! {
#[cfg_attr(PyPy, link_name = "_PyPyLong_NumBits")]
#[cfg(not(Py_3_13))]
#[doc(hidden)]
pub fn _PyLong_NumBits(obj: *mut PyObject) -> size_t;
}

// skipped non-limited _PyLong_Format
// skipped non-limited _PyLong_FormatWriter
// skipped non-limited _PyLong_FormatBytesWriter
// skipped non-limited _PyLong_FormatAdvancedWriter

extern_libpython! {
pub fn PyOS_strtoul(arg1: *const c_char, arg2: *mut *mut c_char, arg3: c_int) -> c_ulong;
pub fn PyOS_strtol(arg1: *const c_char, arg2: *mut *mut c_char, arg3: c_int) -> c_long;
}

// skipped non-limited _PyLong_Rshift
// skipped non-limited _PyLong_Lshift
Loading
Loading