From 1eafc053e667a521af397ab21c7cc76a00b279f4 Mon Sep 17 00:00:00 2001 From: DSPOM Date: Tue, 25 Jan 2022 14:46:27 +0100 Subject: [PATCH] move ffi module to separate crate --- Cargo.toml | 16 +- pyo3-ffi/Cargo.toml | 39 ++ {src/ffi => pyo3-ffi}/LICENSE | 0 {src/ffi => pyo3-ffi}/README.md | 0 pyo3-ffi/build.rs | 151 ++++++ {src/ffi => pyo3-ffi/src}/abstract_.rs | 9 +- {src/ffi => pyo3-ffi/src}/bltinmodule.rs | 2 +- {src/ffi => pyo3-ffi/src}/boolobject.rs | 4 +- {src/ffi => pyo3-ffi/src}/bytearrayobject.rs | 4 +- {src/ffi => pyo3-ffi/src}/bytesobject.rs | 4 +- {src/ffi => pyo3-ffi/src}/ceval.rs | 10 +- {src/ffi => pyo3-ffi/src}/code.rs | 0 {src/ffi => pyo3-ffi/src}/codecs.rs | 2 +- {src/ffi => pyo3-ffi/src}/compile.rs | 0 {src/ffi => pyo3-ffi/src}/complexobject.rs | 2 +- {src/ffi => pyo3-ffi/src}/context.rs | 2 +- .../ffi => pyo3-ffi/src}/cpython/abstract_.rs | 8 +- .../src}/cpython/bytesobject.rs | 4 +- {src/ffi => pyo3-ffi/src}/cpython/ceval.rs | 9 +- {src/ffi => pyo3-ffi/src}/cpython/code.rs | 6 +- {src/ffi => pyo3-ffi/src}/cpython/compile.rs | 8 +- .../src}/cpython/dictobject.rs | 8 +- .../src}/cpython/frameobject.rs | 6 +- {src/ffi => pyo3-ffi/src}/cpython/import.rs | 2 +- .../src}/cpython/initconfig.rs | 2 +- .../src}/cpython/listobject.rs | 4 +- pyo3-ffi/src/cpython/mod.rs | 52 ++ {src/ffi => pyo3-ffi/src}/cpython/object.rs | 24 +- {src/ffi => pyo3-ffi/src}/cpython/pydebug.rs | 0 .../src}/cpython/pylifecycle.rs | 2 +- {src/ffi => pyo3-ffi/src}/cpython/pymem.rs | 0 {src/ffi => pyo3-ffi/src}/cpython/pystate.rs | 10 +- .../ffi => pyo3-ffi/src}/cpython/pythonrun.rs | 8 +- .../src}/cpython/tupleobject.rs | 4 +- pyo3-ffi/src/cpython/unicodeobject.rs | 482 +++++++++++++++++ pyo3-ffi/src/datetime.rs | 428 +++++++++++++++ {src/ffi => pyo3-ffi/src}/descrobject.rs | 6 +- {src/ffi => pyo3-ffi/src}/dictobject.rs | 4 +- {src/ffi => pyo3-ffi/src}/enumobject.rs | 2 +- {src/ffi => pyo3-ffi/src}/eval.rs | 2 +- {src/ffi => pyo3-ffi/src}/fileobject.rs | 2 +- {src/ffi => pyo3-ffi/src}/fileutils.rs | 2 +- {src/ffi => pyo3-ffi/src}/floatobject.rs | 2 +- {src/ffi => pyo3-ffi/src}/funcobject.rs | 2 +- {src/ffi => pyo3-ffi/src}/genobject.rs | 6 +- {src/ffi => pyo3-ffi/src}/import.rs | 2 +- {src/ffi => pyo3-ffi/src}/intrcheck.rs | 0 {src/ffi => pyo3-ffi/src}/iterobject.rs | 2 +- pyo3-ffi/src/lib.rs | 206 ++++++++ {src/ffi => pyo3-ffi/src}/listobject.rs | 4 +- {src/ffi => pyo3-ffi/src}/longobject.rs | 4 +- {src/ffi => pyo3-ffi/src}/marshal.rs | 0 {src/ffi => pyo3-ffi/src}/memoryobject.rs | 4 +- {src/ffi => pyo3-ffi/src}/methodobject.rs | 8 +- {src/ffi => pyo3-ffi/src}/modsupport.rs | 8 +- {src/ffi => pyo3-ffi/src}/moduleobject.rs | 6 +- {src/ffi => pyo3-ffi/src}/object.rs | 4 +- {src/ffi => pyo3-ffi/src}/objimpl.rs | 4 +- {src/ffi => pyo3-ffi/src}/osmodule.rs | 2 +- {src/ffi => pyo3-ffi/src}/pyarena.rs | 0 {src/ffi => pyo3-ffi/src}/pycapsule.rs | 2 +- {src/ffi => pyo3-ffi/src}/pyerrors.rs | 8 +- {src/ffi => pyo3-ffi/src}/pyframe.rs | 2 +- {src/ffi => pyo3-ffi/src}/pyhash.rs | 2 +- {src/ffi => pyo3-ffi/src}/pylifecycle.rs | 2 +- {src/ffi => pyo3-ffi/src}/pymem.rs | 0 {src/ffi => pyo3-ffi/src}/pyport.rs | 0 {src/ffi => pyo3-ffi/src}/pystate.rs | 4 +- {src/ffi => pyo3-ffi/src}/pystrtod.rs | 2 +- {src/ffi => pyo3-ffi/src}/pythonrun.rs | 6 +- {src/ffi => pyo3-ffi/src}/rangeobject.rs | 2 +- {src/ffi => pyo3-ffi/src}/setobject.rs | 8 +- {src/ffi => pyo3-ffi/src}/sliceobject.rs | 4 +- {src/ffi => pyo3-ffi/src}/structmember.rs | 4 +- {src/ffi => pyo3-ffi/src}/structseq.rs | 10 +- {src/ffi => pyo3-ffi/src}/sysmodule.rs | 2 +- {src/ffi => pyo3-ffi/src}/traceback.rs | 4 +- {src/ffi => pyo3-ffi/src}/tupleobject.rs | 4 +- {src/ffi => pyo3-ffi/src}/typeslots.rs | 0 {src/ffi => pyo3-ffi/src}/unicodeobject.rs | 4 +- {src/ffi => pyo3-ffi/src}/warnings.rs | 4 +- {src/ffi => pyo3-ffi/src}/weakrefobject.rs | 2 +- src/ffi/cpython/mod.rs | 53 +- src/ffi/cpython/unicodeobject.rs | 487 +----------------- src/ffi/datetime.rs | 436 +--------------- src/ffi/mod.rs | 198 +------ 86 files changed, 1528 insertions(+), 1316 deletions(-) create mode 100644 pyo3-ffi/Cargo.toml rename {src/ffi => pyo3-ffi}/LICENSE (100%) rename {src/ffi => pyo3-ffi}/README.md (100%) create mode 100644 pyo3-ffi/build.rs rename {src/ffi => pyo3-ffi/src}/abstract_.rs (98%) rename {src/ffi => pyo3-ffi/src}/bltinmodule.rs (84%) rename {src/ffi => pyo3-ffi/src}/boolobject.rs (94%) rename {src/ffi => pyo3-ffi/src}/bytearrayobject.rs (95%) rename {src/ffi => pyo3-ffi/src}/bytesobject.rs (97%) rename {src/ffi => pyo3-ffi/src}/ceval.rs (91%) rename {src/ffi => pyo3-ffi/src}/code.rs (100%) rename {src/ffi => pyo3-ffi/src}/codecs.rs (98%) rename {src/ffi => pyo3-ffi/src}/compile.rs (100%) rename {src/ffi => pyo3-ffi/src}/complexobject.rs (98%) rename {src/ffi => pyo3-ffi/src}/context.rs (96%) rename {src/ffi => pyo3-ffi/src}/cpython/abstract_.rs (98%) rename {src/ffi => pyo3-ffi/src}/cpython/bytesobject.rs (64%) rename {src/ffi => pyo3-ffi/src}/cpython/ceval.rs (55%) rename {src/ffi => pyo3-ffi/src}/cpython/code.rs (97%) rename {src/ffi => pyo3-ffi/src}/cpython/compile.rs (95%) rename {src/ffi => pyo3-ffi/src}/cpython/dictobject.rs (92%) rename {src/ffi => pyo3-ffi/src}/cpython/frameobject.rs (96%) rename {src/ffi => pyo3-ffi/src}/cpython/import.rs (97%) rename {src/ffi => pyo3-ffi/src}/cpython/initconfig.rs (99%) rename {src/ffi => pyo3-ffi/src}/cpython/listobject.rs (92%) create mode 100644 pyo3-ffi/src/cpython/mod.rs rename {src/ffi => pyo3-ffi/src}/cpython/object.rs (95%) rename {src/ffi => pyo3-ffi/src}/cpython/pydebug.rs (100%) rename {src/ffi => pyo3-ffi/src}/cpython/pylifecycle.rs (95%) rename {src/ffi => pyo3-ffi/src}/cpython/pymem.rs (100%) rename {src/ffi => pyo3-ffi/src}/cpython/pystate.rs (93%) rename {src/ffi => pyo3-ffi/src}/cpython/pythonrun.rs (98%) rename {src/ffi => pyo3-ffi/src}/cpython/tupleobject.rs (93%) create mode 100644 pyo3-ffi/src/cpython/unicodeobject.rs create mode 100644 pyo3-ffi/src/datetime.rs rename {src/ffi => pyo3-ffi/src}/descrobject.rs (95%) rename {src/ffi => pyo3-ffi/src}/dictobject.rs (98%) rename {src/ffi => pyo3-ffi/src}/enumobject.rs (80%) rename {src/ffi => pyo3-ffi/src}/eval.rs (95%) rename {src/ffi => pyo3-ffi/src}/fileobject.rs (97%) rename {src/ffi => pyo3-ffi/src}/fileutils.rs (87%) rename {src/ffi => pyo3-ffi/src}/floatobject.rs (98%) rename {src/ffi => pyo3-ffi/src}/funcobject.rs (96%) rename {src/ffi => pyo3-ffi/src}/genobject.rs (95%) rename {src/ffi => pyo3-ffi/src}/import.rs (98%) rename {src/ffi => pyo3-ffi/src}/intrcheck.rs (100%) rename {src/ffi => pyo3-ffi/src}/iterobject.rs (96%) create mode 100644 pyo3-ffi/src/lib.rs rename {src/ffi => pyo3-ffi/src}/listobject.rs (97%) rename {src/ffi => pyo3-ffi/src}/longobject.rs (98%) rename {src/ffi => pyo3-ffi/src}/marshal.rs (100%) rename {src/ffi => pyo3-ffi/src}/memoryobject.rs (95%) rename {src/ffi => pyo3-ffi/src}/methodobject.rs (95%) rename {src/ffi => pyo3-ffi/src}/modsupport.rs (97%) rename {src/ffi => pyo3-ffi/src}/moduleobject.rs (96%) rename {src/ffi => pyo3-ffi/src}/object.rs (99%) rename {src/ffi => pyo3-ffi/src}/objimpl.rs (98%) rename {src/ffi => pyo3-ffi/src}/osmodule.rs (69%) rename {src/ffi => pyo3-ffi/src}/pyarena.rs (100%) rename {src/ffi => pyo3-ffi/src}/pycapsule.rs (98%) rename {src/ffi => pyo3-ffi/src}/pyerrors.rs (99%) rename {src/ffi => pyo3-ffi/src}/pyframe.rs (87%) rename {src/ffi => pyo3-ffi/src}/pyhash.rs (96%) rename {src/ffi => pyo3-ffi/src}/pylifecycle.rs (97%) rename {src/ffi => pyo3-ffi/src}/pymem.rs (100%) rename {src/ffi => pyo3-ffi/src}/pyport.rs (100%) rename {src/ffi => pyo3-ffi/src}/pystate.rs (97%) rename {src/ffi => pyo3-ffi/src}/pystrtod.rs (97%) rename {src/ffi => pyo3-ffi/src}/pythonrun.rs (93%) rename {src/ffi => pyo3-ffi/src}/rangeobject.rs (93%) rename {src/ffi => pyo3-ffi/src}/setobject.rs (96%) rename {src/ffi => pyo3-ffi/src}/sliceobject.rs (97%) rename {src/ffi => pyo3-ffi/src}/structmember.rs (96%) rename {src/ffi => pyo3-ffi/src}/structseq.rs (88%) rename {src/ffi => pyo3-ffi/src}/sysmodule.rs (97%) rename {src/ffi => pyo3-ffi/src}/traceback.rs (86%) rename {src/ffi => pyo3-ffi/src}/tupleobject.rs (95%) rename {src/ffi => pyo3-ffi/src}/typeslots.rs (100%) rename {src/ffi => pyo3-ffi/src}/unicodeobject.rs (99%) rename {src/ffi => pyo3-ffi/src}/warnings.rs (92%) rename {src/ffi => pyo3-ffi/src}/weakrefobject.rs (98%) diff --git a/Cargo.toml b/Cargo.toml index fc69989c701..01b33a25ab2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,9 @@ cfg-if = "1.0" libc = "0.2.62" parking_lot = "0.11.0" +# ffi bindings to the python interpreter, split into a seperate crate so they can be used independently +pyo3-ffi = { path = "pyo3-ffi", version = "=0.15.1" } + # support crates for macros feature pyo3-macros = { path = "pyo3-macros", version = "=0.15.1", optional = true } indoc = { version = "1.0.3", optional = true } @@ -60,16 +63,16 @@ multiple-pymethods = ["inventory", "pyo3-macros/multiple-pymethods"] # Use this feature when building an extension module. # It tells the linker to keep the python symbols unresolved, # so that the module can also be used with statically linked python interpreters. -extension-module = [] +extension-module = ["pyo3-ffi/extension-module"] # Use the Python limited API. See https://www.python.org/dev/peps/pep-0384/ for more. -abi3 = ["pyo3-build-config/abi3"] +abi3 = ["pyo3-build-config/abi3", "pyo3-ffi/abi3"] # With abi3, we can manually set the minimum Python version. -abi3-py37 = ["abi3-py38", "pyo3-build-config/abi3-py37"] -abi3-py38 = ["abi3-py39", "pyo3-build-config/abi3-py38"] -abi3-py39 = ["abi3-py310", "pyo3-build-config/abi3-py39"] -abi3-py310 = ["abi3", "pyo3-build-config/abi3-py310"] +abi3-py37 = ["abi3-py38", "pyo3-build-config/abi3-py37", "pyo3-ffi/abi3-py37"] +abi3-py38 = ["abi3-py39", "pyo3-build-config/abi3-py38", "pyo3-ffi/abi3-py37"] +abi3-py39 = ["abi3-py310", "pyo3-build-config/abi3-py39", "pyo3-ffi/abi3-py37"] +abi3-py310 = ["abi3", "pyo3-build-config/abi3-py310", "pyo3-ffi/abi3-py37"] # Changes `Python::with_gil` and `Python::acquire_gil` to automatically initialize the # Python interpreter if needed. @@ -126,6 +129,7 @@ harness = false [workspace] members = [ + "pyo3-ffi", "pyo3-macros", "pyo3-macros-backend", "pytests/pyo3-benchmarks", diff --git a/pyo3-ffi/Cargo.toml b/pyo3-ffi/Cargo.toml new file mode 100644 index 00000000000..d9d15f9d80b --- /dev/null +++ b/pyo3-ffi/Cargo.toml @@ -0,0 +1,39 @@ +[package] +name = "pyo3-ffi" +version = "0.15.1" +description = "Python-API bindings for the PyO3 ecosystem" +authors = ["PyO3 Project and Contributors "] +keywords = ["pyo3", "python", "cpython", "ffi"] +homepage = "https://github.com/pyo3/pyo3" +repository = "https://github.com/pyo3/pyo3" +categories = ["api-bindings", "development-tools::ffi"] +license = "Apache-2.0" +edition = "2018" + +[dependencies] +libc = "0.2.62" + +[features] + +default = [] + +# Use this feature when building an extension module. +# It tells the linker to keep the python symbols unresolved, +# so that the module can also be used with statically linked python interpreters. +extension-module = [] + +# Use the Python limited API. See https://www.python.org/dev/peps/pep-0384/ for more. +abi3 = ["pyo3-build-config/abi3"] + +# With abi3, we can manually set the minimum Python version. +abi3-py37 = ["abi3-py38", "pyo3-build-config/abi3-py37"] +abi3-py38 = ["abi3-py39", "pyo3-build-config/abi3-py38"] +abi3-py39 = ["abi3-py310", "pyo3-build-config/abi3-py39"] +abi3-py310 = ["abi3", "pyo3-build-config/abi3-py310"] + + + +[build-dependencies] +pyo3-build-config = { path = "../pyo3-build-config", version = "0.15.1", features = ["resolve-config"] } + + diff --git a/src/ffi/LICENSE b/pyo3-ffi/LICENSE similarity index 100% rename from src/ffi/LICENSE rename to pyo3-ffi/LICENSE diff --git a/src/ffi/README.md b/pyo3-ffi/README.md similarity index 100% rename from src/ffi/README.md rename to pyo3-ffi/README.md diff --git a/pyo3-ffi/build.rs b/pyo3-ffi/build.rs new file mode 100644 index 00000000000..2e4c0578eb6 --- /dev/null +++ b/pyo3-ffi/build.rs @@ -0,0 +1,151 @@ +use std::env; + +use pyo3_build_config::{ + bail, ensure, + pyo3_build_script_impl::{ + cargo_env_var, env_var, errors::Result, resolve_interpreter_config, InterpreterConfig, + PythonVersion, + }, +}; + +/// Minimum Python version PyO3 supports. +const MINIMUM_SUPPORTED_VERSION: PythonVersion = PythonVersion { major: 3, minor: 6 }; + +fn ensure_python_version(interpreter_config: &InterpreterConfig) -> Result<()> { + ensure!( + interpreter_config.version >= MINIMUM_SUPPORTED_VERSION, + "the configured Python interpreter version ({}) is lower than PyO3's minimum supported version ({})", + interpreter_config.version, + MINIMUM_SUPPORTED_VERSION, + ); + + Ok(()) +} + +fn ensure_target_pointer_width(interpreter_config: &InterpreterConfig) -> Result<()> { + if let Some(pointer_width) = interpreter_config.pointer_width { + // Try to check whether the target architecture matches the python library + let rust_target = match cargo_env_var("CARGO_CFG_TARGET_POINTER_WIDTH") + .unwrap() + .as_str() + { + "64" => 64, + "32" => 32, + x => bail!("unexpected Rust target pointer width: {}", x), + }; + + ensure!( + rust_target == pointer_width, + "your Rust target architecture ({}-bit) does not match your python interpreter ({}-bit)", + rust_target, + pointer_width + ); + } + Ok(()) +} + +fn ensure_auto_initialize_ok(interpreter_config: &InterpreterConfig) -> Result<()> { + if cargo_env_var("CARGO_FEATURE_AUTO_INITIALIZE").is_some() { + if !interpreter_config.shared { + bail!( + "The `auto-initialize` feature is enabled, but your python installation only supports \ + embedding the Python interpreter statically. If you are attempting to run tests, or a \ + binary which is okay to link dynamically, install a Python distribution which ships \ + with the Python shared library.\n\ + \n\ + Embedding the Python interpreter statically does not yet have first-class support in \ + PyO3. If you are sure you intend to do this, disable the `auto-initialize` feature.\n\ + \n\ + For more information, see \ + https://pyo3.rs/v{pyo3_version}/\ + building_and_distribution.html#embedding-python-in-rust", + pyo3_version = env::var("CARGO_PKG_VERSION").unwrap() + ); + } + + // TODO: PYO3_CI env is a hack to workaround CI with PyPy, where the `dev-dependencies` + // currently cause `auto-initialize` to be enabled in CI. + // Once MSRV is 1.51 or higher, use cargo's `resolver = "2"` instead. + if interpreter_config.implementation.is_pypy() && env::var_os("PYO3_CI").is_none() { + bail!("the `auto-initialize` feature is not supported with PyPy"); + } + } + Ok(()) +} + +fn emit_link_config(interpreter_config: &InterpreterConfig) -> Result<()> { + let target_os = cargo_env_var("CARGO_CFG_TARGET_OS").unwrap(); + let is_extension_module = cargo_env_var("CARGO_FEATURE_EXTENSION_MODULE").is_some(); + if target_os == "windows" || target_os == "android" || !is_extension_module { + // windows and android - always link + // other systems - only link if not extension module + println!( + "cargo:rustc-link-lib={link_model}{alias}{lib_name}", + link_model = if interpreter_config.shared { + "" + } else { + "static=" + }, + alias = if target_os == "windows" { + "pythonXY:" + } else { + "" + }, + lib_name = interpreter_config.lib_name.as_ref().ok_or( + "attempted to link to Python shared library but config does not contain lib_name" + )?, + ); + if let Some(lib_dir) = &interpreter_config.lib_dir { + println!("cargo:rustc-link-search=native={}", lib_dir); + } + } + + Ok(()) +} + +/// Prepares the PyO3 crate for compilation. +/// +/// This loads the config from pyo3-build-config and then makes some additional checks to improve UX +/// for users. +/// +/// Emits the cargo configuration based on this config as well as a few checks of the Rust compiler +/// version to enable features which aren't supported on MSRV. +fn configure_pyo3() -> Result<()> { + let interpreter_config = resolve_interpreter_config()?; + + if env_var("PYO3_PRINT_CONFIG").map_or(false, |os_str| os_str == "1") { + print_config_and_exit(&interpreter_config); + } + + ensure_python_version(&interpreter_config)?; + ensure_target_pointer_width(&interpreter_config)?; + ensure_auto_initialize_ok(&interpreter_config)?; + + if !interpreter_config.suppress_build_script_link_lines { + emit_link_config(&interpreter_config)?; + } + + interpreter_config.emit_pyo3_cfgs(); + + // Extra lines come last, to support last write wins. + for line in &interpreter_config.extra_build_script_lines { + println!("{}", line); + } + + Ok(()) +} + +fn print_config_and_exit(config: &InterpreterConfig) { + println!("\n-- PYO3_PRINT_CONFIG=1 is set, printing configuration and halting compile --"); + config + .to_writer(&mut std::io::stdout()) + .expect("failed to print config to stdout"); + std::process::exit(101); +} + +fn main() { + if let Err(e) = configure_pyo3() { + eprintln!("error: {}", e.report()); + std::process::exit(1) + } +} diff --git a/src/ffi/abstract_.rs b/pyo3-ffi/src/abstract_.rs similarity index 98% rename from src/ffi/abstract_.rs rename to pyo3-ffi/src/abstract_.rs index 07e02da4a52..172396aa839 100644 --- a/src/ffi/abstract_.rs +++ b/pyo3-ffi/src/abstract_.rs @@ -1,5 +1,5 @@ -use crate::ffi::object::*; -use crate::ffi::pyport::Py_ssize_t; +use crate::object::*; +use crate::pyport::Py_ssize_t; use std::os::raw::{c_char, c_int}; use std::ptr; @@ -96,10 +96,9 @@ extern "C" { #[cfg(not(any(Py_LIMITED_API, PyPy)))] #[inline] pub unsafe fn PyIter_Check(o: *mut PyObject) -> c_int { - (match (*crate::ffi::Py_TYPE(o)).tp_iternext { + (match (*crate::Py_TYPE(o)).tp_iternext { Some(tp_iternext) => { - tp_iternext as *const std::os::raw::c_void - != crate::ffi::_PyObject_NextNotImplemented as _ + tp_iternext as *const std::os::raw::c_void != crate::_PyObject_NextNotImplemented as _ } None => false, }) as c_int diff --git a/src/ffi/bltinmodule.rs b/pyo3-ffi/src/bltinmodule.rs similarity index 84% rename from src/ffi/bltinmodule.rs rename to pyo3-ffi/src/bltinmodule.rs index f7069178ad5..cd5be0439a3 100644 --- a/src/ffi/bltinmodule.rs +++ b/pyo3-ffi/src/bltinmodule.rs @@ -1,4 +1,4 @@ -use crate::ffi::object::PyTypeObject; +use crate::object::PyTypeObject; #[cfg_attr(windows, link(name = "pythonXY"))] extern "C" { diff --git a/src/ffi/boolobject.rs b/pyo3-ffi/src/boolobject.rs similarity index 94% rename from src/ffi/boolobject.rs rename to pyo3-ffi/src/boolobject.rs index 92d77d018b0..2b72db3f746 100644 --- a/src/ffi/boolobject.rs +++ b/pyo3-ffi/src/boolobject.rs @@ -1,5 +1,5 @@ -use crate::ffi::longobject::PyLongObject; -use crate::ffi::object::*; +use crate::longobject::PyLongObject; +use crate::object::*; use std::os::raw::{c_int, c_long}; #[cfg_attr(windows, link(name = "pythonXY"))] diff --git a/src/ffi/bytearrayobject.rs b/pyo3-ffi/src/bytearrayobject.rs similarity index 95% rename from src/ffi/bytearrayobject.rs rename to pyo3-ffi/src/bytearrayobject.rs index e7131a170f0..d8df2d6a87b 100644 --- a/src/ffi/bytearrayobject.rs +++ b/pyo3-ffi/src/bytearrayobject.rs @@ -1,5 +1,5 @@ -use crate::ffi::object::*; -use crate::ffi::pyport::Py_ssize_t; +use crate::object::*; +use crate::pyport::Py_ssize_t; use std::os::raw::{c_char, c_int}; #[cfg_attr(windows, link(name = "pythonXY"))] diff --git a/src/ffi/bytesobject.rs b/pyo3-ffi/src/bytesobject.rs similarity index 97% rename from src/ffi/bytesobject.rs rename to pyo3-ffi/src/bytesobject.rs index 1e52a47bb9c..058f402c6c3 100644 --- a/src/ffi/bytesobject.rs +++ b/pyo3-ffi/src/bytesobject.rs @@ -1,5 +1,5 @@ -use crate::ffi::object::*; -use crate::ffi::pyport::Py_ssize_t; +use crate::object::*; +use crate::pyport::Py_ssize_t; use std::os::raw::{c_char, c_int}; #[cfg_attr(windows, link(name = "pythonXY"))] diff --git a/src/ffi/ceval.rs b/pyo3-ffi/src/ceval.rs similarity index 91% rename from src/ffi/ceval.rs rename to pyo3-ffi/src/ceval.rs index 4031daa7b47..a45b305937c 100644 --- a/src/ffi/ceval.rs +++ b/pyo3-ffi/src/ceval.rs @@ -1,5 +1,5 @@ -use crate::ffi::object::PyObject; -use crate::ffi::pystate::PyThreadState; +use crate::object::PyObject; +use crate::pystate::PyThreadState; use std::os::raw::{c_char, c_int, c_void}; extern "C" { @@ -37,7 +37,7 @@ extern "C" { pub fn PyEval_GetGlobals() -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyEval_GetLocals")] pub fn PyEval_GetLocals() -> *mut PyObject; - pub fn PyEval_GetFrame() -> *mut crate::ffi::PyFrameObject; + pub fn PyEval_GetFrame() -> *mut crate::PyFrameObject; #[cfg_attr(PyPy, link_name = "PyPy_AddPendingCall")] pub fn Py_AddPendingCall( func: Option c_int>, @@ -59,8 +59,8 @@ extern "C" { pub fn PyEval_GetFuncName(arg1: *mut PyObject) -> *const c_char; pub fn PyEval_GetFuncDesc(arg1: *mut PyObject) -> *const c_char; pub fn PyEval_GetCallStats(arg1: *mut PyObject) -> *mut PyObject; - pub fn PyEval_EvalFrame(arg1: *mut crate::ffi::PyFrameObject) -> *mut PyObject; - pub fn PyEval_EvalFrameEx(f: *mut crate::ffi::PyFrameObject, exc: c_int) -> *mut PyObject; + pub fn PyEval_EvalFrame(arg1: *mut crate::PyFrameObject) -> *mut PyObject; + pub fn PyEval_EvalFrameEx(f: *mut crate::PyFrameObject, exc: c_int) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyEval_SaveThread")] pub fn PyEval_SaveThread() -> *mut PyThreadState; #[cfg_attr(PyPy, link_name = "PyPyEval_RestoreThread")] diff --git a/src/ffi/code.rs b/pyo3-ffi/src/code.rs similarity index 100% rename from src/ffi/code.rs rename to pyo3-ffi/src/code.rs diff --git a/src/ffi/codecs.rs b/pyo3-ffi/src/codecs.rs similarity index 98% rename from src/ffi/codecs.rs rename to pyo3-ffi/src/codecs.rs index 6c23e29602f..2fd214cbbfe 100644 --- a/src/ffi/codecs.rs +++ b/pyo3-ffi/src/codecs.rs @@ -1,4 +1,4 @@ -use crate::ffi::object::PyObject; +use crate::object::PyObject; use std::os::raw::{c_char, c_int}; extern "C" { diff --git a/src/ffi/compile.rs b/pyo3-ffi/src/compile.rs similarity index 100% rename from src/ffi/compile.rs rename to pyo3-ffi/src/compile.rs diff --git a/src/ffi/complexobject.rs b/pyo3-ffi/src/complexobject.rs similarity index 98% rename from src/ffi/complexobject.rs rename to pyo3-ffi/src/complexobject.rs index beecb42141e..829adf82783 100644 --- a/src/ffi/complexobject.rs +++ b/pyo3-ffi/src/complexobject.rs @@ -1,4 +1,4 @@ -use crate::ffi::object::*; +use crate::object::*; use std::os::raw::{c_double, c_int}; #[repr(C)] diff --git a/src/ffi/context.rs b/pyo3-ffi/src/context.rs similarity index 96% rename from src/ffi/context.rs rename to pyo3-ffi/src/context.rs index f3872a6972a..d720cbe077d 100644 --- a/src/ffi/context.rs +++ b/pyo3-ffi/src/context.rs @@ -1,4 +1,4 @@ -use crate::ffi::object::{PyObject, PyTypeObject, Py_TYPE}; +use crate::object::{PyObject, PyTypeObject, Py_TYPE}; use std::os::raw::{c_char, c_int}; extern "C" { diff --git a/src/ffi/cpython/abstract_.rs b/pyo3-ffi/src/cpython/abstract_.rs similarity index 98% rename from src/ffi/cpython/abstract_.rs rename to pyo3-ffi/src/cpython/abstract_.rs index b86ed1a7008..a7383c2fc0c 100644 --- a/src/ffi/cpython/abstract_.rs +++ b/pyo3-ffi/src/cpython/abstract_.rs @@ -1,8 +1,8 @@ -use crate::ffi::{PyObject, Py_buffer, Py_ssize_t}; +use crate::{PyObject, Py_buffer, Py_ssize_t}; use std::os::raw::{c_char, c_int, c_void}; #[cfg(all(Py_3_8, not(PyPy)))] -use crate::ffi::{ +use crate::{ pyport::PY_SSIZE_T_MAX, vectorcallfunc, PyCallable_Check, PyThreadState, PyThreadState_GET, PyTuple_Check, PyType_HasFeature, Py_TPFLAGS_HAVE_VECTORCALL, }; @@ -51,7 +51,7 @@ pub unsafe fn PyVectorcall_NARGS(n: size_t) -> Py_ssize_t { #[inline(always)] pub unsafe fn PyVectorcall_Function(callable: *mut PyObject) -> Option { assert!(!callable.is_null()); - let tp = crate::ffi::Py_TYPE(callable); + let tp = crate::Py_TYPE(callable); if PyType_HasFeature(tp, Py_TPFLAGS_HAVE_VECTORCALL) == 0 { return None; } @@ -218,7 +218,7 @@ extern "C" { #[cfg(not(any(Py_3_9, PyPy)))] #[inline] pub unsafe fn PyObject_CheckBuffer(o: *mut PyObject) -> c_int { - let tp_as_buffer = (*crate::ffi::Py_TYPE(o)).tp_as_buffer; + let tp_as_buffer = (*crate::Py_TYPE(o)).tp_as_buffer; (!tp_as_buffer.is_null() && (*tp_as_buffer).bf_getbuffer.is_some()) as c_int } diff --git a/src/ffi/cpython/bytesobject.rs b/pyo3-ffi/src/cpython/bytesobject.rs similarity index 64% rename from src/ffi/cpython/bytesobject.rs rename to pyo3-ffi/src/cpython/bytesobject.rs index 108dbb0cff2..9d02c32b362 100644 --- a/src/ffi/cpython/bytesobject.rs +++ b/pyo3-ffi/src/cpython/bytesobject.rs @@ -1,5 +1,5 @@ -use crate::ffi::object::PyObject; -use crate::ffi::pyport::Py_ssize_t; +use crate::object::PyObject; +use crate::pyport::Py_ssize_t; use std::os::raw::c_int; extern "C" { diff --git a/src/ffi/cpython/ceval.rs b/pyo3-ffi/src/cpython/ceval.rs similarity index 55% rename from src/ffi/cpython/ceval.rs rename to pyo3-ffi/src/cpython/ceval.rs index b85c4d07da3..78678cd15c0 100644 --- a/src/ffi/cpython/ceval.rs +++ b/pyo3-ffi/src/cpython/ceval.rs @@ -1,12 +1,9 @@ -use crate::ffi::cpython::pystate::Py_tracefunc; -use crate::ffi::object::{freefunc, PyObject}; +use crate::cpython::pystate::Py_tracefunc; +use crate::object::{freefunc, PyObject}; use std::os::raw::c_int; extern "C" { - pub fn _PyEval_EvalFrameDefault( - arg1: *mut crate::ffi::PyFrameObject, - exc: c_int, - ) -> *mut PyObject; + pub fn _PyEval_EvalFrameDefault(arg1: *mut crate::PyFrameObject, exc: c_int) -> *mut PyObject; pub fn _PyEval_RequestCodeExtraIndex(func: freefunc) -> c_int; pub fn PyEval_SetProfile(trace_func: Option, arg1: *mut PyObject); pub fn PyEval_SetTrace(trace_func: Option, arg1: *mut PyObject); diff --git a/src/ffi/cpython/code.rs b/pyo3-ffi/src/cpython/code.rs similarity index 97% rename from src/ffi/cpython/code.rs rename to pyo3-ffi/src/cpython/code.rs index 7ebceb9f208..9365785508f 100644 --- a/src/ffi/cpython/code.rs +++ b/pyo3-ffi/src/cpython/code.rs @@ -1,5 +1,5 @@ -use crate::ffi::object::*; -use crate::ffi::pyport::Py_ssize_t; +use crate::object::*; +use crate::pyport::Py_ssize_t; use std::os::raw::{c_char, c_int, c_uchar, c_void}; // skipped _Py_CODEUNIT @@ -90,7 +90,7 @@ pub unsafe fn PyCode_Check(op: *mut PyObject) -> c_int { #[inline] #[cfg(not(PyPy))] pub unsafe fn PyCode_GetNumFree(op: *mut PyCodeObject) -> Py_ssize_t { - crate::ffi::PyTuple_GET_SIZE((*op).co_freevars) + crate::PyTuple_GET_SIZE((*op).co_freevars) } extern "C" { diff --git a/src/ffi/cpython/compile.rs b/pyo3-ffi/src/cpython/compile.rs similarity index 95% rename from src/ffi/cpython/compile.rs rename to pyo3-ffi/src/cpython/compile.rs index 4308730ea76..aa459d33ec0 100644 --- a/src/ffi/cpython/compile.rs +++ b/pyo3-ffi/src/cpython/compile.rs @@ -1,11 +1,11 @@ #[cfg(not(Py_3_10))] -use crate::ffi::object::PyObject; +use crate::object::PyObject; #[cfg(not(Py_3_10))] -use crate::ffi::pyarena::*; +use crate::pyarena::*; #[cfg(not(Py_3_10))] -use crate::ffi::pythonrun::*; +use crate::pythonrun::*; #[cfg(not(Py_3_10))] -use crate::ffi::PyCodeObject; +use crate::PyCodeObject; #[cfg(not(Py_3_10))] use std::os::raw::c_char; use std::os::raw::c_int; diff --git a/src/ffi/cpython/dictobject.rs b/pyo3-ffi/src/cpython/dictobject.rs similarity index 92% rename from src/ffi/cpython/dictobject.rs rename to pyo3-ffi/src/cpython/dictobject.rs index 3e58e7b90b8..480cecc77c2 100644 --- a/src/ffi/cpython/dictobject.rs +++ b/pyo3-ffi/src/cpython/dictobject.rs @@ -1,5 +1,5 @@ -use crate::ffi::object::*; -use crate::ffi::pyport::Py_ssize_t; +use crate::object::*; +use crate::pyport::Py_ssize_t; use std::os::raw::c_int; opaque_struct!(PyDictKeysObject); @@ -24,7 +24,7 @@ extern "C" { mp: *mut PyObject, key: *mut PyObject, item: *mut PyObject, - hash: crate::ffi::Py_hash_t, + hash: crate::Py_hash_t, ) -> c_int; // skipped _PyDict_DelItem_KnownHash // skipped _PyDict_DelItemIf @@ -34,7 +34,7 @@ extern "C" { pos: *mut Py_ssize_t, key: *mut *mut PyObject, value: *mut *mut PyObject, - hash: *mut crate::ffi::Py_hash_t, + hash: *mut crate::Py_hash_t, ) -> c_int; // skipped PyDict_GET_SIZE // skipped _PyDict_Contains_KnownHash diff --git a/src/ffi/cpython/frameobject.rs b/pyo3-ffi/src/cpython/frameobject.rs similarity index 96% rename from src/ffi/cpython/frameobject.rs rename to pyo3-ffi/src/cpython/frameobject.rs index 2f7d2b1df90..53d2d494531 100644 --- a/src/ffi/cpython/frameobject.rs +++ b/pyo3-ffi/src/cpython/frameobject.rs @@ -1,6 +1,6 @@ -use crate::ffi::cpython::code::{PyCodeObject, CO_MAXBLOCKS}; -use crate::ffi::object::*; -use crate::ffi::pystate::PyThreadState; +use crate::cpython::code::{PyCodeObject, CO_MAXBLOCKS}; +use crate::object::*; +use crate::pystate::PyThreadState; use std::os::raw::{c_char, c_int}; // skipped _framestate diff --git a/src/ffi/cpython/import.rs b/pyo3-ffi/src/cpython/import.rs similarity index 97% rename from src/ffi/cpython/import.rs rename to pyo3-ffi/src/cpython/import.rs index f342c0e3bd0..d85eb5fadca 100644 --- a/src/ffi/cpython/import.rs +++ b/pyo3-ffi/src/cpython/import.rs @@ -1,4 +1,4 @@ -use crate::ffi::{PyInterpreterState, PyObject}; +use crate::{PyInterpreterState, PyObject}; use std::os::raw::{c_char, c_int, c_uchar}; // skipped PyInit__imp diff --git a/src/ffi/cpython/initconfig.rs b/pyo3-ffi/src/cpython/initconfig.rs similarity index 99% rename from src/ffi/cpython/initconfig.rs rename to pyo3-ffi/src/cpython/initconfig.rs index 95d28b02bf3..552a3664191 100644 --- a/src/ffi/cpython/initconfig.rs +++ b/pyo3-ffi/src/cpython/initconfig.rs @@ -1,6 +1,6 @@ /* --- PyStatus ----------------------------------------------- */ -use crate::ffi::Py_ssize_t; +use crate::Py_ssize_t; use libc::wchar_t; use std::os::raw::{c_char, c_int, c_ulong}; diff --git a/src/ffi/cpython/listobject.rs b/pyo3-ffi/src/cpython/listobject.rs similarity index 92% rename from src/ffi/cpython/listobject.rs rename to pyo3-ffi/src/cpython/listobject.rs index 0489407850b..13b82ff1dfb 100644 --- a/src/ffi/cpython/listobject.rs +++ b/pyo3-ffi/src/cpython/listobject.rs @@ -1,5 +1,5 @@ -use crate::ffi::object::*; -use crate::ffi::pyport::Py_ssize_t; +use crate::object::*; +use crate::pyport::Py_ssize_t; #[repr(C)] #[derive(Copy, Clone)] diff --git a/pyo3-ffi/src/cpython/mod.rs b/pyo3-ffi/src/cpython/mod.rs new file mode 100644 index 00000000000..332b2b225cd --- /dev/null +++ b/pyo3-ffi/src/cpython/mod.rs @@ -0,0 +1,52 @@ +pub(crate) mod abstract_; +// skipped bytearrayobject.h +#[cfg(not(PyPy))] +pub(crate) mod bytesobject; +#[cfg(not(PyPy))] +pub(crate) mod ceval; +pub(crate) mod code; +pub(crate) mod compile; +#[cfg(not(PyPy))] +pub(crate) mod dictobject; +// skipped fileobject.h +// skipped fileutils.h +pub(crate) mod frameobject; +pub(crate) mod import; +#[cfg(all(Py_3_8, not(PyPy)))] +pub(crate) mod initconfig; +// skipped interpreteridobject.h +pub(crate) mod listobject; +pub(crate) mod object; +pub(crate) mod pydebug; +#[cfg(all(Py_3_8, not(PyPy)))] +pub(crate) mod pylifecycle; +pub(crate) mod pymem; +pub(crate) mod pystate; +pub(crate) mod pythonrun; +// skipped sysmodule.h +pub(crate) mod tupleobject; +pub(crate) mod unicodeobject; + +pub use self::abstract_::*; +#[cfg(not(PyPy))] +pub use self::bytesobject::*; +#[cfg(not(PyPy))] +pub use self::ceval::*; +pub use self::code::*; +pub use self::compile::*; +#[cfg(not(PyPy))] +pub use self::dictobject::*; +pub use self::frameobject::*; +pub use self::import::*; +#[cfg(all(Py_3_8, not(PyPy)))] +pub use self::initconfig::*; +pub use self::listobject::*; +pub use self::object::*; +pub use self::pydebug::*; +#[cfg(all(Py_3_8, not(PyPy)))] +pub use self::pylifecycle::*; +pub use self::pymem::*; +pub use self::pystate::*; +pub use self::pythonrun::*; +pub use self::tupleobject::*; +pub use self::unicodeobject::*; diff --git a/src/ffi/cpython/object.rs b/pyo3-ffi/src/cpython/object.rs similarity index 95% rename from src/ffi/cpython/object.rs rename to pyo3-ffi/src/cpython/object.rs index 31a7c3d5031..08c79977209 100644 --- a/src/ffi/cpython/object.rs +++ b/pyo3-ffi/src/cpython/object.rs @@ -1,4 +1,4 @@ -use crate::ffi::PyObject; +use crate::PyObject; use std::os::raw::c_int; // skipped _Py_NewReference @@ -12,7 +12,7 @@ use std::os::raw::c_int; // skipped _Py_IDENTIFIER mod bufferinfo { - use crate::ffi::Py_ssize_t; + use crate::Py_ssize_t; use std::os::raw::{c_char, c_int, c_void}; use std::ptr; @@ -24,7 +24,7 @@ mod bufferinfo { pub struct Py_buffer { pub buf: *mut c_void, /// Owned reference - pub obj: *mut crate::ffi::PyObject, + pub obj: *mut crate::PyObject, pub len: Py_ssize_t, pub itemsize: Py_ssize_t, pub readonly: c_int, @@ -67,12 +67,12 @@ mod bufferinfo { } pub type getbufferproc = unsafe extern "C" fn( - arg1: *mut crate::ffi::PyObject, + arg1: *mut crate::PyObject, arg2: *mut Py_buffer, arg3: c_int, ) -> c_int; pub type releasebufferproc = - unsafe extern "C" fn(arg1: *mut crate::ffi::PyObject, arg2: *mut Py_buffer); + unsafe extern "C" fn(arg1: *mut crate::PyObject, arg2: *mut Py_buffer); /// Maximum number of dimensions pub const PyBUF_MAX_NDIM: c_int = 64; @@ -117,8 +117,8 @@ pub type vectorcallfunc = unsafe extern "C" fn( ) -> *mut PyObject; mod typeobject { - use crate::ffi::{self, object}; - use crate::ffi::{PyObject, Py_ssize_t}; + use crate::object; + use crate::{PyObject, Py_ssize_t}; use std::mem; use std::os::raw::{c_char, c_int, c_uint, c_ulong, c_void}; @@ -248,9 +248,9 @@ mod typeobject { pub tp_weaklistoffset: Py_ssize_t, pub tp_iter: Option, pub tp_iternext: Option, - pub tp_methods: *mut ffi::methodobject::PyMethodDef, - pub tp_members: *mut ffi::structmember::PyMemberDef, - pub tp_getset: *mut ffi::descrobject::PyGetSetDef, + pub tp_methods: *mut crate::methodobject::PyMethodDef, + pub tp_members: *mut crate::structmember::PyMemberDef, + pub tp_getset: *mut crate::descrobject::PyGetSetDef, pub tp_base: *mut PyTypeObject, pub tp_dict: *mut object::PyObject, pub tp_descr_get: Option, @@ -310,10 +310,10 @@ mod typeobject { #[inline] pub unsafe fn PyHeapType_GET_MEMBERS( etype: *mut PyHeapTypeObject, - ) -> *mut ffi::structmember::PyMemberDef { + ) -> *mut crate::structmember::PyMemberDef { let py_type = object::Py_TYPE(etype as *mut object::PyObject); let ptr = etype.offset((*py_type).tp_basicsize); - ptr as *mut ffi::structmember::PyMemberDef + ptr as *mut crate::structmember::PyMemberDef } } diff --git a/src/ffi/cpython/pydebug.rs b/pyo3-ffi/src/cpython/pydebug.rs similarity index 100% rename from src/ffi/cpython/pydebug.rs rename to pyo3-ffi/src/cpython/pydebug.rs diff --git a/src/ffi/cpython/pylifecycle.rs b/pyo3-ffi/src/cpython/pylifecycle.rs similarity index 95% rename from src/ffi/cpython/pylifecycle.rs rename to pyo3-ffi/src/cpython/pylifecycle.rs index b05cbe8cd98..3f1f16e26a4 100644 --- a/src/ffi/cpython/pylifecycle.rs +++ b/pyo3-ffi/src/cpython/pylifecycle.rs @@ -1,4 +1,4 @@ -use crate::ffi::{PyConfig, PyPreConfig, PyStatus, Py_ssize_t}; +use crate::{PyConfig, PyPreConfig, PyStatus, Py_ssize_t}; use libc::wchar_t; use std::os::raw::{c_char, c_int}; diff --git a/src/ffi/cpython/pymem.rs b/pyo3-ffi/src/cpython/pymem.rs similarity index 100% rename from src/ffi/cpython/pymem.rs rename to pyo3-ffi/src/cpython/pymem.rs diff --git a/src/ffi/cpython/pystate.rs b/pyo3-ffi/src/cpython/pystate.rs similarity index 93% rename from src/ffi/cpython/pystate.rs rename to pyo3-ffi/src/cpython/pystate.rs index 3f545450486..67fa42d3df9 100644 --- a/src/ffi/cpython/pystate.rs +++ b/pyo3-ffi/src/cpython/pystate.rs @@ -1,6 +1,6 @@ #[cfg(not(PyPy))] -use crate::ffi::PyThreadState; -use crate::ffi::{PyFrameObject, PyInterpreterState, PyObject}; +use crate::PyThreadState; +use crate::{PyFrameObject, PyInterpreterState, PyObject}; use std::os::raw::c_int; // skipped _PyInterpreterState_RequiresIDRef @@ -60,10 +60,10 @@ extern "C" { #[cfg(Py_3_9)] pub type _PyFrameEvalFunction = extern "C" fn( - *mut crate::ffi::PyThreadState, - *mut crate::ffi::PyFrameObject, + *mut crate::PyThreadState, + *mut crate::PyFrameObject, c_int, -) -> *mut crate::ffi::object::PyObject; +) -> *mut crate::object::PyObject; #[cfg(Py_3_9)] extern "C" { diff --git a/src/ffi/cpython/pythonrun.rs b/pyo3-ffi/src/cpython/pythonrun.rs similarity index 98% rename from src/ffi/cpython/pythonrun.rs rename to pyo3-ffi/src/cpython/pythonrun.rs index 8c3a41f2fd6..ba86fe335f8 100644 --- a/src/ffi/cpython/pythonrun.rs +++ b/pyo3-ffi/src/cpython/pythonrun.rs @@ -1,9 +1,9 @@ -use crate::ffi::object::*; +use crate::object::*; #[cfg(all(not(Py_LIMITED_API), not(Py_3_10)))] -use crate::ffi::pyarena::PyArena; -use crate::ffi::PyCompilerFlags; +use crate::pyarena::PyArena; +use crate::PyCompilerFlags; #[cfg(not(Py_3_10))] -use crate::ffi::{_mod, _node}; +use crate::{_mod, _node}; use libc::FILE; use std::os::raw::{c_char, c_int}; diff --git a/src/ffi/cpython/tupleobject.rs b/pyo3-ffi/src/cpython/tupleobject.rs similarity index 93% rename from src/ffi/cpython/tupleobject.rs rename to pyo3-ffi/src/cpython/tupleobject.rs index 16993a4128a..77baf95c8e4 100644 --- a/src/ffi/cpython/tupleobject.rs +++ b/pyo3-ffi/src/cpython/tupleobject.rs @@ -1,6 +1,6 @@ -use crate::ffi::object::*; +use crate::object::*; #[cfg(not(PyPy))] -use crate::ffi::pyport::Py_ssize_t; +use crate::pyport::Py_ssize_t; #[repr(C)] pub struct PyTupleObject { diff --git a/pyo3-ffi/src/cpython/unicodeobject.rs b/pyo3-ffi/src/cpython/unicodeobject.rs new file mode 100644 index 00000000000..0fa355f93e9 --- /dev/null +++ b/pyo3-ffi/src/cpython/unicodeobject.rs @@ -0,0 +1,482 @@ +use crate::{PyObject, Py_UCS1, Py_UCS2, Py_UCS4, Py_UNICODE, Py_hash_t, Py_ssize_t}; +use libc::wchar_t; +use std::os::raw::{c_char, c_int, c_uint, c_void}; + +// skipped Py_UNICODE_ISSPACE() +// skipped Py_UNICODE_ISLOWER() +// skipped Py_UNICODE_ISUPPER() +// skipped Py_UNICODE_ISTITLE() +// skipped Py_UNICODE_ISLINEBREAK +// skipped Py_UNICODE_TOLOWER +// skipped Py_UNICODE_TOUPPER +// skipped Py_UNICODE_TOTITLE +// skipped Py_UNICODE_ISDECIMAL +// skipped Py_UNICODE_ISDIGIT +// skipped Py_UNICODE_ISNUMERIC +// skipped Py_UNICODE_ISPRINTABLE +// skipped Py_UNICODE_TODECIMAL +// skipped Py_UNICODE_TODIGIT +// skipped Py_UNICODE_TONUMERIC +// skipped Py_UNICODE_ISALPHA +// skipped Py_UNICODE_ISALNUM +// skipped Py_UNICODE_COPY +// skipped Py_UNICODE_FILL +// skipped Py_UNICODE_IS_SURROGATE +// skipped Py_UNICODE_IS_HIGH_SURROGATE +// skipped Py_UNICODE_IS_LOW_SURROGATE +// skipped Py_UNICODE_JOIN_SURROGATES +// skipped Py_UNICODE_HIGH_SURROGATE +// skipped Py_UNICODE_LOW_SURROGATE + +#[repr(C)] +pub struct PyASCIIObject { + pub ob_base: PyObject, + pub length: Py_ssize_t, + pub hash: Py_hash_t, + /// A bit field with various properties. + /// + /// Rust doesn't expose bitfields. So we have accessor functions for + /// retrieving values. + /// + /// unsigned int interned:2; // SSTATE_* constants. + /// unsigned int kind:3; // PyUnicode_*_KIND constants. + /// unsigned int compact:1; + /// unsigned int ascii:1; + /// unsigned int ready:1; + /// unsigned int :24; + pub state: u32, + pub wstr: *mut wchar_t, +} + +/// Interacting with the bitfield is not actually well-defined, so we mark these APIs unsafe. +/// +/// In addition, they are disabled on big-endian architectures to restrict this to most "common" +/// platforms, which are at least tested on CI and appear to be sound. +#[cfg(target_endian = "little")] +impl PyASCIIObject { + #[inline] + pub unsafe fn interned(&self) -> c_uint { + self.state & 3 + } + + #[inline] + pub unsafe fn kind(&self) -> c_uint { + (self.state >> 2) & 7 + } + + #[inline] + pub unsafe fn compact(&self) -> c_uint { + (self.state >> 5) & 1 + } + + #[inline] + pub unsafe fn ascii(&self) -> c_uint { + (self.state >> 6) & 1 + } + + #[inline] + pub unsafe fn ready(&self) -> c_uint { + (self.state >> 7) & 1 + } +} + +#[repr(C)] +pub struct PyCompactUnicodeObject { + pub _base: PyASCIIObject, + pub utf8_length: Py_ssize_t, + pub utf8: *mut c_char, + pub wstr_length: Py_ssize_t, +} + +#[repr(C)] +pub union PyUnicodeObjectData { + any: *mut c_void, + latin1: *mut Py_UCS1, + ucs2: *mut Py_UCS2, + ucs4: *mut Py_UCS4, +} + +#[repr(C)] +pub struct PyUnicodeObject { + pub _base: PyCompactUnicodeObject, + pub data: PyUnicodeObjectData, +} + +extern "C" { + #[cfg(not(PyPy))] + pub fn _PyUnicode_CheckConsistency(op: *mut PyObject, check_content: c_int) -> c_int; +} + +// skipped PyUnicode_GET_SIZE +// skipped PyUnicode_GET_DATA_SIZE +// skipped PyUnicode_AS_UNICODE +// skipped PyUnicode_AS_DATA + +pub const SSTATE_NOT_INTERNED: c_uint = 0; +pub const SSTATE_INTERNED_MORTAL: c_uint = 1; +pub const SSTATE_INTERNED_IMMORTAL: c_uint = 2; + +#[inline] +#[cfg(target_endian = "little")] +pub unsafe fn PyUnicode_IS_ASCII(op: *mut PyObject) -> c_uint { + debug_assert!(crate::PyUnicode_Check(op) != 0); + debug_assert!(PyUnicode_IS_READY(op) != 0); + + (*(op as *mut PyASCIIObject)).ascii() +} + +#[inline] +#[cfg(target_endian = "little")] +pub unsafe fn PyUnicode_IS_COMPACT(op: *mut PyObject) -> c_uint { + (*(op as *mut PyASCIIObject)).compact() +} + +#[inline] +#[cfg(target_endian = "little")] +pub unsafe fn PyUnicode_IS_COMPACT_ASCII(op: *mut PyObject) -> c_uint { + if (*(op as *mut PyASCIIObject)).ascii() != 0 && PyUnicode_IS_COMPACT(op) != 0 { + 1 + } else { + 0 + } +} + +#[cfg(not(Py_3_12))] +#[cfg_attr(Py_3_10, deprecated(note = "Python 3.10"))] +pub const PyUnicode_WCHAR_KIND: c_uint = 0; + +pub const PyUnicode_1BYTE_KIND: c_uint = 1; +pub const PyUnicode_2BYTE_KIND: c_uint = 2; +pub const PyUnicode_4BYTE_KIND: c_uint = 4; + +#[inline] +#[cfg(target_endian = "little")] +pub unsafe fn PyUnicode_1BYTE_DATA(op: *mut PyObject) -> *mut Py_UCS1 { + PyUnicode_DATA(op) as *mut Py_UCS1 +} + +#[inline] +#[cfg(target_endian = "little")] +pub unsafe fn PyUnicode_2BYTE_DATA(op: *mut PyObject) -> *mut Py_UCS2 { + PyUnicode_DATA(op) as *mut Py_UCS2 +} + +#[inline] +#[cfg(target_endian = "little")] +pub unsafe fn PyUnicode_4BYTE_DATA(op: *mut PyObject) -> *mut Py_UCS4 { + PyUnicode_DATA(op) as *mut Py_UCS4 +} + +#[inline] +#[cfg(target_endian = "little")] +pub unsafe fn PyUnicode_KIND(op: *mut PyObject) -> c_uint { + debug_assert!(crate::PyUnicode_Check(op) != 0); + debug_assert!(PyUnicode_IS_READY(op) != 0); + + (*(op as *mut PyASCIIObject)).kind() +} + +#[inline] +#[cfg(target_endian = "little")] +pub unsafe fn _PyUnicode_COMPACT_DATA(op: *mut PyObject) -> *mut c_void { + if PyUnicode_IS_ASCII(op) != 0 { + (op as *mut PyASCIIObject).offset(1) as *mut c_void + } else { + (op as *mut PyCompactUnicodeObject).offset(1) as *mut c_void + } +} + +#[inline] +#[cfg(target_endian = "little")] +pub unsafe fn _PyUnicode_NONCOMPACT_DATA(op: *mut PyObject) -> *mut c_void { + debug_assert!(!(*(op as *mut PyUnicodeObject)).data.any.is_null()); + + (*(op as *mut PyUnicodeObject)).data.any +} + +#[inline] +#[cfg(target_endian = "little")] +pub unsafe fn PyUnicode_DATA(op: *mut PyObject) -> *mut c_void { + debug_assert!(crate::PyUnicode_Check(op) != 0); + + if PyUnicode_IS_COMPACT(op) != 0 { + _PyUnicode_COMPACT_DATA(op) + } else { + _PyUnicode_NONCOMPACT_DATA(op) + } +} + +// skipped PyUnicode_WRITE +// skipped PyUnicode_READ +// skipped PyUnicode_READ_CHAR + +#[inline] +#[cfg(target_endian = "little")] +pub unsafe fn PyUnicode_GET_LENGTH(op: *mut PyObject) -> Py_ssize_t { + debug_assert!(crate::PyUnicode_Check(op) != 0); + debug_assert!(PyUnicode_IS_READY(op) != 0); + + (*(op as *mut PyASCIIObject)).length +} + +#[inline] +#[cfg(target_endian = "little")] +pub unsafe fn PyUnicode_IS_READY(op: *mut PyObject) -> c_uint { + (*(op as *mut PyASCIIObject)).ready() +} + +#[cfg(not(Py_3_12))] +#[cfg_attr(Py_3_10, deprecated(note = "Python 3.10"))] +#[inline] +#[cfg(target_endian = "little")] +pub unsafe fn PyUnicode_READY(op: *mut PyObject) -> c_int { + debug_assert!(crate::PyUnicode_Check(op) != 0); + + if PyUnicode_IS_READY(op) != 0 { + 0 + } else { + _PyUnicode_Ready(op) + } +} + +// skipped PyUnicode_MAX_CHAR_VALUE +// skipped _PyUnicode_get_wstr_length +// skipped PyUnicode_WSTR_LENGTH + +extern "C" { + #[cfg_attr(PyPy, link_name = "PyPyUnicode_New")] + pub fn PyUnicode_New(size: Py_ssize_t, maxchar: Py_UCS4) -> *mut PyObject; + #[cfg_attr(PyPy, link_name = "_PyPyUnicode_Ready")] + pub fn _PyUnicode_Ready(unicode: *mut PyObject) -> c_int; + + // skipped _PyUnicode_Copy + + #[cfg(not(PyPy))] + pub fn PyUnicode_CopyCharacters( + to: *mut PyObject, + to_start: Py_ssize_t, + from: *mut PyObject, + from_start: Py_ssize_t, + how_many: Py_ssize_t, + ) -> Py_ssize_t; + + // skipped _PyUnicode_FastCopyCharacters + + #[cfg(not(PyPy))] + pub fn PyUnicode_Fill( + unicode: *mut PyObject, + start: Py_ssize_t, + length: Py_ssize_t, + fill_char: Py_UCS4, + ) -> Py_ssize_t; + + // skipped _PyUnicode_FastFill + + #[cfg(not(Py_3_12))] + #[deprecated] + #[cfg_attr(PyPy, link_name = "PyPyUnicode_FromUnicode")] + pub fn PyUnicode_FromUnicode(u: *const Py_UNICODE, size: Py_ssize_t) -> *mut PyObject; + + #[cfg_attr(PyPy, link_name = "PyPyUnicode_FromKindAndData")] + pub fn PyUnicode_FromKindAndData( + kind: c_int, + buffer: *const c_void, + size: Py_ssize_t, + ) -> *mut PyObject; + + // skipped _PyUnicode_FromASCII + // skipped _PyUnicode_FindMaxChar + + #[cfg(not(Py_3_12))] + #[deprecated] + #[cfg_attr(PyPy, link_name = "PyPyUnicode_AsUnicode")] + pub fn PyUnicode_AsUnicode(unicode: *mut PyObject) -> *mut Py_UNICODE; + + // skipped _PyUnicode_AsUnicode + + #[cfg(not(Py_3_12))] + #[deprecated] + #[cfg_attr(PyPy, link_name = "PyPyUnicode_AsUnicodeAndSize")] + pub fn PyUnicode_AsUnicodeAndSize( + unicode: *mut PyObject, + size: *mut Py_ssize_t, + ) -> *mut Py_UNICODE; + + // skipped PyUnicode_GetMax +} + +// skipped _PyUnicodeWriter +// skipped _PyUnicodeWriter_Init +// skipped _PyUnicodeWriter_Prepare +// skipped _PyUnicodeWriter_PrepareInternal +// skipped _PyUnicodeWriter_PrepareKind +// skipped _PyUnicodeWriter_PrepareKindInternal +// skipped _PyUnicodeWriter_WriteChar +// skipped _PyUnicodeWriter_WriteStr +// skipped _PyUnicodeWriter_WriteSubstring +// skipped _PyUnicodeWriter_WriteASCIIString +// skipped _PyUnicodeWriter_WriteLatin1String +// skipped _PyUnicodeWriter_Finish +// skipped _PyUnicodeWriter_Dealloc +// skipped _PyUnicode_FormatAdvancedWriter + +extern "C" { + // skipped _PyUnicode_AsStringAndSize + + #[cfg_attr(PyPy, link_name = "PyPyUnicode_AsUTF8")] + pub fn PyUnicode_AsUTF8(unicode: *mut PyObject) -> *const c_char; + + // skipped _PyUnicode_AsString + + pub fn PyUnicode_Encode( + s: *const Py_UNICODE, + size: Py_ssize_t, + encoding: *const c_char, + errors: *const c_char, + ) -> *mut PyObject; + + pub fn PyUnicode_EncodeUTF7( + data: *const Py_UNICODE, + length: Py_ssize_t, + base64SetO: c_int, + base64WhiteSpace: c_int, + errors: *const c_char, + ) -> *mut PyObject; + + // skipped _PyUnicode_EncodeUTF7 + // skipped _PyUnicode_AsUTF8String + + #[cfg_attr(PyPy, link_name = "PyPyUnicode_EncodeUTF8")] + pub fn PyUnicode_EncodeUTF8( + data: *const Py_UNICODE, + length: Py_ssize_t, + errors: *const c_char, + ) -> *mut PyObject; + + pub fn PyUnicode_EncodeUTF32( + data: *const Py_UNICODE, + length: Py_ssize_t, + errors: *const c_char, + byteorder: c_int, + ) -> *mut PyObject; + + // skipped _PyUnicode_EncodeUTF32 + + pub fn PyUnicode_EncodeUTF16( + data: *const Py_UNICODE, + length: Py_ssize_t, + errors: *const c_char, + byteorder: c_int, + ) -> *mut PyObject; + + // skipped _PyUnicode_EncodeUTF16 + // skipped _PyUnicode_DecodeUnicodeEscape + + pub fn PyUnicode_EncodeUnicodeEscape( + data: *const Py_UNICODE, + length: Py_ssize_t, + ) -> *mut PyObject; + + pub fn PyUnicode_EncodeRawUnicodeEscape( + data: *const Py_UNICODE, + length: Py_ssize_t, + ) -> *mut PyObject; + + // skipped _PyUnicode_AsLatin1String + + #[cfg_attr(PyPy, link_name = "PyPyUnicode_EncodeLatin1")] + pub fn PyUnicode_EncodeLatin1( + data: *const Py_UNICODE, + length: Py_ssize_t, + errors: *const c_char, + ) -> *mut PyObject; + + // skipped _PyUnicode_AsASCIIString + + #[cfg_attr(PyPy, link_name = "PyPyUnicode_EncodeASCII")] + pub fn PyUnicode_EncodeASCII( + data: *const Py_UNICODE, + length: Py_ssize_t, + errors: *const c_char, + ) -> *mut PyObject; + + pub fn PyUnicode_EncodeCharmap( + data: *const Py_UNICODE, + length: Py_ssize_t, + mapping: *mut PyObject, + errors: *const c_char, + ) -> *mut PyObject; + + // skipped _PyUnicode_EncodeCharmap + + pub fn PyUnicode_TranslateCharmap( + data: *const Py_UNICODE, + length: Py_ssize_t, + table: *mut PyObject, + errors: *const c_char, + ) -> *mut PyObject; + + // skipped PyUnicode_EncodeMBCS + + #[cfg_attr(PyPy, link_name = "PyPyUnicode_EncodeDecimal")] + pub fn PyUnicode_EncodeDecimal( + s: *mut Py_UNICODE, + length: Py_ssize_t, + output: *mut c_char, + errors: *const c_char, + ) -> c_int; + + #[cfg_attr(PyPy, link_name = "PyPyUnicode_TransformDecimalToASCII")] + pub fn PyUnicode_TransformDecimalToASCII( + s: *mut Py_UNICODE, + length: Py_ssize_t, + ) -> *mut PyObject; + + // skipped _PyUnicode_TransformDecimalAndSpaceToASCII +} + +// skipped _PyUnicode_JoinArray +// skipped _PyUnicode_EqualToASCIIId +// skipped _PyUnicode_EqualToASCIIString +// skipped _PyUnicode_XStrip +// skipped _PyUnicode_InsertThousandsGrouping + +// skipped _Py_ascii_whitespace + +// skipped _PyUnicode_IsLowercase +// skipped _PyUnicode_IsUppercase +// skipped _PyUnicode_IsTitlecase +// skipped _PyUnicode_IsXidStart +// skipped _PyUnicode_IsXidContinue +// skipped _PyUnicode_IsWhitespace +// skipped _PyUnicode_IsLinebreak +// skipped _PyUnicode_ToLowercase +// skipped _PyUnicode_ToUppercase +// skipped _PyUnicode_ToTitlecase +// skipped _PyUnicode_ToLowerFull +// skipped _PyUnicode_ToTitleFull +// skipped _PyUnicode_ToUpperFull +// skipped _PyUnicode_ToFoldedFull +// skipped _PyUnicode_IsCaseIgnorable +// skipped _PyUnicode_IsCased +// skipped _PyUnicode_ToDecimalDigit +// skipped _PyUnicode_ToDigit +// skipped _PyUnicode_ToNumeric +// skipped _PyUnicode_IsDecimalDigit +// skipped _PyUnicode_IsDigit +// skipped _PyUnicode_IsNumeric +// skipped _PyUnicode_IsPrintable +// skipped _PyUnicode_IsAlpha +// skipped Py_UNICODE_strlen +// skipped Py_UNICODE_strcpy +// skipped Py_UNICODE_strcat +// skipped Py_UNICODE_strncpy +// skipped Py_UNICODE_strcmp +// skipped Py_UNICODE_strncmp +// skipped Py_UNICODE_strchr +// skipped Py_UNICODE_strrchr +// skipped _PyUnicode_FormatLong +// skipped PyUnicode_AsUnicodeCopy +// skipped _PyUnicode_FromId +// skipped _PyUnicode_EQ +// skipped _PyUnicode_ScanIdentifier diff --git a/pyo3-ffi/src/datetime.rs b/pyo3-ffi/src/datetime.rs new file mode 100644 index 00000000000..b5215743160 --- /dev/null +++ b/pyo3-ffi/src/datetime.rs @@ -0,0 +1,428 @@ +//! FFI bindings to the functions and structs defined in `datetime.h` +//! +//! This is the unsafe thin wrapper around the [CPython C API](https://docs.python.org/3/c-api/datetime.html), +//! and covers the various date and time related objects in the Python `datetime` +//! standard library module. +//! +//! A note regarding PyPy (cpyext) support: +//! +//! Support for `PyDateTime_CAPI` is limited as of PyPy 7.0.0. +//! `DateTime_FromTimestamp` and `Date_FromTimestamp` are currently not supported. + +#[cfg(not(PyPy))] +use crate::Py_hash_t; +use crate::{PyObject, PyTypeObject}; +use std::os::raw::{c_char, c_int, c_uchar}; + +// Type struct wrappers +const _PyDateTime_DATE_DATASIZE: usize = 4; +const _PyDateTime_TIME_DATASIZE: usize = 6; +const _PyDateTime_DATETIME_DATASIZE: usize = 10; + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +/// Structure representing a `datetime.timedelta`. +pub struct PyDateTime_Delta { + pub ob_base: PyObject, + #[cfg(not(PyPy))] + pub hashcode: Py_hash_t, + pub days: c_int, + pub seconds: c_int, + pub microseconds: c_int, +} + +// skipped non-limited PyDateTime_TZInfo +// skipped non-limited _PyDateTime_BaseTZInfo +// skipped non-limited _PyDateTime_BaseTime + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +/// Structure representing a `datetime.time`. +pub struct PyDateTime_Time { + pub ob_base: PyObject, + #[cfg(not(PyPy))] + pub hashcode: Py_hash_t, + pub hastzinfo: c_char, + #[cfg(not(PyPy))] + pub data: [c_uchar; _PyDateTime_TIME_DATASIZE], + #[cfg(not(PyPy))] + pub fold: c_uchar, + pub tzinfo: *mut PyObject, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +/// Structure representing a `datetime.date` +pub struct PyDateTime_Date { + pub ob_base: PyObject, + #[cfg(not(PyPy))] + pub hashcode: Py_hash_t, + pub hastzinfo: c_char, + pub data: [c_uchar; _PyDateTime_DATE_DATASIZE], +} + +// skipped non-limited _PyDateTime_BaseDateTime + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +/// Structure representing a `datetime.datetime` +pub struct PyDateTime_DateTime { + pub ob_base: PyObject, + #[cfg(not(PyPy))] + pub hashcode: Py_hash_t, + pub hastzinfo: c_char, + #[cfg(not(PyPy))] + pub data: [c_uchar; _PyDateTime_DATETIME_DATASIZE], + #[cfg(not(PyPy))] + pub fold: c_uchar, + pub tzinfo: *mut PyObject, +} + +// skipped non-limited _PyDateTime_HAS_TZINFO + +// Accessor functions for PyDateTime_Date and PyDateTime_DateTime +#[inline] +#[cfg(not(PyPy))] +/// Retrieve the year component of a `PyDateTime_Date` or `PyDateTime_DateTime`. +/// Returns a signed integer greater than 0. +pub unsafe fn PyDateTime_GET_YEAR(o: *mut PyObject) -> c_int { + // This should work for Date or DateTime + let d = *(o as *mut PyDateTime_Date); + c_int::from(d.data[0]) << 8 | c_int::from(d.data[1]) +} + +#[inline] +#[cfg(not(PyPy))] +/// Retrieve the month component of a `PyDateTime_Date` or `PyDateTime_DateTime`. +/// Returns a signed integer in the range `[1, 12]`. +pub unsafe fn PyDateTime_GET_MONTH(o: *mut PyObject) -> c_int { + let d = *(o as *mut PyDateTime_Date); + c_int::from(d.data[2]) +} + +#[inline] +#[cfg(not(PyPy))] +/// Retrieve the day component of a `PyDateTime_Date` or `PyDateTime_DateTime`. +/// Returns a signed integer in the interval `[1, 31]`. +pub unsafe fn PyDateTime_GET_DAY(o: *mut PyObject) -> c_int { + let d = *(o as *mut PyDateTime_Date); + c_int::from(d.data[3]) +} + +// Accessor macros for times +#[cfg(not(PyPy))] +macro_rules! _PyDateTime_GET_HOUR { + ($o: expr, $offset:expr) => { + c_int::from((*$o).data[$offset + 0]) + }; +} + +#[cfg(not(PyPy))] +macro_rules! _PyDateTime_GET_MINUTE { + ($o: expr, $offset:expr) => { + c_int::from((*$o).data[$offset + 1]) + }; +} + +#[cfg(not(PyPy))] +macro_rules! _PyDateTime_GET_SECOND { + ($o: expr, $offset:expr) => { + c_int::from((*$o).data[$offset + 2]) + }; +} + +#[cfg(not(PyPy))] +macro_rules! _PyDateTime_GET_MICROSECOND { + ($o: expr, $offset:expr) => { + (c_int::from((*$o).data[$offset + 3]) << 16) + | (c_int::from((*$o).data[$offset + 4]) << 8) + | (c_int::from((*$o).data[$offset + 5])) + }; +} + +#[cfg(not(PyPy))] +macro_rules! _PyDateTime_GET_FOLD { + ($o: expr) => { + (*$o).fold + }; +} + +#[cfg(not(PyPy))] +macro_rules! _PyDateTime_GET_TZINFO { + ($o: expr) => { + (*$o).tzinfo + }; +} + +// Accessor functions for DateTime +#[inline] +#[cfg(not(PyPy))] +/// Retrieve the hour component of a `PyDateTime_DateTime`. +/// Returns a signed integer in the interval `[0, 23]` +pub unsafe fn PyDateTime_DATE_GET_HOUR(o: *mut PyObject) -> c_int { + _PyDateTime_GET_HOUR!((o as *mut PyDateTime_DateTime), _PyDateTime_DATE_DATASIZE) +} + +#[inline] +#[cfg(not(PyPy))] +/// Retrieve the minute component of a `PyDateTime_DateTime`. +/// Returns a signed integer in the interval `[0, 59]` +pub unsafe fn PyDateTime_DATE_GET_MINUTE(o: *mut PyObject) -> c_int { + _PyDateTime_GET_MINUTE!((o as *mut PyDateTime_DateTime), _PyDateTime_DATE_DATASIZE) +} + +#[inline] +#[cfg(not(PyPy))] +/// Retrieve the second component of a `PyDateTime_DateTime`. +/// Returns a signed integer in the interval `[0, 59]` +pub unsafe fn PyDateTime_DATE_GET_SECOND(o: *mut PyObject) -> c_int { + _PyDateTime_GET_SECOND!((o as *mut PyDateTime_DateTime), _PyDateTime_DATE_DATASIZE) +} + +#[inline] +#[cfg(not(PyPy))] +/// Retrieve the microsecond component of a `PyDateTime_DateTime`. +/// Returns a signed integer in the interval `[0, 999999]` +pub unsafe fn PyDateTime_DATE_GET_MICROSECOND(o: *mut PyObject) -> c_int { + _PyDateTime_GET_MICROSECOND!((o as *mut PyDateTime_DateTime), _PyDateTime_DATE_DATASIZE) +} + +#[inline] +#[cfg(not(PyPy))] +/// Retrieve the fold component of a `PyDateTime_DateTime`. +/// Returns a signed integer in the interval `[0, 1]` +pub unsafe fn PyDateTime_DATE_GET_FOLD(o: *mut PyObject) -> c_uchar { + _PyDateTime_GET_FOLD!(o as *mut PyDateTime_DateTime) +} + +#[inline] +#[cfg(not(PyPy))] +/// Retrieve the tzinfo component of a `PyDateTime_DateTime`. +/// Returns a pointer to a `PyObject` that should be either NULL or an instance +/// of a `datetime.tzinfo` subclass. +pub unsafe fn PyDateTime_DATE_GET_TZINFO(o: *mut PyObject) -> *mut PyObject { + _PyDateTime_GET_TZINFO!(o as *mut PyDateTime_DateTime) +} + +// Accessor functions for Time +#[inline] +#[cfg(not(PyPy))] +/// Retrieve the hour component of a `PyDateTime_Time`. +/// Returns a signed integer in the interval `[0, 23]` +pub unsafe fn PyDateTime_TIME_GET_HOUR(o: *mut PyObject) -> c_int { + _PyDateTime_GET_HOUR!((o as *mut PyDateTime_Time), 0) +} + +#[inline] +#[cfg(not(PyPy))] +/// Retrieve the minute component of a `PyDateTime_Time`. +/// Returns a signed integer in the interval `[0, 59]` +pub unsafe fn PyDateTime_TIME_GET_MINUTE(o: *mut PyObject) -> c_int { + _PyDateTime_GET_MINUTE!((o as *mut PyDateTime_Time), 0) +} + +#[inline] +#[cfg(not(PyPy))] +/// Retrieve the second component of a `PyDateTime_DateTime`. +/// Returns a signed integer in the interval `[0, 59]` +pub unsafe fn PyDateTime_TIME_GET_SECOND(o: *mut PyObject) -> c_int { + _PyDateTime_GET_SECOND!((o as *mut PyDateTime_Time), 0) +} + +#[inline] +#[cfg(not(PyPy))] +/// Retrieve the microsecond component of a `PyDateTime_DateTime`. +/// Returns a signed integer in the interval `[0, 999999]` +pub unsafe fn PyDateTime_TIME_GET_MICROSECOND(o: *mut PyObject) -> c_int { + _PyDateTime_GET_MICROSECOND!((o as *mut PyDateTime_Time), 0) +} + +#[cfg(not(PyPy))] +#[inline] +/// Retrieve the fold component of a `PyDateTime_Time`. +/// Returns a signed integer in the interval `[0, 1]` +pub unsafe fn PyDateTime_TIME_GET_FOLD(o: *mut PyObject) -> c_uchar { + _PyDateTime_GET_FOLD!(o as *mut PyDateTime_Time) +} + +#[inline] +#[cfg(not(PyPy))] +/// Retrieve the tzinfo component of a `PyDateTime_Time`. +/// Returns a pointer to a `PyObject` that should be either NULL or an instance +/// of a `datetime.tzinfo` subclass. +pub unsafe fn PyDateTime_TIME_GET_TZINFO(o: *mut PyObject) -> *mut PyObject { + _PyDateTime_GET_TZINFO!(o as *mut PyDateTime_Time) +} + +// Accessor functions +#[cfg(not(PyPy))] +macro_rules! _access_field { + ($obj:expr, $type: ident, $field:ident) => { + (*($obj as *mut $type)).$field + }; +} + +// Accessor functions for PyDateTime_Delta +#[cfg(not(PyPy))] +macro_rules! _access_delta_field { + ($obj:expr, $field:ident) => { + _access_field!($obj, PyDateTime_Delta, $field) + }; +} + +#[inline] +#[cfg(not(PyPy))] +/// Retrieve the days component of a `PyDateTime_Delta`. +/// +/// Returns a signed integer in the interval [-999999999, 999999999]. +/// +/// Note: This retrieves a component from the underlying structure, it is *not* +/// a representation of the total duration of the structure. +pub unsafe fn PyDateTime_DELTA_GET_DAYS(o: *mut PyObject) -> c_int { + _access_delta_field!(o, days) +} + +#[inline] +#[cfg(not(PyPy))] +/// Retrieve the seconds component of a `PyDateTime_Delta`. +/// +/// Returns a signed integer in the interval [0, 86399]. +/// +/// Note: This retrieves a component from the underlying structure, it is *not* +/// a representation of the total duration of the structure. +pub unsafe fn PyDateTime_DELTA_GET_SECONDS(o: *mut PyObject) -> c_int { + _access_delta_field!(o, seconds) +} + +#[inline] +#[cfg(not(PyPy))] +/// Retrieve the seconds component of a `PyDateTime_Delta`. +/// +/// Returns a signed integer in the interval [0, 999999]. +/// +/// Note: This retrieves a component from the underlying structure, it is *not* +/// a representation of the total duration of the structure. +pub unsafe fn PyDateTime_DELTA_GET_MICROSECONDS(o: *mut PyObject) -> c_int { + _access_delta_field!(o, microseconds) +} + +#[cfg(PyPy)] +extern "C" { + // skipped _PyDateTime_HAS_TZINFO (not in PyPy) + #[link_name = "PyPyDateTime_GET_YEAR"] + pub fn PyDateTime_GET_YEAR(o: *mut PyObject) -> c_int; + #[link_name = "PyPyDateTime_GET_MONTH"] + pub fn PyDateTime_GET_MONTH(o: *mut PyObject) -> c_int; + #[link_name = "PyPyDateTime_GET_DAY"] + pub fn PyDateTime_GET_DAY(o: *mut PyObject) -> c_int; + + #[link_name = "PyPyDateTime_DATE_GET_HOUR"] + pub fn PyDateTime_DATE_GET_HOUR(o: *mut PyObject) -> c_int; + #[link_name = "PyPyDateTime_DATE_GET_MINUTE"] + pub fn PyDateTime_DATE_GET_MINUTE(o: *mut PyObject) -> c_int; + #[link_name = "PyPyDateTime_DATE_GET_SECOND"] + pub fn PyDateTime_DATE_GET_SECOND(o: *mut PyObject) -> c_int; + #[link_name = "PyPyDateTime_DATE_GET_MICROSECOND"] + pub fn PyDateTime_DATE_GET_MICROSECOND(o: *mut PyObject) -> c_int; + // skipped PyDateTime_DATE_GET_FOLD (not in PyPy) + // skipped PyDateTime_DATE_GET_TZINFO (not in PyPy) + + #[link_name = "PyPyDateTime_TIME_GET_HOUR"] + pub fn PyDateTime_TIME_GET_HOUR(o: *mut PyObject) -> c_int; + #[link_name = "PyPyDateTime_TIME_GET_MINUTE"] + pub fn PyDateTime_TIME_GET_MINUTE(o: *mut PyObject) -> c_int; + #[link_name = "PyPyDateTime_TIME_GET_SECOND"] + pub fn PyDateTime_TIME_GET_SECOND(o: *mut PyObject) -> c_int; + #[link_name = "PyPyDateTime_TIME_GET_MICROSECOND"] + pub fn PyDateTime_TIME_GET_MICROSECOND(o: *mut PyObject) -> c_int; + // skipped PyDateTime_TIME_GET_FOLD (not in PyPy) + // skipped PyDateTime_TIME_GET_TZINFO (not in PyPy) + + #[link_name = "PyPyDateTime_DELTA_GET_DAYS"] + pub fn PyDateTime_DELTA_GET_DAYS(o: *mut PyObject) -> c_int; + #[link_name = "PyPyDateTime_DELTA_GET_SECONDS"] + pub fn PyDateTime_DELTA_GET_SECONDS(o: *mut PyObject) -> c_int; + #[link_name = "PyPyDateTime_DELTA_GET_MICROSECONDS"] + pub fn PyDateTime_DELTA_GET_MICROSECONDS(o: *mut PyObject) -> c_int; +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct PyDateTime_CAPI { + pub DateType: *mut PyTypeObject, + pub DateTimeType: *mut PyTypeObject, + pub TimeType: *mut PyTypeObject, + pub DeltaType: *mut PyTypeObject, + pub TZInfoType: *mut PyTypeObject, + #[cfg(not(all(PyPy, not(Py_3_8))))] + pub TimeZone_UTC: *mut PyObject, + pub Date_FromDate: unsafe extern "C" fn( + year: c_int, + month: c_int, + day: c_int, + cls: *mut PyTypeObject, + ) -> *mut PyObject, + pub DateTime_FromDateAndTime: unsafe extern "C" fn( + year: c_int, + month: c_int, + day: c_int, + hour: c_int, + minute: c_int, + second: c_int, + microsecond: c_int, + tzinfo: *mut PyObject, + cls: *mut PyTypeObject, + ) -> *mut PyObject, + pub Time_FromTime: unsafe extern "C" fn( + hour: c_int, + minute: c_int, + second: c_int, + microsecond: c_int, + tzinfo: *mut PyObject, + cls: *mut PyTypeObject, + ) -> *mut PyObject, + pub Delta_FromDelta: unsafe extern "C" fn( + days: c_int, + seconds: c_int, + microseconds: c_int, + normalize: c_int, + cls: *mut PyTypeObject, + ) -> *mut PyObject, + #[cfg(not(all(PyPy, not(Py_3_8))))] + pub TimeZone_FromTimeZone: + unsafe extern "C" fn(offset: *mut PyObject, name: *mut PyObject) -> *mut PyObject, + + pub DateTime_FromTimestamp: unsafe extern "C" fn( + cls: *mut PyTypeObject, + args: *mut PyObject, + kwargs: *mut PyObject, + ) -> *mut PyObject, + pub Date_FromTimestamp: + unsafe extern "C" fn(cls: *mut PyTypeObject, args: *mut PyObject) -> *mut PyObject, + #[cfg(not(PyPy))] + pub DateTime_FromDateAndTimeAndFold: unsafe extern "C" fn( + year: c_int, + month: c_int, + day: c_int, + hour: c_int, + minute: c_int, + second: c_int, + microsecond: c_int, + tzinfo: *mut PyObject, + fold: c_int, + cls: *mut PyTypeObject, + ) -> *mut PyObject, + #[cfg(not(PyPy))] + pub Time_FromTimeAndFold: unsafe extern "C" fn( + hour: c_int, + minute: c_int, + second: c_int, + microsecond: c_int, + tzinfo: *mut PyObject, + fold: c_int, + cls: *mut PyTypeObject, + ) -> *mut PyObject, +} + +// Python already shares this object between threads, so it's no more evil for us to do it too! +unsafe impl Sync for PyDateTime_CAPI {} diff --git a/src/ffi/descrobject.rs b/pyo3-ffi/src/descrobject.rs similarity index 95% rename from src/ffi/descrobject.rs rename to pyo3-ffi/src/descrobject.rs index 6b6b0b2daa3..253b40dc4ab 100644 --- a/src/ffi/descrobject.rs +++ b/pyo3-ffi/src/descrobject.rs @@ -1,6 +1,6 @@ -use crate::ffi::methodobject::PyMethodDef; -use crate::ffi::object::{PyObject, PyTypeObject}; -use crate::ffi::structmember::PyMemberDef; +use crate::methodobject::PyMethodDef; +use crate::object::{PyObject, PyTypeObject}; +use crate::structmember::PyMemberDef; use std::os::raw::{c_char, c_int, c_void}; pub type getter = unsafe extern "C" fn(slf: *mut PyObject, closure: *mut c_void) -> *mut PyObject; diff --git a/src/ffi/dictobject.rs b/pyo3-ffi/src/dictobject.rs similarity index 98% rename from src/ffi/dictobject.rs rename to pyo3-ffi/src/dictobject.rs index a0d2b2b3c9b..c4cb719375d 100644 --- a/src/ffi/dictobject.rs +++ b/pyo3-ffi/src/dictobject.rs @@ -1,5 +1,5 @@ -use crate::ffi::object::*; -use crate::ffi::pyport::Py_ssize_t; +use crate::object::*; +use crate::pyport::Py_ssize_t; use std::os::raw::{c_char, c_int}; #[cfg_attr(windows, link(name = "pythonXY"))] diff --git a/src/ffi/enumobject.rs b/pyo3-ffi/src/enumobject.rs similarity index 80% rename from src/ffi/enumobject.rs rename to pyo3-ffi/src/enumobject.rs index 6be7f1f32e0..e3f187d16c5 100644 --- a/src/ffi/enumobject.rs +++ b/pyo3-ffi/src/enumobject.rs @@ -1,4 +1,4 @@ -use crate::ffi::object::PyTypeObject; +use crate::object::PyTypeObject; #[cfg_attr(windows, link(name = "pythonXY"))] extern "C" { diff --git a/src/ffi/eval.rs b/pyo3-ffi/src/eval.rs similarity index 95% rename from src/ffi/eval.rs rename to pyo3-ffi/src/eval.rs index 1ce62c07cc0..612617c0c29 100644 --- a/src/ffi/eval.rs +++ b/pyo3-ffi/src/eval.rs @@ -1,4 +1,4 @@ -use crate::ffi::object::PyObject; +use crate::object::PyObject; use std::os::raw::c_int; extern "C" { diff --git a/src/ffi/fileobject.rs b/pyo3-ffi/src/fileobject.rs similarity index 97% rename from src/ffi/fileobject.rs rename to pyo3-ffi/src/fileobject.rs index a72db98581b..525a7f1021a 100644 --- a/src/ffi/fileobject.rs +++ b/pyo3-ffi/src/fileobject.rs @@ -1,4 +1,4 @@ -use crate::ffi::object::PyObject; +use crate::object::PyObject; use std::os::raw::{c_char, c_int}; pub const PY_STDIOTEXTMODE: &str = "b"; diff --git a/src/ffi/fileutils.rs b/pyo3-ffi/src/fileutils.rs similarity index 87% rename from src/ffi/fileutils.rs rename to pyo3-ffi/src/fileutils.rs index eb1de0257d6..3f053b72b51 100644 --- a/src/ffi/fileutils.rs +++ b/pyo3-ffi/src/fileutils.rs @@ -1,4 +1,4 @@ -use crate::ffi::pyport::Py_ssize_t; +use crate::pyport::Py_ssize_t; use libc::wchar_t; use std::os::raw::c_char; diff --git a/src/ffi/floatobject.rs b/pyo3-ffi/src/floatobject.rs similarity index 98% rename from src/ffi/floatobject.rs rename to pyo3-ffi/src/floatobject.rs index d33feb9aa9b..476f2145fa0 100644 --- a/src/ffi/floatobject.rs +++ b/pyo3-ffi/src/floatobject.rs @@ -1,4 +1,4 @@ -use crate::ffi::object::*; +use crate::object::*; use std::os::raw::{c_double, c_int}; #[cfg(Py_LIMITED_API)] diff --git a/src/ffi/funcobject.rs b/pyo3-ffi/src/funcobject.rs similarity index 96% rename from src/ffi/funcobject.rs rename to pyo3-ffi/src/funcobject.rs index f5ec3d87787..020d2b49470 100644 --- a/src/ffi/funcobject.rs +++ b/pyo3-ffi/src/funcobject.rs @@ -1,6 +1,6 @@ use std::os::raw::c_int; -use crate::ffi::object::{PyObject, PyTypeObject, Py_TYPE}; +use crate::object::{PyObject, PyTypeObject, Py_TYPE}; // skipped PyFunctionObject diff --git a/src/ffi/genobject.rs b/pyo3-ffi/src/genobject.rs similarity index 95% rename from src/ffi/genobject.rs rename to pyo3-ffi/src/genobject.rs index c486e202165..054104de906 100644 --- a/src/ffi/genobject.rs +++ b/pyo3-ffi/src/genobject.rs @@ -1,6 +1,6 @@ -use crate::ffi::object::*; -use crate::ffi::pyport::Py_ssize_t; -use crate::ffi::PyFrameObject; +use crate::object::*; +use crate::pyport::Py_ssize_t; +use crate::PyFrameObject; use std::os::raw::c_int; #[repr(C)] diff --git a/src/ffi/import.rs b/pyo3-ffi/src/import.rs similarity index 98% rename from src/ffi/import.rs rename to pyo3-ffi/src/import.rs index 0edb58ccb83..794e0ee5480 100644 --- a/src/ffi/import.rs +++ b/pyo3-ffi/src/import.rs @@ -1,4 +1,4 @@ -use crate::ffi::object::PyObject; +use crate::object::PyObject; use std::os::raw::{c_char, c_int, c_long}; extern "C" { diff --git a/src/ffi/intrcheck.rs b/pyo3-ffi/src/intrcheck.rs similarity index 100% rename from src/ffi/intrcheck.rs rename to pyo3-ffi/src/intrcheck.rs diff --git a/src/ffi/iterobject.rs b/pyo3-ffi/src/iterobject.rs similarity index 96% rename from src/ffi/iterobject.rs rename to pyo3-ffi/src/iterobject.rs index b41fa0083af..f83e30bb5f5 100644 --- a/src/ffi/iterobject.rs +++ b/pyo3-ffi/src/iterobject.rs @@ -1,4 +1,4 @@ -use crate::ffi::object::*; +use crate::object::*; use std::os::raw::c_int; #[cfg_attr(windows, link(name = "pythonXY"))] diff --git a/pyo3-ffi/src/lib.rs b/pyo3-ffi/src/lib.rs new file mode 100644 index 00000000000..428c71c6694 --- /dev/null +++ b/pyo3-ffi/src/lib.rs @@ -0,0 +1,206 @@ +//! Raw FFI declarations for Python's C API. +//! +//! This module provides low level bindings to the Python interpreter. +//! It is meant for advanced users only - regular PyO3 users shouldn't +//! need to interact with this module at all. +//! +//! The contents of this module are not documented here, as it would entail +//! basically copying the documentation from CPython. Consult the [Python/C API Reference +//! Manual][capi] for up-to-date documentation. +//! +//! # Safety +//! +//! The functions in this module lack individual safety documentation, but +//! generally the following apply: +//! - Pointer arguments have to point to a valid Python object of the correct type, +//! although null pointers are sometimes valid input. +//! - The vast majority can only be used safely while the GIL is held. +//! - Some functions have additional safety requirements, consult the +//! [Python/C API Reference Manual][capi] +//! for more information. +//! +//! [capi]: https://docs.python.org/3/c-api/index.html +#![allow( + missing_docs, + non_camel_case_types, + non_snake_case, + non_upper_case_globals, + clippy::upper_case_acronyms, + clippy::missing_safety_doc +)] + +// Until `extern type` is stabilized, use the recommended approach to +// model opaque types: +// https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs +macro_rules! opaque_struct { + ($name:ident) => { + #[repr(C)] + pub struct $name([u8; 0]); + }; +} + +pub use self::abstract_::*; +pub use self::bltinmodule::*; +pub use self::boolobject::*; +pub use self::bytearrayobject::*; +pub use self::bytesobject::*; +pub use self::ceval::*; +pub use self::code::*; +pub use self::codecs::*; +pub use self::compile::*; +pub use self::complexobject::*; +#[cfg(all(Py_3_8, not(Py_LIMITED_API)))] +pub use self::context::*; +#[cfg(not(Py_LIMITED_API))] +pub use self::datetime::*; +pub use self::descrobject::*; +pub use self::dictobject::*; +pub use self::enumobject::*; +pub use self::eval::*; +pub use self::fileobject::*; +pub use self::fileutils::*; +pub use self::floatobject::*; +#[cfg(not(Py_LIMITED_API))] +pub use self::funcobject::*; +#[cfg(not(Py_LIMITED_API))] +pub use self::genobject::*; +pub use self::import::*; +pub use self::intrcheck::*; +pub use self::iterobject::*; +pub use self::listobject::*; +pub use self::longobject::*; +pub use self::marshal::*; +pub use self::memoryobject::*; +pub use self::methodobject::*; +pub use self::modsupport::*; +pub use self::moduleobject::*; +pub use self::object::*; +pub use self::objimpl::*; +pub use self::osmodule::*; +#[cfg(not(Py_LIMITED_API))] +pub use self::pyarena::*; +pub use self::pycapsule::*; +pub use self::pyerrors::*; +pub use self::pyframe::*; +pub use self::pyhash::*; +pub use self::pylifecycle::*; +pub use self::pymem::*; +pub use self::pyport::*; +pub use self::pystate::*; +pub use self::pystrtod::*; +pub use self::pythonrun::*; +pub use self::rangeobject::*; +pub use self::setobject::*; +pub use self::sliceobject::*; +pub use self::structseq::*; +pub use self::sysmodule::*; +pub use self::traceback::*; +pub use self::tupleobject::*; +pub use self::typeslots::*; +pub use self::unicodeobject::*; +pub use self::warnings::*; +pub use self::weakrefobject::*; + +mod abstract_; +// skipped asdl.h +// skipped ast.h +mod bltinmodule; +mod boolobject; +mod bytearrayobject; +mod bytesobject; +// skipped cellobject.h +mod ceval; +// skipped classobject.h +mod code; +mod codecs; +mod compile; +mod complexobject; +#[cfg(all(Py_3_8, not(Py_LIMITED_API)))] +mod context; // It's actually 3.7.1, but no cfg for patches. +#[cfg(not(Py_LIMITED_API))] +pub(crate) mod datetime; +mod descrobject; +mod dictobject; +// skipped dynamic_annotations.h +mod enumobject; +// skipped errcode.h +mod eval; +// skipped exports.h +mod fileobject; +mod fileutils; +mod floatobject; +// skipped empty frameobject.h +#[cfg(not(Py_LIMITED_API))] +pub(crate) mod funcobject; +// skipped genericaliasobject.h +#[cfg(not(Py_LIMITED_API))] +mod genobject; +mod import; +// skipped interpreteridobject.h +mod intrcheck; +mod iterobject; +mod listobject; +// skipped longintrepr.h +mod longobject; +pub(crate) mod marshal; +mod memoryobject; +mod methodobject; +mod modsupport; +mod moduleobject; +// skipped namespaceobject.h +mod object; +mod objimpl; +// skipped odictobject.h +// skipped opcode.h +// skipped osdefs.h +mod osmodule; +// skipped parser_interface.h +// skipped patchlevel.h +// skipped picklebufobject.h +// skipped pyctype.h +// skipped py_curses.h +#[cfg(not(Py_LIMITED_API))] +mod pyarena; +mod pycapsule; +// skipped pydecimal.h +// skipped pydtrace.h +mod pyerrors; +// skipped pyexpat.h +// skipped pyfpe.h +mod pyframe; +mod pyhash; +mod pylifecycle; +// skipped pymacconfig.h +// skipped pymacro.h +// skipped pymath.h +mod pymem; +mod pyport; +mod pystate; +mod pythonrun; +// skipped pystrhex.h +// skipped pystrcmp.h +mod pystrtod; +// skipped pythread.h +// skipped pytime.h +mod rangeobject; +mod setobject; +mod sliceobject; +mod structseq; +mod sysmodule; +mod traceback; +// skipped tracemalloc.h +mod tupleobject; +mod typeslots; +mod unicodeobject; +mod warnings; +mod weakrefobject; + +// Additional headers that are not exported by Python.h +pub mod structmember; + +// "Limited API" definitions matching Python's `include/cpython` directory. +#[cfg(not(Py_LIMITED_API))] +mod cpython; + +#[cfg(not(Py_LIMITED_API))] +pub use self::cpython::*; diff --git a/src/ffi/listobject.rs b/pyo3-ffi/src/listobject.rs similarity index 97% rename from src/ffi/listobject.rs rename to pyo3-ffi/src/listobject.rs index 79885bcff3e..c45b1fcbbf9 100644 --- a/src/ffi/listobject.rs +++ b/pyo3-ffi/src/listobject.rs @@ -1,5 +1,5 @@ -use crate::ffi::object::*; -use crate::ffi::pyport::Py_ssize_t; +use crate::object::*; +use crate::pyport::Py_ssize_t; use std::os::raw::c_int; #[cfg_attr(windows, link(name = "pythonXY"))] diff --git a/src/ffi/longobject.rs b/pyo3-ffi/src/longobject.rs similarity index 98% rename from src/ffi/longobject.rs rename to pyo3-ffi/src/longobject.rs index 58d93d76b6a..33f336af0d1 100644 --- a/src/ffi/longobject.rs +++ b/pyo3-ffi/src/longobject.rs @@ -1,5 +1,5 @@ -use crate::ffi::object::*; -use crate::ffi::pyport::Py_ssize_t; +use crate::object::*; +use crate::pyport::Py_ssize_t; use libc::size_t; #[cfg(not(Py_LIMITED_API))] use std::os::raw::c_uchar; diff --git a/src/ffi/marshal.rs b/pyo3-ffi/src/marshal.rs similarity index 100% rename from src/ffi/marshal.rs rename to pyo3-ffi/src/marshal.rs diff --git a/src/ffi/memoryobject.rs b/pyo3-ffi/src/memoryobject.rs similarity index 95% rename from src/ffi/memoryobject.rs rename to pyo3-ffi/src/memoryobject.rs index 8ca27d79130..1bebc881cce 100644 --- a/src/ffi/memoryobject.rs +++ b/pyo3-ffi/src/memoryobject.rs @@ -1,5 +1,5 @@ -use crate::ffi::object::*; -use crate::ffi::pyport::Py_ssize_t; +use crate::object::*; +use crate::pyport::Py_ssize_t; use std::os::raw::{c_char, c_int}; // skipped non-limited _PyManagedBuffer_Type diff --git a/src/ffi/methodobject.rs b/pyo3-ffi/src/methodobject.rs similarity index 95% rename from src/ffi/methodobject.rs rename to pyo3-ffi/src/methodobject.rs index 24dac732440..af027407f2c 100644 --- a/src/ffi/methodobject.rs +++ b/pyo3-ffi/src/methodobject.rs @@ -1,6 +1,6 @@ -use crate::ffi::object::{PyObject, PyTypeObject, Py_TYPE}; +use crate::object::{PyObject, PyTypeObject, Py_TYPE}; #[cfg(Py_3_9)] -use crate::ffi::PyObject_TypeCheck; +use crate::PyObject_TypeCheck; use std::mem; use std::os::raw::{c_char, c_int}; @@ -35,7 +35,7 @@ pub type PyCFunction = pub type _PyCFunctionFast = unsafe extern "C" fn( slf: *mut PyObject, args: *mut *mut PyObject, - nargs: crate::ffi::pyport::Py_ssize_t, + nargs: crate::pyport::Py_ssize_t, kwnames: *mut PyObject, ) -> *mut PyObject; @@ -49,7 +49,7 @@ pub type PyCFunctionWithKeywords = unsafe extern "C" fn( pub type _PyCFunctionFastWithKeywords = unsafe extern "C" fn( slf: *mut PyObject, args: *const *mut PyObject, - nargs: crate::ffi::pyport::Py_ssize_t, + nargs: crate::pyport::Py_ssize_t, kwnames: *mut PyObject, ) -> *mut PyObject; diff --git a/src/ffi/modsupport.rs b/pyo3-ffi/src/modsupport.rs similarity index 97% rename from src/ffi/modsupport.rs rename to pyo3-ffi/src/modsupport.rs index 30cba10e639..fc0815a4105 100644 --- a/src/ffi/modsupport.rs +++ b/pyo3-ffi/src/modsupport.rs @@ -1,7 +1,7 @@ -use crate::ffi::methodobject::PyMethodDef; -use crate::ffi::moduleobject::PyModuleDef; -use crate::ffi::object::PyObject; -use crate::ffi::pyport::Py_ssize_t; +use crate::methodobject::PyMethodDef; +use crate::moduleobject::PyModuleDef; +use crate::object::PyObject; +use crate::pyport::Py_ssize_t; use std::os::raw::{c_char, c_int, c_long}; extern "C" { diff --git a/src/ffi/moduleobject.rs b/pyo3-ffi/src/moduleobject.rs similarity index 96% rename from src/ffi/moduleobject.rs rename to pyo3-ffi/src/moduleobject.rs index 96d3e64bc7c..94939943ba5 100644 --- a/src/ffi/moduleobject.rs +++ b/pyo3-ffi/src/moduleobject.rs @@ -1,6 +1,6 @@ -use crate::ffi::methodobject::PyMethodDef; -use crate::ffi::object::*; -use crate::ffi::pyport::Py_ssize_t; +use crate::methodobject::PyMethodDef; +use crate::object::*; +use crate::pyport::Py_ssize_t; use std::os::raw::{c_char, c_int, c_void}; #[cfg_attr(windows, link(name = "pythonXY"))] diff --git a/src/ffi/object.rs b/pyo3-ffi/src/object.rs similarity index 99% rename from src/ffi/object.rs rename to pyo3-ffi/src/object.rs index e113d1eea2a..ca9e180fff2 100644 --- a/src/ffi/object.rs +++ b/pyo3-ffi/src/object.rs @@ -1,6 +1,6 @@ // FFI note: this file changed a lot between 3.6 and 3.10. // Some missing definitions may not be marked "skipped". -use crate::ffi::pyport::{Py_hash_t, Py_ssize_t}; +use crate::pyport::{Py_hash_t, Py_ssize_t}; use std::mem; use std::os::raw::{c_char, c_int, c_uint, c_ulong, c_void}; use std::ptr; @@ -9,7 +9,7 @@ use std::ptr; opaque_struct!(PyTypeObject); #[cfg(not(Py_LIMITED_API))] -pub use crate::ffi::cpython::object::PyTypeObject; +pub use crate::cpython::object::PyTypeObject; // _PyObject_HEAD_EXTRA: conditionally defined in PyObject_HEAD_INIT // _PyObject_EXTRA_INIT: conditionally defined in PyObject_HEAD_INIT diff --git a/src/ffi/objimpl.rs b/pyo3-ffi/src/objimpl.rs similarity index 98% rename from src/ffi/objimpl.rs rename to pyo3-ffi/src/objimpl.rs index 8f805e3b1c1..deeaceb1518 100644 --- a/src/ffi/objimpl.rs +++ b/pyo3-ffi/src/objimpl.rs @@ -1,5 +1,5 @@ -use crate::ffi::object::*; -use crate::ffi::pyport::Py_ssize_t; +use crate::object::*; +use crate::pyport::Py_ssize_t; use libc::size_t; use std::os::raw::{c_int, c_void}; diff --git a/src/ffi/osmodule.rs b/pyo3-ffi/src/osmodule.rs similarity index 69% rename from src/ffi/osmodule.rs rename to pyo3-ffi/src/osmodule.rs index f15682bde54..cacec4433e1 100644 --- a/src/ffi/osmodule.rs +++ b/pyo3-ffi/src/osmodule.rs @@ -1,4 +1,4 @@ -use crate::ffi::object::PyObject; +use crate::object::PyObject; extern "C" { pub fn PyOS_FSPath(path: *mut PyObject) -> *mut PyObject; diff --git a/src/ffi/pyarena.rs b/pyo3-ffi/src/pyarena.rs similarity index 100% rename from src/ffi/pyarena.rs rename to pyo3-ffi/src/pyarena.rs diff --git a/src/ffi/pycapsule.rs b/pyo3-ffi/src/pycapsule.rs similarity index 98% rename from src/ffi/pycapsule.rs rename to pyo3-ffi/src/pycapsule.rs index f93cf0988df..0e15d13849f 100644 --- a/src/ffi/pycapsule.rs +++ b/pyo3-ffi/src/pycapsule.rs @@ -1,4 +1,4 @@ -use crate::ffi::object::*; +use crate::object::*; use std::os::raw::{c_char, c_int, c_void}; #[cfg_attr(windows, link(name = "pythonXY"))] diff --git a/src/ffi/pyerrors.rs b/pyo3-ffi/src/pyerrors.rs similarity index 99% rename from src/ffi/pyerrors.rs rename to pyo3-ffi/src/pyerrors.rs index 462d983d07c..94bbbfc5b38 100644 --- a/src/ffi/pyerrors.rs +++ b/pyo3-ffi/src/pyerrors.rs @@ -1,5 +1,5 @@ -use crate::ffi::object::*; -use crate::ffi::pyport::Py_ssize_t; +use crate::object::*; +use crate::pyport::Py_ssize_t; use std::os::raw::{c_char, c_int}; #[repr(C)] @@ -158,9 +158,9 @@ pub unsafe fn PyUnicodeDecodeError_Create( end: Py_ssize_t, _reason: *const c_char, ) -> *mut PyObject { - crate::ffi::PyObject_CallFunction( + crate::PyObject_CallFunction( PyExc_UnicodeDecodeError, - std::ffi::CStr::from_bytes_with_nul(b"sy#nns\0") + std::crate::CStr::from_bytes_with_nul(b"sy#nns\0") .unwrap() .as_ptr(), encoding, diff --git a/src/ffi/pyframe.rs b/pyo3-ffi/src/pyframe.rs similarity index 87% rename from src/ffi/pyframe.rs rename to pyo3-ffi/src/pyframe.rs index e3c72268c62..c58bc1fbc2d 100644 --- a/src/ffi/pyframe.rs +++ b/pyo3-ffi/src/pyframe.rs @@ -1,5 +1,5 @@ #[cfg(not(Py_LIMITED_API))] -use crate::ffi::PyFrameObject; +use crate::PyFrameObject; use std::os::raw::c_int; #[cfg(Py_LIMITED_API)] diff --git a/src/ffi/pyhash.rs b/pyo3-ffi/src/pyhash.rs similarity index 96% rename from src/ffi/pyhash.rs rename to pyo3-ffi/src/pyhash.rs index 703f6245467..bfff7341bcd 100644 --- a/src/ffi/pyhash.rs +++ b/pyo3-ffi/src/pyhash.rs @@ -1,5 +1,5 @@ #[cfg(not(Py_LIMITED_API))] -use crate::ffi::pyport::{Py_hash_t, Py_ssize_t}; +use crate::pyport::{Py_hash_t, Py_ssize_t}; #[cfg(not(Py_LIMITED_API))] use std::os::raw::{c_char, c_void}; diff --git a/src/ffi/pylifecycle.rs b/pyo3-ffi/src/pylifecycle.rs similarity index 97% rename from src/ffi/pylifecycle.rs rename to pyo3-ffi/src/pylifecycle.rs index 9970ceb974a..7f73e3f0e9b 100644 --- a/src/ffi/pylifecycle.rs +++ b/pyo3-ffi/src/pylifecycle.rs @@ -1,4 +1,4 @@ -use crate::ffi::pystate::PyThreadState; +use crate::pystate::PyThreadState; use libc::wchar_t; use std::os::raw::{c_char, c_int}; diff --git a/src/ffi/pymem.rs b/pyo3-ffi/src/pymem.rs similarity index 100% rename from src/ffi/pymem.rs rename to pyo3-ffi/src/pymem.rs diff --git a/src/ffi/pyport.rs b/pyo3-ffi/src/pyport.rs similarity index 100% rename from src/ffi/pyport.rs rename to pyo3-ffi/src/pyport.rs diff --git a/src/ffi/pystate.rs b/pyo3-ffi/src/pystate.rs similarity index 97% rename from src/ffi/pystate.rs rename to pyo3-ffi/src/pystate.rs index 4eb2049f114..8bae6652d07 100644 --- a/src/ffi/pystate.rs +++ b/pyo3-ffi/src/pystate.rs @@ -1,6 +1,6 @@ #[cfg(not(PyPy))] -use crate::ffi::moduleobject::PyModuleDef; -use crate::ffi::object::PyObject; +use crate::moduleobject::PyModuleDef; +use crate::object::PyObject; use std::os::raw::c_int; #[cfg(not(PyPy))] diff --git a/src/ffi/pystrtod.rs b/pyo3-ffi/src/pystrtod.rs similarity index 97% rename from src/ffi/pystrtod.rs rename to pyo3-ffi/src/pystrtod.rs index 4937a88ee54..1f027686bd9 100644 --- a/src/ffi/pystrtod.rs +++ b/pyo3-ffi/src/pystrtod.rs @@ -1,4 +1,4 @@ -use crate::ffi::object::PyObject; +use crate::object::PyObject; use std::os::raw::{c_char, c_double, c_int}; extern "C" { diff --git a/src/ffi/pythonrun.rs b/pyo3-ffi/src/pythonrun.rs similarity index 93% rename from src/ffi/pythonrun.rs rename to pyo3-ffi/src/pythonrun.rs index 66f6703dcbd..5045abc1826 100644 --- a/src/ffi/pythonrun.rs +++ b/pyo3-ffi/src/pythonrun.rs @@ -1,4 +1,4 @@ -use crate::ffi::object::*; +use crate::object::*; #[cfg(all(not(Py_LIMITED_API), not(Py_3_10)))] use libc::FILE; #[cfg(any(Py_LIMITED_API, not(Py_3_10)))] @@ -47,7 +47,7 @@ opaque_struct!(_node); #[inline] pub unsafe fn PyParser_SimpleParseString(s: *const c_char, b: c_int) -> *mut _node { #[allow(deprecated)] - crate::ffi::PyParser_SimpleParseStringFlags(s, b, 0) + crate::PyParser_SimpleParseStringFlags(s, b, 0) } #[cfg(all(not(Py_LIMITED_API), not(Py_3_10)))] @@ -55,7 +55,7 @@ pub unsafe fn PyParser_SimpleParseString(s: *const c_char, b: c_int) -> *mut _no #[inline] pub unsafe fn PyParser_SimpleParseFile(fp: *mut FILE, s: *const c_char, b: c_int) -> *mut _node { #[allow(deprecated)] - crate::ffi::PyParser_SimpleParseFileFlags(fp, s, b, 0) + crate::PyParser_SimpleParseFileFlags(fp, s, b, 0) } extern "C" { diff --git a/src/ffi/rangeobject.rs b/pyo3-ffi/src/rangeobject.rs similarity index 93% rename from src/ffi/rangeobject.rs rename to pyo3-ffi/src/rangeobject.rs index 1f2195bb41e..af2d3d0b45f 100644 --- a/src/ffi/rangeobject.rs +++ b/pyo3-ffi/src/rangeobject.rs @@ -1,4 +1,4 @@ -use crate::ffi::object::*; +use crate::object::*; use std::os::raw::c_int; #[cfg_attr(windows, link(name = "pythonXY"))] diff --git a/src/ffi/setobject.rs b/pyo3-ffi/src/setobject.rs similarity index 96% rename from src/ffi/setobject.rs rename to pyo3-ffi/src/setobject.rs index 7471c5fe8ad..b5e4859274f 100644 --- a/src/ffi/setobject.rs +++ b/pyo3-ffi/src/setobject.rs @@ -1,7 +1,7 @@ -use crate::ffi::object::*; +use crate::object::*; #[cfg(not(Py_LIMITED_API))] -use crate::ffi::pyport::Py_hash_t; -use crate::ffi::pyport::Py_ssize_t; +use crate::pyport::Py_hash_t; +use crate::pyport::Py_ssize_t; use std::os::raw::c_int; pub const PySet_MINSIZE: usize = 8; @@ -120,7 +120,7 @@ pub unsafe fn PyAnySet_Check(ob: *mut PyObject) -> c_int { #[inline] #[cfg(Py_3_10)] pub unsafe fn PySet_CheckExact(op: *mut PyObject) -> c_int { - crate::ffi::Py_IS_TYPE(op, &mut PySet_Type) + crate::Py_IS_TYPE(op, &mut PySet_Type) } extern "C" { diff --git a/src/ffi/sliceobject.rs b/pyo3-ffi/src/sliceobject.rs similarity index 97% rename from src/ffi/sliceobject.rs rename to pyo3-ffi/src/sliceobject.rs index 31488bb443a..036b4c7d6d2 100644 --- a/src/ffi/sliceobject.rs +++ b/pyo3-ffi/src/sliceobject.rs @@ -1,5 +1,5 @@ -use crate::ffi::object::*; -use crate::ffi::pyport::Py_ssize_t; +use crate::object::*; +use crate::pyport::Py_ssize_t; use std::os::raw::c_int; extern "C" { diff --git a/src/ffi/structmember.rs b/pyo3-ffi/src/structmember.rs similarity index 96% rename from src/ffi/structmember.rs rename to pyo3-ffi/src/structmember.rs index fc06e6da532..4c94a206720 100644 --- a/src/ffi/structmember.rs +++ b/pyo3-ffi/src/structmember.rs @@ -1,5 +1,5 @@ -use crate::ffi::object::PyObject; -use crate::ffi::pyport::Py_ssize_t; +use crate::object::PyObject; +use crate::pyport::Py_ssize_t; use std::os::raw::{c_char, c_int}; #[repr(C)] diff --git a/src/ffi/structseq.rs b/pyo3-ffi/src/structseq.rs similarity index 88% rename from src/ffi/structseq.rs rename to pyo3-ffi/src/structseq.rs index d0d45c795ef..8e66a95e0e2 100644 --- a/src/ffi/structseq.rs +++ b/pyo3-ffi/src/structseq.rs @@ -1,6 +1,6 @@ -use crate::ffi::object::{PyObject, PyTypeObject}; +use crate::object::{PyObject, PyTypeObject}; #[cfg(not(PyPy))] -use crate::ffi::pyport::Py_ssize_t; +use crate::pyport::Py_ssize_t; use std::os::raw::{c_char, c_int}; #[repr(C)] @@ -40,18 +40,18 @@ extern "C" { } #[cfg(not(Py_LIMITED_API))] -pub type PyStructSequence = crate::ffi::PyTupleObject; +pub type PyStructSequence = crate::PyTupleObject; #[cfg(not(any(Py_LIMITED_API, PyPy)))] #[inline] pub unsafe fn PyStructSequence_SET_ITEM(op: *mut PyObject, i: Py_ssize_t, v: *mut PyObject) { - crate::ffi::PyTuple_SET_ITEM(op, i, v) + crate::PyTuple_SET_ITEM(op, i, v) } #[cfg(not(any(Py_LIMITED_API, PyPy)))] #[inline] pub unsafe fn PyStructSequence_GET_ITEM(op: *mut PyObject, i: Py_ssize_t) -> *mut PyObject { - crate::ffi::PyTuple_GET_ITEM(op, i) + crate::PyTuple_GET_ITEM(op, i) } extern "C" { diff --git a/src/ffi/sysmodule.rs b/pyo3-ffi/src/sysmodule.rs similarity index 97% rename from src/ffi/sysmodule.rs rename to pyo3-ffi/src/sysmodule.rs index 2498702984b..3c552254244 100644 --- a/src/ffi/sysmodule.rs +++ b/pyo3-ffi/src/sysmodule.rs @@ -1,4 +1,4 @@ -use crate::ffi::object::PyObject; +use crate::object::PyObject; use libc::wchar_t; use std::os::raw::{c_char, c_int}; diff --git a/src/ffi/traceback.rs b/pyo3-ffi/src/traceback.rs similarity index 86% rename from src/ffi/traceback.rs rename to pyo3-ffi/src/traceback.rs index e08f9c353a4..f9398fb69fb 100644 --- a/src/ffi/traceback.rs +++ b/pyo3-ffi/src/traceback.rs @@ -1,9 +1,9 @@ -use crate::ffi::object::*; +use crate::object::*; use std::os::raw::c_int; extern "C" { #[cfg_attr(PyPy, link_name = "PyPyTraceBack_Here")] - pub fn PyTraceBack_Here(arg1: *mut crate::ffi::PyFrameObject) -> c_int; + pub fn PyTraceBack_Here(arg1: *mut crate::PyFrameObject) -> c_int; #[cfg_attr(PyPy, link_name = "PyPyTraceBack_Print")] pub fn PyTraceBack_Print(arg1: *mut PyObject, arg2: *mut PyObject) -> c_int; } diff --git a/src/ffi/tupleobject.rs b/pyo3-ffi/src/tupleobject.rs similarity index 95% rename from src/ffi/tupleobject.rs rename to pyo3-ffi/src/tupleobject.rs index 17198b39ea7..e4f4b9ea455 100644 --- a/src/ffi/tupleobject.rs +++ b/pyo3-ffi/src/tupleobject.rs @@ -1,5 +1,5 @@ -use crate::ffi::object::*; -use crate::ffi::pyport::Py_ssize_t; +use crate::object::*; +use crate::pyport::Py_ssize_t; use std::os::raw::c_int; #[cfg_attr(windows, link(name = "pythonXY"))] diff --git a/src/ffi/typeslots.rs b/pyo3-ffi/src/typeslots.rs similarity index 100% rename from src/ffi/typeslots.rs rename to pyo3-ffi/src/typeslots.rs diff --git a/src/ffi/unicodeobject.rs b/pyo3-ffi/src/unicodeobject.rs similarity index 99% rename from src/ffi/unicodeobject.rs rename to pyo3-ffi/src/unicodeobject.rs index 10c32ca21f2..5dd2b3cbb63 100644 --- a/src/ffi/unicodeobject.rs +++ b/pyo3-ffi/src/unicodeobject.rs @@ -1,5 +1,5 @@ -use crate::ffi::object::*; -use crate::ffi::pyport::Py_ssize_t; +use crate::object::*; +use crate::pyport::Py_ssize_t; use libc::wchar_t; use std::os::raw::{c_char, c_int, c_void}; diff --git a/src/ffi/warnings.rs b/pyo3-ffi/src/warnings.rs similarity index 92% rename from src/ffi/warnings.rs rename to pyo3-ffi/src/warnings.rs index 2e2731cc37b..488a23e7adb 100644 --- a/src/ffi/warnings.rs +++ b/pyo3-ffi/src/warnings.rs @@ -1,5 +1,5 @@ -use crate::ffi::object::PyObject; -use crate::ffi::pyport::Py_ssize_t; +use crate::object::PyObject; +use crate::pyport::Py_ssize_t; use std::os::raw::{c_char, c_int}; extern "C" { diff --git a/src/ffi/weakrefobject.rs b/pyo3-ffi/src/weakrefobject.rs similarity index 98% rename from src/ffi/weakrefobject.rs rename to pyo3-ffi/src/weakrefobject.rs index 19e12da695a..575bc495de0 100644 --- a/src/ffi/weakrefobject.rs +++ b/pyo3-ffi/src/weakrefobject.rs @@ -1,4 +1,4 @@ -use crate::ffi::object::*; +use crate::object::*; use std::os::raw::c_int; opaque_struct!(PyWeakReference); diff --git a/src/ffi/cpython/mod.rs b/src/ffi/cpython/mod.rs index 332b2b225cd..26aebaf4c38 100644 --- a/src/ffi/cpython/mod.rs +++ b/src/ffi/cpython/mod.rs @@ -1,52 +1 @@ -pub(crate) mod abstract_; -// skipped bytearrayobject.h -#[cfg(not(PyPy))] -pub(crate) mod bytesobject; -#[cfg(not(PyPy))] -pub(crate) mod ceval; -pub(crate) mod code; -pub(crate) mod compile; -#[cfg(not(PyPy))] -pub(crate) mod dictobject; -// skipped fileobject.h -// skipped fileutils.h -pub(crate) mod frameobject; -pub(crate) mod import; -#[cfg(all(Py_3_8, not(PyPy)))] -pub(crate) mod initconfig; -// skipped interpreteridobject.h -pub(crate) mod listobject; -pub(crate) mod object; -pub(crate) mod pydebug; -#[cfg(all(Py_3_8, not(PyPy)))] -pub(crate) mod pylifecycle; -pub(crate) mod pymem; -pub(crate) mod pystate; -pub(crate) mod pythonrun; -// skipped sysmodule.h -pub(crate) mod tupleobject; -pub(crate) mod unicodeobject; - -pub use self::abstract_::*; -#[cfg(not(PyPy))] -pub use self::bytesobject::*; -#[cfg(not(PyPy))] -pub use self::ceval::*; -pub use self::code::*; -pub use self::compile::*; -#[cfg(not(PyPy))] -pub use self::dictobject::*; -pub use self::frameobject::*; -pub use self::import::*; -#[cfg(all(Py_3_8, not(PyPy)))] -pub use self::initconfig::*; -pub use self::listobject::*; -pub use self::object::*; -pub use self::pydebug::*; -#[cfg(all(Py_3_8, not(PyPy)))] -pub use self::pylifecycle::*; -pub use self::pymem::*; -pub use self::pystate::*; -pub use self::pythonrun::*; -pub use self::tupleobject::*; -pub use self::unicodeobject::*; +mod unicodeobject; diff --git a/src/ffi/cpython/unicodeobject.rs b/src/ffi/cpython/unicodeobject.rs index 00b832fcaac..79512583fc7 100644 --- a/src/ffi/cpython/unicodeobject.rs +++ b/src/ffi/cpython/unicodeobject.rs @@ -1,492 +1,11 @@ -use crate::ffi::{PyObject, Py_UCS1, Py_UCS2, Py_UCS4, Py_UNICODE, Py_hash_t, Py_ssize_t}; -use libc::wchar_t; -use std::os::raw::{c_char, c_int, c_uint, c_void}; - -// skipped Py_UNICODE_ISSPACE() -// skipped Py_UNICODE_ISLOWER() -// skipped Py_UNICODE_ISUPPER() -// skipped Py_UNICODE_ISTITLE() -// skipped Py_UNICODE_ISLINEBREAK -// skipped Py_UNICODE_TOLOWER -// skipped Py_UNICODE_TOUPPER -// skipped Py_UNICODE_TOTITLE -// skipped Py_UNICODE_ISDECIMAL -// skipped Py_UNICODE_ISDIGIT -// skipped Py_UNICODE_ISNUMERIC -// skipped Py_UNICODE_ISPRINTABLE -// skipped Py_UNICODE_TODECIMAL -// skipped Py_UNICODE_TODIGIT -// skipped Py_UNICODE_TONUMERIC -// skipped Py_UNICODE_ISALPHA -// skipped Py_UNICODE_ISALNUM -// skipped Py_UNICODE_COPY -// skipped Py_UNICODE_FILL -// skipped Py_UNICODE_IS_SURROGATE -// skipped Py_UNICODE_IS_HIGH_SURROGATE -// skipped Py_UNICODE_IS_LOW_SURROGATE -// skipped Py_UNICODE_JOIN_SURROGATES -// skipped Py_UNICODE_HIGH_SURROGATE -// skipped Py_UNICODE_LOW_SURROGATE - -#[repr(C)] -pub struct PyASCIIObject { - pub ob_base: PyObject, - pub length: Py_ssize_t, - pub hash: Py_hash_t, - /// A bit field with various properties. - /// - /// Rust doesn't expose bitfields. So we have accessor functions for - /// retrieving values. - /// - /// unsigned int interned:2; // SSTATE_* constants. - /// unsigned int kind:3; // PyUnicode_*_KIND constants. - /// unsigned int compact:1; - /// unsigned int ascii:1; - /// unsigned int ready:1; - /// unsigned int :24; - pub state: u32, - pub wstr: *mut wchar_t, -} - -/// Interacting with the bitfield is not actually well-defined, so we mark these APIs unsafe. -/// -/// In addition, they are disabled on big-endian architectures to restrict this to most "common" -/// platforms, which are at least tested on CI and appear to be sound. -#[cfg(target_endian = "little")] -impl PyASCIIObject { - #[inline] - pub unsafe fn interned(&self) -> c_uint { - self.state & 3 - } - - #[inline] - pub unsafe fn kind(&self) -> c_uint { - (self.state >> 2) & 7 - } - - #[inline] - pub unsafe fn compact(&self) -> c_uint { - (self.state >> 5) & 1 - } - - #[inline] - pub unsafe fn ascii(&self) -> c_uint { - (self.state >> 6) & 1 - } - - #[inline] - pub unsafe fn ready(&self) -> c_uint { - (self.state >> 7) & 1 - } -} - -#[repr(C)] -pub struct PyCompactUnicodeObject { - pub _base: PyASCIIObject, - pub utf8_length: Py_ssize_t, - pub utf8: *mut c_char, - pub wstr_length: Py_ssize_t, -} - -#[repr(C)] -pub union PyUnicodeObjectData { - any: *mut c_void, - latin1: *mut Py_UCS1, - ucs2: *mut Py_UCS2, - ucs4: *mut Py_UCS4, -} - -#[repr(C)] -pub struct PyUnicodeObject { - pub _base: PyCompactUnicodeObject, - pub data: PyUnicodeObjectData, -} - -extern "C" { - #[cfg(not(PyPy))] - pub fn _PyUnicode_CheckConsistency(op: *mut PyObject, check_content: c_int) -> c_int; -} - -// skipped PyUnicode_GET_SIZE -// skipped PyUnicode_GET_DATA_SIZE -// skipped PyUnicode_AS_UNICODE -// skipped PyUnicode_AS_DATA - -pub const SSTATE_NOT_INTERNED: c_uint = 0; -pub const SSTATE_INTERNED_MORTAL: c_uint = 1; -pub const SSTATE_INTERNED_IMMORTAL: c_uint = 2; - -#[inline] -#[cfg(target_endian = "little")] -pub unsafe fn PyUnicode_IS_ASCII(op: *mut PyObject) -> c_uint { - debug_assert!(crate::ffi::PyUnicode_Check(op) != 0); - debug_assert!(PyUnicode_IS_READY(op) != 0); - - (*(op as *mut PyASCIIObject)).ascii() -} - -#[inline] -#[cfg(target_endian = "little")] -pub unsafe fn PyUnicode_IS_COMPACT(op: *mut PyObject) -> c_uint { - (*(op as *mut PyASCIIObject)).compact() -} - -#[inline] -#[cfg(target_endian = "little")] -pub unsafe fn PyUnicode_IS_COMPACT_ASCII(op: *mut PyObject) -> c_uint { - if (*(op as *mut PyASCIIObject)).ascii() != 0 && PyUnicode_IS_COMPACT(op) != 0 { - 1 - } else { - 0 - } -} - -#[cfg(not(Py_3_12))] -#[cfg_attr(Py_3_10, deprecated(note = "Python 3.10"))] -pub const PyUnicode_WCHAR_KIND: c_uint = 0; - -pub const PyUnicode_1BYTE_KIND: c_uint = 1; -pub const PyUnicode_2BYTE_KIND: c_uint = 2; -pub const PyUnicode_4BYTE_KIND: c_uint = 4; - -#[inline] -#[cfg(target_endian = "little")] -pub unsafe fn PyUnicode_1BYTE_DATA(op: *mut PyObject) -> *mut Py_UCS1 { - PyUnicode_DATA(op) as *mut Py_UCS1 -} - -#[inline] -#[cfg(target_endian = "little")] -pub unsafe fn PyUnicode_2BYTE_DATA(op: *mut PyObject) -> *mut Py_UCS2 { - PyUnicode_DATA(op) as *mut Py_UCS2 -} - -#[inline] -#[cfg(target_endian = "little")] -pub unsafe fn PyUnicode_4BYTE_DATA(op: *mut PyObject) -> *mut Py_UCS4 { - PyUnicode_DATA(op) as *mut Py_UCS4 -} - -#[inline] -#[cfg(target_endian = "little")] -pub unsafe fn PyUnicode_KIND(op: *mut PyObject) -> c_uint { - debug_assert!(crate::ffi::PyUnicode_Check(op) != 0); - debug_assert!(PyUnicode_IS_READY(op) != 0); - - (*(op as *mut PyASCIIObject)).kind() -} - -#[inline] -#[cfg(target_endian = "little")] -pub unsafe fn _PyUnicode_COMPACT_DATA(op: *mut PyObject) -> *mut c_void { - if PyUnicode_IS_ASCII(op) != 0 { - (op as *mut PyASCIIObject).offset(1) as *mut c_void - } else { - (op as *mut PyCompactUnicodeObject).offset(1) as *mut c_void - } -} - -#[inline] -#[cfg(target_endian = "little")] -pub unsafe fn _PyUnicode_NONCOMPACT_DATA(op: *mut PyObject) -> *mut c_void { - debug_assert!(!(*(op as *mut PyUnicodeObject)).data.any.is_null()); - - (*(op as *mut PyUnicodeObject)).data.any -} - -#[inline] -#[cfg(target_endian = "little")] -pub unsafe fn PyUnicode_DATA(op: *mut PyObject) -> *mut c_void { - debug_assert!(crate::ffi::PyUnicode_Check(op) != 0); - - if PyUnicode_IS_COMPACT(op) != 0 { - _PyUnicode_COMPACT_DATA(op) - } else { - _PyUnicode_NONCOMPACT_DATA(op) - } -} - -// skipped PyUnicode_WRITE -// skipped PyUnicode_READ -// skipped PyUnicode_READ_CHAR - -#[inline] -#[cfg(target_endian = "little")] -pub unsafe fn PyUnicode_GET_LENGTH(op: *mut PyObject) -> Py_ssize_t { - debug_assert!(crate::ffi::PyUnicode_Check(op) != 0); - debug_assert!(PyUnicode_IS_READY(op) != 0); - - (*(op as *mut PyASCIIObject)).length -} - -#[inline] -#[cfg(target_endian = "little")] -pub unsafe fn PyUnicode_IS_READY(op: *mut PyObject) -> c_uint { - (*(op as *mut PyASCIIObject)).ready() -} - -#[cfg(not(Py_3_12))] -#[cfg_attr(Py_3_10, deprecated(note = "Python 3.10"))] -#[inline] -#[cfg(target_endian = "little")] -pub unsafe fn PyUnicode_READY(op: *mut PyObject) -> c_int { - debug_assert!(crate::ffi::PyUnicode_Check(op) != 0); - - if PyUnicode_IS_READY(op) != 0 { - 0 - } else { - _PyUnicode_Ready(op) - } -} - -// skipped PyUnicode_MAX_CHAR_VALUE -// skipped _PyUnicode_get_wstr_length -// skipped PyUnicode_WSTR_LENGTH - -extern "C" { - #[cfg_attr(PyPy, link_name = "PyPyUnicode_New")] - pub fn PyUnicode_New(size: Py_ssize_t, maxchar: Py_UCS4) -> *mut PyObject; - #[cfg_attr(PyPy, link_name = "_PyPyUnicode_Ready")] - pub fn _PyUnicode_Ready(unicode: *mut PyObject) -> c_int; - - // skipped _PyUnicode_Copy - - #[cfg(not(PyPy))] - pub fn PyUnicode_CopyCharacters( - to: *mut PyObject, - to_start: Py_ssize_t, - from: *mut PyObject, - from_start: Py_ssize_t, - how_many: Py_ssize_t, - ) -> Py_ssize_t; - - // skipped _PyUnicode_FastCopyCharacters - - #[cfg(not(PyPy))] - pub fn PyUnicode_Fill( - unicode: *mut PyObject, - start: Py_ssize_t, - length: Py_ssize_t, - fill_char: Py_UCS4, - ) -> Py_ssize_t; - - // skipped _PyUnicode_FastFill - - #[cfg(not(Py_3_12))] - #[deprecated] - #[cfg_attr(PyPy, link_name = "PyPyUnicode_FromUnicode")] - pub fn PyUnicode_FromUnicode(u: *const Py_UNICODE, size: Py_ssize_t) -> *mut PyObject; - - #[cfg_attr(PyPy, link_name = "PyPyUnicode_FromKindAndData")] - pub fn PyUnicode_FromKindAndData( - kind: c_int, - buffer: *const c_void, - size: Py_ssize_t, - ) -> *mut PyObject; - - // skipped _PyUnicode_FromASCII - // skipped _PyUnicode_FindMaxChar - - #[cfg(not(Py_3_12))] - #[deprecated] - #[cfg_attr(PyPy, link_name = "PyPyUnicode_AsUnicode")] - pub fn PyUnicode_AsUnicode(unicode: *mut PyObject) -> *mut Py_UNICODE; - - // skipped _PyUnicode_AsUnicode - - #[cfg(not(Py_3_12))] - #[deprecated] - #[cfg_attr(PyPy, link_name = "PyPyUnicode_AsUnicodeAndSize")] - pub fn PyUnicode_AsUnicodeAndSize( - unicode: *mut PyObject, - size: *mut Py_ssize_t, - ) -> *mut Py_UNICODE; - - // skipped PyUnicode_GetMax -} - -// skipped _PyUnicodeWriter -// skipped _PyUnicodeWriter_Init -// skipped _PyUnicodeWriter_Prepare -// skipped _PyUnicodeWriter_PrepareInternal -// skipped _PyUnicodeWriter_PrepareKind -// skipped _PyUnicodeWriter_PrepareKindInternal -// skipped _PyUnicodeWriter_WriteChar -// skipped _PyUnicodeWriter_WriteStr -// skipped _PyUnicodeWriter_WriteSubstring -// skipped _PyUnicodeWriter_WriteASCIIString -// skipped _PyUnicodeWriter_WriteLatin1String -// skipped _PyUnicodeWriter_Finish -// skipped _PyUnicodeWriter_Dealloc -// skipped _PyUnicode_FormatAdvancedWriter - -extern "C" { - // skipped _PyUnicode_AsStringAndSize - - #[cfg_attr(PyPy, link_name = "PyPyUnicode_AsUTF8")] - pub fn PyUnicode_AsUTF8(unicode: *mut PyObject) -> *const c_char; - - // skipped _PyUnicode_AsString - - pub fn PyUnicode_Encode( - s: *const Py_UNICODE, - size: Py_ssize_t, - encoding: *const c_char, - errors: *const c_char, - ) -> *mut PyObject; - - pub fn PyUnicode_EncodeUTF7( - data: *const Py_UNICODE, - length: Py_ssize_t, - base64SetO: c_int, - base64WhiteSpace: c_int, - errors: *const c_char, - ) -> *mut PyObject; - - // skipped _PyUnicode_EncodeUTF7 - // skipped _PyUnicode_AsUTF8String - - #[cfg_attr(PyPy, link_name = "PyPyUnicode_EncodeUTF8")] - pub fn PyUnicode_EncodeUTF8( - data: *const Py_UNICODE, - length: Py_ssize_t, - errors: *const c_char, - ) -> *mut PyObject; - - pub fn PyUnicode_EncodeUTF32( - data: *const Py_UNICODE, - length: Py_ssize_t, - errors: *const c_char, - byteorder: c_int, - ) -> *mut PyObject; - - // skipped _PyUnicode_EncodeUTF32 - - pub fn PyUnicode_EncodeUTF16( - data: *const Py_UNICODE, - length: Py_ssize_t, - errors: *const c_char, - byteorder: c_int, - ) -> *mut PyObject; - - // skipped _PyUnicode_EncodeUTF16 - // skipped _PyUnicode_DecodeUnicodeEscape - - pub fn PyUnicode_EncodeUnicodeEscape( - data: *const Py_UNICODE, - length: Py_ssize_t, - ) -> *mut PyObject; - - pub fn PyUnicode_EncodeRawUnicodeEscape( - data: *const Py_UNICODE, - length: Py_ssize_t, - ) -> *mut PyObject; - - // skipped _PyUnicode_AsLatin1String - - #[cfg_attr(PyPy, link_name = "PyPyUnicode_EncodeLatin1")] - pub fn PyUnicode_EncodeLatin1( - data: *const Py_UNICODE, - length: Py_ssize_t, - errors: *const c_char, - ) -> *mut PyObject; - - // skipped _PyUnicode_AsASCIIString - - #[cfg_attr(PyPy, link_name = "PyPyUnicode_EncodeASCII")] - pub fn PyUnicode_EncodeASCII( - data: *const Py_UNICODE, - length: Py_ssize_t, - errors: *const c_char, - ) -> *mut PyObject; - - pub fn PyUnicode_EncodeCharmap( - data: *const Py_UNICODE, - length: Py_ssize_t, - mapping: *mut PyObject, - errors: *const c_char, - ) -> *mut PyObject; - - // skipped _PyUnicode_EncodeCharmap - - pub fn PyUnicode_TranslateCharmap( - data: *const Py_UNICODE, - length: Py_ssize_t, - table: *mut PyObject, - errors: *const c_char, - ) -> *mut PyObject; - - // skipped PyUnicode_EncodeMBCS - - #[cfg_attr(PyPy, link_name = "PyPyUnicode_EncodeDecimal")] - pub fn PyUnicode_EncodeDecimal( - s: *mut Py_UNICODE, - length: Py_ssize_t, - output: *mut c_char, - errors: *const c_char, - ) -> c_int; - - #[cfg_attr(PyPy, link_name = "PyPyUnicode_TransformDecimalToASCII")] - pub fn PyUnicode_TransformDecimalToASCII( - s: *mut Py_UNICODE, - length: Py_ssize_t, - ) -> *mut PyObject; - - // skipped _PyUnicode_TransformDecimalAndSpaceToASCII -} - -// skipped _PyUnicode_JoinArray -// skipped _PyUnicode_EqualToASCIIId -// skipped _PyUnicode_EqualToASCIIString -// skipped _PyUnicode_XStrip -// skipped _PyUnicode_InsertThousandsGrouping - -// skipped _Py_ascii_whitespace - -// skipped _PyUnicode_IsLowercase -// skipped _PyUnicode_IsUppercase -// skipped _PyUnicode_IsTitlecase -// skipped _PyUnicode_IsXidStart -// skipped _PyUnicode_IsXidContinue -// skipped _PyUnicode_IsWhitespace -// skipped _PyUnicode_IsLinebreak -// skipped _PyUnicode_ToLowercase -// skipped _PyUnicode_ToUppercase -// skipped _PyUnicode_ToTitlecase -// skipped _PyUnicode_ToLowerFull -// skipped _PyUnicode_ToTitleFull -// skipped _PyUnicode_ToUpperFull -// skipped _PyUnicode_ToFoldedFull -// skipped _PyUnicode_IsCaseIgnorable -// skipped _PyUnicode_IsCased -// skipped _PyUnicode_ToDecimalDigit -// skipped _PyUnicode_ToDigit -// skipped _PyUnicode_ToNumeric -// skipped _PyUnicode_IsDecimalDigit -// skipped _PyUnicode_IsDigit -// skipped _PyUnicode_IsNumeric -// skipped _PyUnicode_IsPrintable -// skipped _PyUnicode_IsAlpha -// skipped Py_UNICODE_strlen -// skipped Py_UNICODE_strcpy -// skipped Py_UNICODE_strcat -// skipped Py_UNICODE_strncpy -// skipped Py_UNICODE_strcmp -// skipped Py_UNICODE_strncmp -// skipped Py_UNICODE_strchr -// skipped Py_UNICODE_strrchr -// skipped _PyUnicode_FormatLong -// skipped PyUnicode_AsUnicodeCopy -// skipped _PyUnicode_FromId -// skipped _PyUnicode_EQ -// skipped _PyUnicode_ScanIdentifier - #[cfg(test)] #[cfg(target_endian = "little")] mod tests { - use super::*; + use libc::wchar_t; + use crate::types::PyString; use crate::{AsPyPointer, Python}; + use pyo3_ffi::*; #[test] fn ascii_object_bitfield() { diff --git a/src/ffi/datetime.rs b/src/ffi/datetime.rs index c7d7b787e42..4790f81fa32 100644 --- a/src/ffi/datetime.rs +++ b/src/ffi/datetime.rs @@ -1,438 +1,12 @@ -//! FFI bindings to the functions and structs defined in `datetime.h` -//! -//! This is the unsafe thin wrapper around the [CPython C API](https://docs.python.org/3/c-api/datetime.html), -//! and covers the various date and time related objects in the Python `datetime` -//! standard library module. -//! -//! A note regarding PyPy (cpyext) support: -//! -//! Support for `PyDateTime_CAPI` is limited as of PyPy 7.0.0. -//! `DateTime_FromTimestamp` and `Date_FromTimestamp` are currently not supported. - -use crate::ffi::{PyObject, PyTypeObject}; -use crate::ffi::{PyObject_TypeCheck, Py_TYPE}; -use crate::once_cell::GILOnceCell; -use crate::Python; use std::ops::Deref; -use std::os::raw::{c_char, c_int, c_uchar}; -#[cfg(not(PyPy))] -use { - crate::ffi::{PyCapsule_Import, Py_hash_t}, - std::ffi::CString, -}; - -// Type struct wrappers -const _PyDateTime_DATE_DATASIZE: usize = 4; -const _PyDateTime_TIME_DATASIZE: usize = 6; -const _PyDateTime_DATETIME_DATASIZE: usize = 10; - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -/// Structure representing a `datetime.timedelta`. -pub struct PyDateTime_Delta { - pub ob_base: PyObject, - #[cfg(not(PyPy))] - pub hashcode: Py_hash_t, - pub days: c_int, - pub seconds: c_int, - pub microseconds: c_int, -} - -// skipped non-limited PyDateTime_TZInfo -// skipped non-limited _PyDateTime_BaseTZInfo -// skipped non-limited _PyDateTime_BaseTime - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -/// Structure representing a `datetime.time`. -pub struct PyDateTime_Time { - pub ob_base: PyObject, - #[cfg(not(PyPy))] - pub hashcode: Py_hash_t, - pub hastzinfo: c_char, - #[cfg(not(PyPy))] - pub data: [c_uchar; _PyDateTime_TIME_DATASIZE], - #[cfg(not(PyPy))] - pub fold: c_uchar, - pub tzinfo: *mut PyObject, -} - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -/// Structure representing a `datetime.date` -pub struct PyDateTime_Date { - pub ob_base: PyObject, - #[cfg(not(PyPy))] - pub hashcode: Py_hash_t, - pub hastzinfo: c_char, - pub data: [c_uchar; _PyDateTime_DATE_DATASIZE], -} - -// skipped non-limited _PyDateTime_BaseDateTime - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -/// Structure representing a `datetime.datetime` -pub struct PyDateTime_DateTime { - pub ob_base: PyObject, - #[cfg(not(PyPy))] - pub hashcode: Py_hash_t, - pub hastzinfo: c_char, - #[cfg(not(PyPy))] - pub data: [c_uchar; _PyDateTime_DATETIME_DATASIZE], - #[cfg(not(PyPy))] - pub fold: c_uchar, - pub tzinfo: *mut PyObject, -} - -// skipped non-limited _PyDateTime_HAS_TZINFO - -// Accessor functions for PyDateTime_Date and PyDateTime_DateTime -#[inline] -#[cfg(not(PyPy))] -/// Retrieve the year component of a `PyDateTime_Date` or `PyDateTime_DateTime`. -/// Returns a signed integer greater than 0. -pub unsafe fn PyDateTime_GET_YEAR(o: *mut PyObject) -> c_int { - // This should work for Date or DateTime - let d = *(o as *mut PyDateTime_Date); - c_int::from(d.data[0]) << 8 | c_int::from(d.data[1]) -} - -#[inline] -#[cfg(not(PyPy))] -/// Retrieve the month component of a `PyDateTime_Date` or `PyDateTime_DateTime`. -/// Returns a signed integer in the range `[1, 12]`. -pub unsafe fn PyDateTime_GET_MONTH(o: *mut PyObject) -> c_int { - let d = *(o as *mut PyDateTime_Date); - c_int::from(d.data[2]) -} - -#[inline] -#[cfg(not(PyPy))] -/// Retrieve the day component of a `PyDateTime_Date` or `PyDateTime_DateTime`. -/// Returns a signed integer in the interval `[1, 31]`. -pub unsafe fn PyDateTime_GET_DAY(o: *mut PyObject) -> c_int { - let d = *(o as *mut PyDateTime_Date); - c_int::from(d.data[3]) -} - -// Accessor macros for times -#[cfg(not(PyPy))] -macro_rules! _PyDateTime_GET_HOUR { - ($o: expr, $offset:expr) => { - c_int::from((*$o).data[$offset + 0]) - }; -} - -#[cfg(not(PyPy))] -macro_rules! _PyDateTime_GET_MINUTE { - ($o: expr, $offset:expr) => { - c_int::from((*$o).data[$offset + 1]) - }; -} -#[cfg(not(PyPy))] -macro_rules! _PyDateTime_GET_SECOND { - ($o: expr, $offset:expr) => { - c_int::from((*$o).data[$offset + 2]) - }; -} - -#[cfg(not(PyPy))] -macro_rules! _PyDateTime_GET_MICROSECOND { - ($o: expr, $offset:expr) => { - (c_int::from((*$o).data[$offset + 3]) << 16) - | (c_int::from((*$o).data[$offset + 4]) << 8) - | (c_int::from((*$o).data[$offset + 5])) - }; -} - -#[cfg(not(PyPy))] -macro_rules! _PyDateTime_GET_FOLD { - ($o: expr) => { - (*$o).fold - }; -} - -#[cfg(not(PyPy))] -macro_rules! _PyDateTime_GET_TZINFO { - ($o: expr) => { - (*$o).tzinfo - }; -} - -// Accessor functions for DateTime -#[inline] -#[cfg(not(PyPy))] -/// Retrieve the hour component of a `PyDateTime_DateTime`. -/// Returns a signed integer in the interval `[0, 23]` -pub unsafe fn PyDateTime_DATE_GET_HOUR(o: *mut PyObject) -> c_int { - _PyDateTime_GET_HOUR!((o as *mut PyDateTime_DateTime), _PyDateTime_DATE_DATASIZE) -} - -#[inline] -#[cfg(not(PyPy))] -/// Retrieve the minute component of a `PyDateTime_DateTime`. -/// Returns a signed integer in the interval `[0, 59]` -pub unsafe fn PyDateTime_DATE_GET_MINUTE(o: *mut PyObject) -> c_int { - _PyDateTime_GET_MINUTE!((o as *mut PyDateTime_DateTime), _PyDateTime_DATE_DATASIZE) -} - -#[inline] -#[cfg(not(PyPy))] -/// Retrieve the second component of a `PyDateTime_DateTime`. -/// Returns a signed integer in the interval `[0, 59]` -pub unsafe fn PyDateTime_DATE_GET_SECOND(o: *mut PyObject) -> c_int { - _PyDateTime_GET_SECOND!((o as *mut PyDateTime_DateTime), _PyDateTime_DATE_DATASIZE) -} - -#[inline] -#[cfg(not(PyPy))] -/// Retrieve the microsecond component of a `PyDateTime_DateTime`. -/// Returns a signed integer in the interval `[0, 999999]` -pub unsafe fn PyDateTime_DATE_GET_MICROSECOND(o: *mut PyObject) -> c_int { - _PyDateTime_GET_MICROSECOND!((o as *mut PyDateTime_DateTime), _PyDateTime_DATE_DATASIZE) -} - -#[inline] -#[cfg(not(PyPy))] -/// Retrieve the fold component of a `PyDateTime_DateTime`. -/// Returns a signed integer in the interval `[0, 1]` -pub unsafe fn PyDateTime_DATE_GET_FOLD(o: *mut PyObject) -> c_uchar { - _PyDateTime_GET_FOLD!(o as *mut PyDateTime_DateTime) -} - -#[inline] -#[cfg(not(PyPy))] -/// Retrieve the tzinfo component of a `PyDateTime_DateTime`. -/// Returns a pointer to a `PyObject` that should be either NULL or an instance -/// of a `datetime.tzinfo` subclass. -pub unsafe fn PyDateTime_DATE_GET_TZINFO(o: *mut PyObject) -> *mut PyObject { - _PyDateTime_GET_TZINFO!(o as *mut PyDateTime_DateTime) -} - -// Accessor functions for Time -#[inline] -#[cfg(not(PyPy))] -/// Retrieve the hour component of a `PyDateTime_Time`. -/// Returns a signed integer in the interval `[0, 23]` -pub unsafe fn PyDateTime_TIME_GET_HOUR(o: *mut PyObject) -> c_int { - _PyDateTime_GET_HOUR!((o as *mut PyDateTime_Time), 0) -} - -#[inline] -#[cfg(not(PyPy))] -/// Retrieve the minute component of a `PyDateTime_Time`. -/// Returns a signed integer in the interval `[0, 59]` -pub unsafe fn PyDateTime_TIME_GET_MINUTE(o: *mut PyObject) -> c_int { - _PyDateTime_GET_MINUTE!((o as *mut PyDateTime_Time), 0) -} - -#[inline] -#[cfg(not(PyPy))] -/// Retrieve the second component of a `PyDateTime_DateTime`. -/// Returns a signed integer in the interval `[0, 59]` -pub unsafe fn PyDateTime_TIME_GET_SECOND(o: *mut PyObject) -> c_int { - _PyDateTime_GET_SECOND!((o as *mut PyDateTime_Time), 0) -} - -#[inline] -#[cfg(not(PyPy))] -/// Retrieve the microsecond component of a `PyDateTime_DateTime`. -/// Returns a signed integer in the interval `[0, 999999]` -pub unsafe fn PyDateTime_TIME_GET_MICROSECOND(o: *mut PyObject) -> c_int { - _PyDateTime_GET_MICROSECOND!((o as *mut PyDateTime_Time), 0) -} - -#[cfg(not(PyPy))] -#[inline] -/// Retrieve the fold component of a `PyDateTime_Time`. -/// Returns a signed integer in the interval `[0, 1]` -pub unsafe fn PyDateTime_TIME_GET_FOLD(o: *mut PyObject) -> c_uchar { - _PyDateTime_GET_FOLD!(o as *mut PyDateTime_Time) -} - -#[inline] -#[cfg(not(PyPy))] -/// Retrieve the tzinfo component of a `PyDateTime_Time`. -/// Returns a pointer to a `PyObject` that should be either NULL or an instance -/// of a `datetime.tzinfo` subclass. -pub unsafe fn PyDateTime_TIME_GET_TZINFO(o: *mut PyObject) -> *mut PyObject { - _PyDateTime_GET_TZINFO!(o as *mut PyDateTime_Time) -} - -// Accessor functions -#[cfg(not(PyPy))] -macro_rules! _access_field { - ($obj:expr, $type: ident, $field:ident) => { - (*($obj as *mut $type)).$field - }; -} - -// Accessor functions for PyDateTime_Delta -#[cfg(not(PyPy))] -macro_rules! _access_delta_field { - ($obj:expr, $field:ident) => { - _access_field!($obj, PyDateTime_Delta, $field) - }; -} - -#[inline] -#[cfg(not(PyPy))] -/// Retrieve the days component of a `PyDateTime_Delta`. -/// -/// Returns a signed integer in the interval [-999999999, 999999999]. -/// -/// Note: This retrieves a component from the underlying structure, it is *not* -/// a representation of the total duration of the structure. -pub unsafe fn PyDateTime_DELTA_GET_DAYS(o: *mut PyObject) -> c_int { - _access_delta_field!(o, days) -} - -#[inline] -#[cfg(not(PyPy))] -/// Retrieve the seconds component of a `PyDateTime_Delta`. -/// -/// Returns a signed integer in the interval [0, 86399]. -/// -/// Note: This retrieves a component from the underlying structure, it is *not* -/// a representation of the total duration of the structure. -pub unsafe fn PyDateTime_DELTA_GET_SECONDS(o: *mut PyObject) -> c_int { - _access_delta_field!(o, seconds) -} +use crate::once_cell::GILOnceCell; +use crate::Python; +use libc::c_int; +use pyo3_ffi::*; -#[inline] #[cfg(not(PyPy))] -/// Retrieve the seconds component of a `PyDateTime_Delta`. -/// -/// Returns a signed integer in the interval [0, 999999]. -/// -/// Note: This retrieves a component from the underlying structure, it is *not* -/// a representation of the total duration of the structure. -pub unsafe fn PyDateTime_DELTA_GET_MICROSECONDS(o: *mut PyObject) -> c_int { - _access_delta_field!(o, microseconds) -} - -#[cfg(PyPy)] -extern "C" { - // skipped _PyDateTime_HAS_TZINFO (not in PyPy) - #[link_name = "PyPyDateTime_GET_YEAR"] - pub fn PyDateTime_GET_YEAR(o: *mut PyObject) -> c_int; - #[link_name = "PyPyDateTime_GET_MONTH"] - pub fn PyDateTime_GET_MONTH(o: *mut PyObject) -> c_int; - #[link_name = "PyPyDateTime_GET_DAY"] - pub fn PyDateTime_GET_DAY(o: *mut PyObject) -> c_int; - - #[link_name = "PyPyDateTime_DATE_GET_HOUR"] - pub fn PyDateTime_DATE_GET_HOUR(o: *mut PyObject) -> c_int; - #[link_name = "PyPyDateTime_DATE_GET_MINUTE"] - pub fn PyDateTime_DATE_GET_MINUTE(o: *mut PyObject) -> c_int; - #[link_name = "PyPyDateTime_DATE_GET_SECOND"] - pub fn PyDateTime_DATE_GET_SECOND(o: *mut PyObject) -> c_int; - #[link_name = "PyPyDateTime_DATE_GET_MICROSECOND"] - pub fn PyDateTime_DATE_GET_MICROSECOND(o: *mut PyObject) -> c_int; - // skipped PyDateTime_DATE_GET_FOLD (not in PyPy) - // skipped PyDateTime_DATE_GET_TZINFO (not in PyPy) - - #[link_name = "PyPyDateTime_TIME_GET_HOUR"] - pub fn PyDateTime_TIME_GET_HOUR(o: *mut PyObject) -> c_int; - #[link_name = "PyPyDateTime_TIME_GET_MINUTE"] - pub fn PyDateTime_TIME_GET_MINUTE(o: *mut PyObject) -> c_int; - #[link_name = "PyPyDateTime_TIME_GET_SECOND"] - pub fn PyDateTime_TIME_GET_SECOND(o: *mut PyObject) -> c_int; - #[link_name = "PyPyDateTime_TIME_GET_MICROSECOND"] - pub fn PyDateTime_TIME_GET_MICROSECOND(o: *mut PyObject) -> c_int; - // skipped PyDateTime_TIME_GET_FOLD (not in PyPy) - // skipped PyDateTime_TIME_GET_TZINFO (not in PyPy) - - #[link_name = "PyPyDateTime_DELTA_GET_DAYS"] - pub fn PyDateTime_DELTA_GET_DAYS(o: *mut PyObject) -> c_int; - #[link_name = "PyPyDateTime_DELTA_GET_SECONDS"] - pub fn PyDateTime_DELTA_GET_SECONDS(o: *mut PyObject) -> c_int; - #[link_name = "PyPyDateTime_DELTA_GET_MICROSECONDS"] - pub fn PyDateTime_DELTA_GET_MICROSECONDS(o: *mut PyObject) -> c_int; -} - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct PyDateTime_CAPI { - pub DateType: *mut PyTypeObject, - pub DateTimeType: *mut PyTypeObject, - pub TimeType: *mut PyTypeObject, - pub DeltaType: *mut PyTypeObject, - pub TZInfoType: *mut PyTypeObject, - #[cfg(not(all(PyPy, not(Py_3_8))))] - pub TimeZone_UTC: *mut PyObject, - pub Date_FromDate: unsafe extern "C" fn( - year: c_int, - month: c_int, - day: c_int, - cls: *mut PyTypeObject, - ) -> *mut PyObject, - pub DateTime_FromDateAndTime: unsafe extern "C" fn( - year: c_int, - month: c_int, - day: c_int, - hour: c_int, - minute: c_int, - second: c_int, - microsecond: c_int, - tzinfo: *mut PyObject, - cls: *mut PyTypeObject, - ) -> *mut PyObject, - pub Time_FromTime: unsafe extern "C" fn( - hour: c_int, - minute: c_int, - second: c_int, - microsecond: c_int, - tzinfo: *mut PyObject, - cls: *mut PyTypeObject, - ) -> *mut PyObject, - pub Delta_FromDelta: unsafe extern "C" fn( - days: c_int, - seconds: c_int, - microseconds: c_int, - normalize: c_int, - cls: *mut PyTypeObject, - ) -> *mut PyObject, - #[cfg(not(all(PyPy, not(Py_3_8))))] - pub TimeZone_FromTimeZone: - unsafe extern "C" fn(offset: *mut PyObject, name: *mut PyObject) -> *mut PyObject, - - pub DateTime_FromTimestamp: unsafe extern "C" fn( - cls: *mut PyTypeObject, - args: *mut PyObject, - kwargs: *mut PyObject, - ) -> *mut PyObject, - pub Date_FromTimestamp: - unsafe extern "C" fn(cls: *mut PyTypeObject, args: *mut PyObject) -> *mut PyObject, - #[cfg(not(PyPy))] - pub DateTime_FromDateAndTimeAndFold: unsafe extern "C" fn( - year: c_int, - month: c_int, - day: c_int, - hour: c_int, - minute: c_int, - second: c_int, - microsecond: c_int, - tzinfo: *mut PyObject, - fold: c_int, - cls: *mut PyTypeObject, - ) -> *mut PyObject, - #[cfg(not(PyPy))] - pub Time_FromTimeAndFold: unsafe extern "C" fn( - hour: c_int, - minute: c_int, - second: c_int, - microsecond: c_int, - tzinfo: *mut PyObject, - fold: c_int, - cls: *mut PyTypeObject, - ) -> *mut PyObject, -} - -// Python already shares this object between threads, so it's no more evil for us to do it too! -unsafe impl Sync for PyDateTime_CAPI {} +use {crate::ffi::PyCapsule_Import, std::ffi::CString}; /// Safe wrapper around the Python datetime C-API global. Note that this object differs slightly /// from the equivalent C object: in C, this is implemented as a `static PyDateTime_CAPI *`. Here diff --git a/src/ffi/mod.rs b/src/ffi/mod.rs index 82e59e9920f..2b698585e5f 100644 --- a/src/ffi/mod.rs +++ b/src/ffi/mod.rs @@ -1,25 +1,3 @@ -//! Raw FFI declarations for Python's C API. -//! -//! This module provides low level bindings to the Python interpreter. -//! It is meant for advanced users only - regular PyO3 users shouldn't -//! need to interact with this module at all. -//! -//! The contents of this module are not documented here, as it would entail -//! basically copying the documentation from CPython. Consult the [Python/C API Reference -//! Manual][capi] for up-to-date documentation. -//! -//! # Safety -//! -//! The functions in this module lack individual safety documentation, but -//! generally the following apply: -//! - Pointer arguments have to point to a valid Python object of the correct type, -//! although null pointers are sometimes valid input. -//! - The vast majority can only be used safely while the GIL is held. -//! - Some functions have additional safety requirements, consult the -//! [Python/C API Reference Manual][capi] -//! for more information. -//! -//! [capi]: https://docs.python.org/3/c-api/index.html #![allow( missing_docs, non_camel_case_types, @@ -28,182 +6,16 @@ clippy::upper_case_acronyms, clippy::missing_safety_doc )] - -// Until `extern type` is stabilized, use the recommended approach to -// model opaque types: -// https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs -macro_rules! opaque_struct { - ($name:ident) => { - #[repr(C)] - pub struct $name([u8; 0]); - }; -} - -pub use self::abstract_::*; -pub use self::bltinmodule::*; -pub use self::boolobject::*; -pub use self::bytearrayobject::*; -pub use self::bytesobject::*; -pub use self::ceval::*; -pub use self::code::*; -pub use self::codecs::*; -pub use self::compile::*; -pub use self::complexobject::*; -#[cfg(all(Py_3_8, not(Py_LIMITED_API)))] -pub use self::context::*; -#[cfg(not(Py_LIMITED_API))] -pub use self::datetime::*; -pub use self::descrobject::*; -pub use self::dictobject::*; -pub use self::enumobject::*; -pub use self::eval::*; -pub use self::fileobject::*; -pub use self::fileutils::*; -pub use self::floatobject::*; -#[cfg(not(Py_LIMITED_API))] -pub use self::funcobject::*; -#[cfg(not(Py_LIMITED_API))] -pub use self::genobject::*; -pub use self::import::*; -pub use self::intrcheck::*; -pub use self::iterobject::*; -pub use self::listobject::*; -pub use self::longobject::*; -pub use self::marshal::*; -pub use self::memoryobject::*; -pub use self::methodobject::*; -pub use self::modsupport::*; -pub use self::moduleobject::*; -pub use self::object::*; -pub use self::objimpl::*; -pub use self::osmodule::*; -#[cfg(not(Py_LIMITED_API))] -pub use self::pyarena::*; -pub use self::pycapsule::*; -pub use self::pyerrors::*; -pub use self::pyframe::*; -pub use self::pyhash::*; -pub use self::pylifecycle::*; -pub use self::pymem::*; -pub use self::pyport::*; -pub use self::pystate::*; -pub use self::pystrtod::*; -pub use self::pythonrun::*; -pub use self::rangeobject::*; -pub use self::setobject::*; -pub use self::sliceobject::*; -pub use self::structseq::*; -pub use self::sysmodule::*; -pub use self::traceback::*; -pub use self::tupleobject::*; -pub use self::typeslots::*; -pub use self::unicodeobject::*; -pub use self::warnings::*; -pub use self::weakrefobject::*; - -mod abstract_; -// skipped asdl.h -// skipped ast.h -mod bltinmodule; -mod boolobject; -mod bytearrayobject; -mod bytesobject; -// skipped cellobject.h -mod ceval; -// skipped classobject.h -mod code; -mod codecs; -mod compile; -mod complexobject; -#[cfg(all(Py_3_8, not(Py_LIMITED_API)))] -mod context; // It's actually 3.7.1, but no cfg for patches. #[cfg(not(Py_LIMITED_API))] -pub(crate) mod datetime; -mod descrobject; -mod dictobject; -// skipped dynamic_annotations.h -mod enumobject; -// skipped errcode.h -mod eval; -// skipped exports.h -mod fileobject; -mod fileutils; -mod floatobject; -// skipped empty frameobject.h -#[cfg(not(Py_LIMITED_API))] -pub(crate) mod funcobject; -// skipped genericaliasobject.h -#[cfg(not(Py_LIMITED_API))] -mod genobject; -mod import; -// skipped interpreteridobject.h -mod intrcheck; -mod iterobject; -mod listobject; -// skipped longintrepr.h -mod longobject; -pub(crate) mod marshal; -mod memoryobject; -mod methodobject; -mod modsupport; -mod moduleobject; -// skipped namespaceobject.h -mod object; -mod objimpl; -// skipped odictobject.h -// skipped opcode.h -// skipped osdefs.h -mod osmodule; -// skipped parser_interface.h -// skipped patchlevel.h -// skipped picklebufobject.h -// skipped pyctype.h -// skipped py_curses.h +mod cpython; #[cfg(not(Py_LIMITED_API))] -mod pyarena; -mod pycapsule; -// skipped pydecimal.h -// skipped pydtrace.h -mod pyerrors; -// skipped pyexpat.h -// skipped pyfpe.h -mod pyframe; -mod pyhash; -mod pylifecycle; -// skipped pymacconfig.h -// skipped pymacro.h -// skipped pymath.h -mod pymem; -mod pyport; -mod pystate; -mod pythonrun; -// skipped pystrhex.h -// skipped pystrcmp.h -mod pystrtod; -// skipped pythread.h -// skipped pytime.h -mod rangeobject; -mod setobject; -mod sliceobject; -mod structseq; -mod sysmodule; -mod traceback; -// skipped tracemalloc.h -mod tupleobject; -mod typeslots; -mod unicodeobject; -mod warnings; -mod weakrefobject; +mod datetime; -// Additional headers that are not exported by Python.h -pub mod structmember; - -// "Limited API" definitions matching Python's `include/cpython` directory. #[cfg(not(Py_LIMITED_API))] -mod cpython; +pub use datetime::*; -#[cfg(not(Py_LIMITED_API))] -pub use self::cpython::*; +// reexport raw bindings exposed in pyo3_ffi +pub use pyo3_ffi::*; /// Helper to enable #\[pymethods\] to see the workaround for __ipow__ on Python 3.7 #[doc(hidden)]