long.rs


Overview

The `long.rs` file provides low-level Rust bindings and utilities to interact with Python's internal representation of long integers (`PyLongObject`) within the PyO3 FFI layer. It primarily focuses on supporting Python 3.12's new long integer internal layout while maintaining backward compatibility with earlier Python versions.

This file defines internal Rust representations of Python’s long integer structures and includes several inline helper functions to query and manipulate these objects efficiently. These helpers facilitate checking the sign of the long integer, determining if it fits within a 32-bit signed integer, checking if the integer is zero, and extracting the integer's inline value. The implementation leverages conditional compilation to adapt to changes introduced in Python 3.12 and optional features like `"inline_int"`.


Detailed Description

Structs

_PyLongValue

#[repr(C)]
pub(crate) struct _PyLongValue {
    pub lv_tag: usize,
    pub ob_digit: u32,
}

PyLongObject

There are two variants depending on the Python version:

#[repr(C)]
pub(crate) struct PyLongObject {
    pub ob_base: pyo3_ffi::PyObject,
    pub long_value: _PyLongValue,
}
#[repr(C)]
pub(crate) struct PyLongObject {
    pub ob_base: pyo3_ffi::PyVarObject,
    pub ob_digit: u32,
}

Constants

Defined only when targeting Python 3.12 and optionally with `"inline_int"` feature:

These constants are crucial for decoding the tagged integer representation introduced in Python 3.12.


Functions

All functions are marked `pub(crate)` and `inline(always)` for efficient FFI calls.


pylong_is_unsigned

pub(crate) fn pylong_is_unsigned(ptr: *mut pyo3_ffi::PyObject) -> bool
if pylong_is_unsigned(py_long_ptr) {
    println!("The Python long integer is non-negative.");
} else {
    println!("The Python long integer is negative.");
}

pylong_fits_in_i32

pub(crate) fn pylong_fits_in_i32(ptr: *mut pyo3_ffi::PyObject) -> bool
if pylong_fits_in_i32(py_long_ptr) {
    println!("Integer fits in i32.");
} else {
    println!("Integer too large for i32.");
}

pylong_is_zero

pub(crate) fn pylong_is_zero(ptr: *mut pyo3_ffi::PyObject) -> bool
if pylong_is_zero(py_long_ptr) {
    println!("Integer is zero.");
} else {
    println!("Integer is non-zero.");
}

pylong_get_inline_value

pub(crate) fn pylong_get_inline_value(ptr: *mut pyo3_ffi::PyObject) -> i64
let value = pylong_get_inline_value(py_long_ptr);
println!("Inline integer value: {}", value);

Implementation Details and Algorithms


Interaction with Other Parts of the System


Visual Diagram

classDiagram
    class _PyLongValue {
        +usize lv_tag
        +u32 ob_digit
    }

    class PyLongObject_3_12 {
        +pyo3_ffi::PyObject ob_base
        +_PyLongValue long_value
    }

    class PyLongObject_pre_3_12 {
        +pyo3_ffi::PyVarObject ob_base
        +u32 ob_digit
    }

    PyLongObject_3_12 --> _PyLongValue

Summary

The `long.rs` file encapsulates the Python long integer's internal representation and provides efficient, version-dependent utilities for inspecting and extracting integer values from Python objects in Rust. It is designed for use within the PyO3 FFI ecosystem to bridge Rust and Python integer handling with attention to the optimizations introduced in Python 3.12.