From 83739e60f7a4efa388aa7ee7ae3fea478959db21 Mon Sep 17 00:00:00 2001 From: Nicholas Sim Date: Sun, 27 Dec 2020 14:00:50 +0800 Subject: [PATCH 01/14] ffi module cleanup: context.h to frameobject.h --- CHANGELOG.md | 2 + src/ffi/context.rs | 35 +- src/ffi/cpython/dictobject.rs | 51 ++ src/ffi/{ => cpython}/frameobject.rs | 14 +- src/ffi/cpython/mod.rs | 6 + src/ffi/datetime.rs | 711 ++++++++++++++------------- src/ffi/descrobject.rs | 63 ++- src/ffi/dictobject.rs | 124 +++-- src/ffi/eval.rs | 3 + src/ffi/fileobject.rs | 8 +- src/ffi/floatobject.rs | 24 +- src/ffi/genobject.rs | 2 +- src/ffi/mod.rs | 52 +- src/ffi/object.rs | 5 + src/ffi/pyframe.rs | 12 + src/ffi/pystate.rs | 2 +- 16 files changed, 635 insertions(+), 479 deletions(-) create mode 100644 src/ffi/cpython/dictobject.rs rename src/ffi/{ => cpython}/frameobject.rs (88%) create mode 100644 src/ffi/pyframe.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index ac2b3024909..0d51ddfb17e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Fixed - Stop including `Py_TRACE_REFS` config setting automatically if `Py_DEBUG` is set on Python 3.8 and up. [#1334](https://github.com/PyO3/pyo3/pull/1334) - Remove `#[deny(warnings)]` attribute (and instead refuse warnings only in CI). [#1340](https://github.com/PyO3/pyo3/pull/1340) + +### Changed - Deprecate FFI definitions `PyEval_CallObjectWithKeywords`, `PyEval_CallObject`, `PyEval_CallFunction`, `PyEval_CallMethod` when building for Python 3.9. [#1338](https://github.com/PyO3/pyo3/pull/1338) ## [0.13.0] - 2020-12-22 diff --git a/src/ffi/context.rs b/src/ffi/context.rs index 20778e744ac..cbb58f39216 100644 --- a/src/ffi/context.rs +++ b/src/ffi/context.rs @@ -3,21 +3,11 @@ use std::os::raw::{c_char, c_int}; extern "C" { pub static mut PyContext_Type: PyTypeObject; + // skipped non-limited opaque PyContext pub static mut PyContextVar_Type: PyTypeObject; + // skipped non-limited opaque PyContextVar pub static mut PyContextToken_Type: PyTypeObject; - pub fn PyContext_New() -> *mut PyObject; - pub fn PyContext_Copy(ctx: *mut PyObject) -> *mut PyObject; - pub fn PyContext_CopyCurrent() -> *mut PyObject; - pub fn PyContext_Enter(ctx: *mut PyObject) -> c_int; - pub fn PyContext_Exit(ctx: *mut PyObject) -> c_int; - pub fn PyContextVar_New(name: *const c_char, def: *mut PyObject) -> *mut PyObject; - pub fn PyContextVar_Get( - var: *mut PyObject, - default_value: *mut PyObject, - value: *mut *mut PyObject, - ) -> c_int; - pub fn PyContextVar_Set(var: *mut PyObject, value: *mut PyObject) -> *mut PyObject; - pub fn PyContextVar_Reset(var: *mut PyObject, token: *mut PyObject) -> c_int; +// skipped non-limited opaque PyContextToken } #[inline] @@ -34,3 +24,22 @@ pub unsafe fn PyContextVar_CheckExact(op: *mut PyObject) -> c_int { pub unsafe fn PyContextToken_CheckExact(op: *mut PyObject) -> c_int { (Py_TYPE(op) == &mut PyContextToken_Type) as c_int } + +extern "C" { + pub fn PyContext_New() -> *mut PyObject; + pub fn PyContext_Copy(ctx: *mut PyObject) -> *mut PyObject; + pub fn PyContext_CopyCurrent() -> *mut PyObject; + + pub fn PyContext_Enter(ctx: *mut PyObject) -> c_int; + pub fn PyContext_Exit(ctx: *mut PyObject) -> c_int; + + pub fn PyContextVar_New(name: *const c_char, def: *mut PyObject) -> *mut PyObject; + pub fn PyContextVar_Get( + var: *mut PyObject, + default_value: *mut PyObject, + value: *mut *mut PyObject, + ) -> c_int; + pub fn PyContextVar_Set(var: *mut PyObject, value: *mut PyObject) -> *mut PyObject; + pub fn PyContextVar_Reset(var: *mut PyObject, token: *mut PyObject) -> c_int; +// skipped non-limited _PyContext_NewHamtForTests +} diff --git a/src/ffi/cpython/dictobject.rs b/src/ffi/cpython/dictobject.rs new file mode 100644 index 00000000000..9176541f2c8 --- /dev/null +++ b/src/ffi/cpython/dictobject.rs @@ -0,0 +1,51 @@ +use crate::ffi::object::*; +use crate::ffi::pyport::Py_ssize_t; +use std::os::raw::c_int; + +#[cfg(not(PyPy))] +extern "C" { + // skipped _PyDict_GetItem_KnownHash + // skipped _PyDict_GetItemIdWithError + // skipped _PyDict_GetItemStringWithError + // skipped PyDict_SetDefault + pub fn _PyDict_SetItem_KnownHash( + mp: *mut PyObject, + key: *mut PyObject, + item: *mut PyObject, + hash: crate::ffi::Py_hash_t, + ) -> c_int; + // skipped _PyDict_DelItem_KnownHash + // skipped _PyDict_DelItemIf + // skipped _PyDict_NewKeysForClass + pub fn _PyDict_Next( + mp: *mut PyObject, + pos: *mut Py_ssize_t, + key: *mut *mut PyObject, + value: *mut *mut PyObject, + hash: *mut crate::ffi::Py_hash_t, + ) -> c_int; + // skipped PyDict_GET_SIZE + // skipped _PyDict_Contains_KnownHash + // skipped _PyDict_ContainsId + pub fn _PyDict_NewPresized(minused: Py_ssize_t) -> *mut PyObject; + // skipped _PyDict_MaybeUntrack + // skipped _PyDict_HasOnlyStringKeys + // skipped _PyDict_KeysSize + // skipped _PyDict_SizeOf + // skipped _PyDict_Pop + // skipped _PyDict_Pop_KnownHash + // skipped _PyDict_FromKeys + // skipped _PyDict_HasSplitTable + // skipped _PyDict_MergeEx + // skipped _PyDict_SetItemId + // skipped _PyDict_DelItemId + // skipped _PyDict_DebugMallocStats + // skipped _PyObjectDict_SetItem + // skipped _PyDict_LoadGlobal + // skipped _PyDict_GetItemHint + // skipped _PyDictViewObject + // skipped _PyDictView_New + // skipped _PyDictView_Intersect + // FIXME: PyDict_Contains is defined in dictobject.c + pub fn _PyDict_Contains(mp: *mut PyObject, key: *mut PyObject, hash: Py_ssize_t) -> c_int; +} diff --git a/src/ffi/frameobject.rs b/src/ffi/cpython/frameobject.rs similarity index 88% rename from src/ffi/frameobject.rs rename to src/ffi/cpython/frameobject.rs index 6178ab87af8..fbe06b2e51f 100644 --- a/src/ffi/frameobject.rs +++ b/src/ffi/cpython/frameobject.rs @@ -3,6 +3,9 @@ use crate::ffi::object::*; use crate::ffi::pystate::PyThreadState; use std::os::raw::{c_char, c_int}; +// skipped _framestate +// skipped PyFrameState + #[repr(C)] #[derive(Copy, Clone)] pub struct PyTryBlock { @@ -11,6 +14,7 @@ pub struct PyTryBlock { pub b_level: c_int, } +/// struct _frame as typedef'ed in pyframe.h #[repr(C)] #[derive(Copy, Clone)] pub struct PyFrameObject { @@ -45,6 +49,10 @@ pub struct PyFrameObject { pub f_localsplus: [*mut PyObject; 1], /* locals+stack, dynamically sized */ } +// skipped _PyFrame_IsRunnable +// skipped _PyFrame_IsExecuting +// skipped _PyFrameHasCompleted + #[cfg_attr(windows, link(name = "pythonXY"))] extern "C" { pub static mut PyFrame_Type: PyTypeObject; @@ -63,6 +71,7 @@ extern "C" { globals: *mut PyObject, locals: *mut PyObject, ) -> *mut PyFrameObject; + // skipped _PyFrame_New_NoTrack pub fn PyFrame_BlockSetup(f: *mut PyFrameObject, _type: c_int, handler: c_int, level: c_int); pub fn PyFrame_BlockPop(f: *mut PyFrameObject) -> *mut PyTryBlock; @@ -71,6 +80,9 @@ extern "C" { pub fn PyFrame_FastToLocalsWithError(f: *mut PyFrameObject) -> c_int; pub fn PyFrame_FastToLocals(f: *mut PyFrameObject); + // skipped _PyFrame_DebugMallocStats + // skipped PyFrame_GetBack + + // FIXME: PyFrame_ClearFreeList is defined in frameobject.c pub fn PyFrame_ClearFreeList() -> c_int; - pub fn PyFrame_GetLineNumber(f: *mut PyFrameObject) -> c_int; } diff --git a/src/ffi/cpython/mod.rs b/src/ffi/cpython/mod.rs index 76513bde8f2..7227cacb2e8 100644 --- a/src/ffi/cpython/mod.rs +++ b/src/ffi/cpython/mod.rs @@ -1,11 +1,17 @@ pub mod abstract_; +// skipped bytearrayobject.h #[cfg(not(PyPy))] pub mod bytesobject; pub mod ceval; pub mod code; +pub mod dictobject; +// skipped fileobject.h +pub mod frameobject; pub use self::abstract_::*; #[cfg(not(PyPy))] pub use self::bytesobject::*; pub use self::ceval::*; pub use self::code::*; +pub use self::dictobject::*; +pub use self::frameobject::*; diff --git a/src/ffi/datetime.rs b/src/ffi/datetime.rs index 4b17e3efc81..daa8f0e106e 100644 --- a/src/ffi/datetime.rs +++ b/src/ffi/datetime.rs @@ -23,6 +23,338 @@ use { 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) +} + +#[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 { @@ -84,124 +416,27 @@ pub struct PyDateTime_CAPI { 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, -} - -#[cfg(PyPy)] -extern "C" { - #[link_name = "_PyPyDateTime_Import"] - pub fn PyDateTime_Import() -> &'static PyDateTime_CAPI; - #[link_name = "PyPyDateTime_DATE_GET_HOUR"] - pub fn PyDateTime_DATE_GET_HOUR(o: *mut PyObject) -> c_int; - #[link_name = "PyPyDateTime_DATE_GET_MICROSECOND"] - pub fn PyDateTime_DATE_GET_MICROSECOND(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_DELTA_GET_DAYS"] - pub fn PyDateTime_DELTA_GET_DAYS(o: *mut PyObject) -> c_int; - #[link_name = "PyPyDateTime_DELTA_GET_MICROSECONDS"] - pub fn PyDateTime_DELTA_GET_MICROSECONDS(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_GET_DAY"] - pub fn PyDateTime_GET_DAY(o: *mut PyObject) -> c_int; - #[link_name = "PyPyDateTime_GET_MONTH"] - pub fn PyDateTime_GET_MONTH(o: *mut PyObject) -> c_int; - #[link_name = "PyPyDateTime_GET_YEAR"] - pub fn PyDateTime_GET_YEAR(o: *mut PyObject) -> c_int; - #[link_name = "PyPyDateTime_TIME_GET_HOUR"] - pub fn PyDateTime_TIME_GET_HOUR(o: *mut PyObject) -> c_int; - #[link_name = "PyPyDateTime_TIME_GET_MICROSECOND"] - pub fn PyDateTime_TIME_GET_MICROSECOND(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 = "PyPyDate_FromTimestamp"] - pub fn PyDate_FromTimestamp(args: *mut PyObject) -> *mut PyObject; - #[link_name = "PyPyDateTime_FromTimestamp"] - pub fn PyDateTime_FromTimestamp(args: *mut PyObject) -> *mut PyObject; -} - -// 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.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], -} - -#[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.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, -} - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -/// Structure representing a `datetime.timedelta` -pub struct PyDateTime_Delta { - pub ob_base: PyObject, + 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 hashcode: Py_hash_t, - pub days: c_int, - pub seconds: c_int, - pub microseconds: c_int, + 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! @@ -256,6 +491,8 @@ pub unsafe fn PyDateTime_IMPORT() -> &'static PyDateTime_CAPI { }) } +// skipped non-limited PyDateTime_TimeZone_UTC + /// Type Check macros /// /// These are bindings around the C API typecheck macros, all of them return @@ -321,228 +558,24 @@ pub unsafe fn PyTZInfo_CheckExact(op: *mut PyObject) -> c_int { (Py_TYPE(op) == PyDateTimeAPI.TZInfoType) as c_int } -/// Accessor functions -#[cfg(not(PyPy))] -macro_rules! _access_field { - ($obj:expr, $type: ident, $field:ident) => { - (*($obj as *mut $type)).$field - }; -} - -// 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 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) -} +// skipped non-limited PyDate_FromDate +// skipped non-limited PyDateTime_FromDateAndTime +// skipped non-limited PyDateTime_FromDateAndTimeAndFold +// skipped non-limited PyTime_FromTime +// skipped non-limited PyTime_FromTimeAndFold +// skipped non-limited PyDelta_FromDSU +// skipped non-limited PyTimeZone_FromOffset +// skipped non-limited PyTimeZone_FromOffsetAndName -#[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) +#[cfg(PyPy)] +extern "C" { + #[link_name = "PyPyDate_FromTimestamp"] + pub fn PyDate_FromTimestamp(args: *mut PyObject) -> *mut PyObject; + #[link_name = "PyPyDateTime_FromTimestamp"] + pub fn PyDateTime_FromTimestamp(args: *mut PyObject) -> *mut PyObject; } - -#[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" { + #[link_name = "_PyPyDateTime_Import"] + pub fn PyDateTime_Import() -> &'static PyDateTime_CAPI; } diff --git a/src/ffi/descrobject.rs b/src/ffi/descrobject.rs index 6cdb91a4626..b2619f83c07 100644 --- a/src/ffi/descrobject.rs +++ b/src/ffi/descrobject.rs @@ -20,27 +20,19 @@ pub struct PyGetSetDef { pub closure: *mut c_void, } -pub const PyGetSetDef_INIT: PyGetSetDef = PyGetSetDef { - name: ptr::null_mut(), - get: None, - set: None, - doc: ptr::null_mut(), - closure: ptr::null_mut(), -}; +// skipped non-limited wrapperfunc +// skipped non-limited wrapperfunc_kwds +// skipped non-limited struct wrapperbase +// skipped non-limited PyWrapperFlag_KEYWORDS -#[cfg(any(PyPy, Py_LIMITED_API))] -pub const PyGetSetDef_DICT: PyGetSetDef = PyGetSetDef_INIT; - -// PyPy doesn't export neither PyObject_GenericGetDict/PyObject_GenericSetDict -// Py_LIMITED_API exposes PyObject_GenericSetDict but not Get. -#[cfg(all(not(PyPy), not(Py_LIMITED_API)))] -pub const PyGetSetDef_DICT: PyGetSetDef = PyGetSetDef { - name: "__dict__\0".as_ptr() as *mut c_char, - get: Some(PyObject_GenericGetDict), - set: Some(PyObject_GenericSetDict), - doc: ptr::null_mut(), - closure: ptr::null_mut(), -}; +// skipped non-limited PyDescrObject +// skipped non-limited PyDescr_COMMON +// skipped non-limited PyDescr_TYPE +// skipped non-limited PyDescr_NAME +// skipped non-limited PyMethodDescrObject +// skipped non-limited PyMemberDescrObject +// skipped non-limited PyGetSetDescrObject +// skipped non-limited PyWrapperDescrObject #[cfg_attr(windows, link(name = "pythonXY"))] extern "C" { @@ -56,6 +48,7 @@ extern "C" { pub static mut PyWrapperDescr_Type: PyTypeObject; #[cfg_attr(PyPy, link_name = "PyPyDictProxy_Type")] pub static mut PyDictProxy_Type: PyTypeObject; +// skipped non-limited _PyMethodWrapper_Type } extern "C" { @@ -65,6 +58,8 @@ extern "C" { -> *mut PyObject; pub fn PyDescr_NewMember(arg1: *mut PyTypeObject, arg2: *mut PyMemberDef) -> *mut PyObject; pub fn PyDescr_NewGetSet(arg1: *mut PyTypeObject, arg2: *mut PyGetSetDef) -> *mut PyObject; + // skipped non-limited PyDescr_NewWrapper + // skipped non-limited PyDescr_IsData #[cfg_attr(PyPy, link_name = "PyPyDictProxy_New")] pub fn PyDictProxy_New(arg1: *mut PyObject) -> *mut PyObject; pub fn PyWrapper_New(arg1: *mut PyObject, arg2: *mut PyObject) -> *mut PyObject; @@ -72,3 +67,31 @@ extern "C" { #[cfg_attr(PyPy, link_name = "PyPyProperty_Type")] pub static mut PyProperty_Type: PyTypeObject; } + +/// Helper initial value of [`PyGetSetDef`] for a Python class. +/// +/// Not present in `cpython/Include/descrobject`. +pub const PyGetSetDef_INIT: PyGetSetDef = PyGetSetDef { + name: ptr::null_mut(), + get: None, + set: None, + doc: ptr::null_mut(), + closure: ptr::null_mut(), +}; + +#[cfg(any(PyPy, Py_LIMITED_API))] +pub const PyGetSetDef_DICT: PyGetSetDef = PyGetSetDef_INIT; + +/// Helper initial value of [`PyGetSetDef`] for a dict-like Python class. +/// +/// Not present in `cpython/Include/descrobject.h`. +// PyPy doesn't export neither PyObject_GenericGetDict/PyObject_GenericSetDict +// Py_LIMITED_API exposes PyObject_GenericSetDict but not Get. +#[cfg(all(not(PyPy), not(Py_LIMITED_API)))] +pub const PyGetSetDef_DICT: PyGetSetDef = PyGetSetDef { + name: "__dict__\0".as_ptr() as *mut c_char, + get: Some(PyObject_GenericGetDict), + set: Some(PyObject_GenericSetDict), + doc: ptr::null_mut(), + closure: ptr::null_mut(), +}; diff --git a/src/ffi/dictobject.rs b/src/ffi/dictobject.rs index fa37ed1ebdd..246fa0bc530 100644 --- a/src/ffi/dictobject.rs +++ b/src/ffi/dictobject.rs @@ -6,33 +6,6 @@ use std::os::raw::{c_char, c_int}; extern "C" { #[cfg_attr(PyPy, link_name = "PyPyDict_Type")] pub static mut PyDict_Type: PyTypeObject; - pub static mut PyDictIterKey_Type: PyTypeObject; - pub static mut PyDictIterValue_Type: PyTypeObject; - pub static mut PyDictIterItem_Type: PyTypeObject; - pub static mut PyDictKeys_Type: PyTypeObject; - pub static mut PyDictItems_Type: PyTypeObject; - pub static mut PyDictValues_Type: PyTypeObject; - #[cfg(Py_3_8)] - pub static mut PyDictRevIterKey_Type: PyTypeObject; - #[cfg(Py_3_8)] - pub static mut PyDictRevIterValue_Type: PyTypeObject; - #[cfg(Py_3_8)] - pub static mut PyDictRevIterItem_Type: PyTypeObject; -} - -#[repr(C)] -pub struct PyDictKeysObject { - _unused: [u8; 0], -} - -#[repr(C)] -#[derive(Debug)] -pub struct PyDictObject { - pub ob_base: PyObject, - pub ma_used: Py_ssize_t, - pub ma_version_tag: u64, - pub ma_keys: *mut PyDictKeysObject, - pub ma_values: *mut *mut PyObject, } #[inline] @@ -45,43 +18,14 @@ pub unsafe fn PyDict_CheckExact(op: *mut PyObject) -> c_int { (Py_TYPE(op) == &mut PyDict_Type) as c_int } -#[inline] -pub unsafe fn PyDictKeys_Check(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == &mut PyDictKeys_Type) as c_int -} - -#[inline] -pub unsafe fn PyDictItems_Check(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == &mut PyDictItems_Type) as c_int -} - -#[inline] -pub unsafe fn PyDictValues_Check(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == &mut PyDictValues_Type) as c_int -} - -#[inline] -pub unsafe fn PyDictViewSet_Check(op: *mut PyObject) -> c_int { - (PyDictKeys_Check(op) != 0 || PyDictItems_Check(op) != 0) as c_int -} - extern "C" { #[cfg_attr(PyPy, link_name = "PyPyDict_New")] pub fn PyDict_New() -> *mut PyObject; - #[cfg(not(PyPy))] - pub fn _PyDict_NewPresized(minused: Py_ssize_t) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyDict_GetItem")] pub fn PyDict_GetItem(mp: *mut PyObject, key: *mut PyObject) -> *mut PyObject; pub fn PyDict_GetItemWithError(mp: *mut PyObject, key: *mut PyObject) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyDict_SetItem")] pub fn PyDict_SetItem(mp: *mut PyObject, key: *mut PyObject, item: *mut PyObject) -> c_int; - #[cfg(not(PyPy))] - pub fn _PyDict_SetItem_KnownHash( - mp: *mut PyObject, - key: *mut PyObject, - item: *mut PyObject, - hash: crate::ffi::Py_hash_t, - ) -> c_int; #[cfg_attr(PyPy, link_name = "PyPyDict_DelItem")] pub fn PyDict_DelItem(mp: *mut PyObject, key: *mut PyObject) -> c_int; #[cfg_attr(PyPy, link_name = "PyPyDict_Clear")] @@ -93,14 +37,6 @@ extern "C" { key: *mut *mut PyObject, value: *mut *mut PyObject, ) -> c_int; - #[cfg(not(PyPy))] - pub fn _PyDict_Next( - mp: *mut PyObject, - pos: *mut Py_ssize_t, - key: *mut *mut PyObject, - value: *mut *mut PyObject, - hash: *mut crate::ffi::Py_hash_t, - ) -> c_int; #[cfg_attr(PyPy, link_name = "PyPyDict_Keys")] pub fn PyDict_Keys(mp: *mut PyObject) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyDict_Values")] @@ -113,8 +49,6 @@ extern "C" { pub fn PyDict_Copy(mp: *mut PyObject) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyDict_Contains")] pub fn PyDict_Contains(mp: *mut PyObject, key: *mut PyObject) -> c_int; - #[cfg(not(PyPy))] - pub fn _PyDict_Contains(mp: *mut PyObject, key: *mut PyObject, hash: Py_ssize_t) -> c_int; #[cfg_attr(PyPy, link_name = "PyPyDict_Update")] pub fn PyDict_Update(mp: *mut PyObject, other: *mut PyObject) -> c_int; #[cfg_attr(PyPy, link_name = "PyPyDict_Merge")] @@ -130,6 +64,60 @@ extern "C" { ) -> c_int; #[cfg_attr(PyPy, link_name = "PyPyDict_DelItemString")] pub fn PyDict_DelItemString(dp: *mut PyObject, key: *const c_char) -> c_int; - #[cfg(not(PyPy))] - pub fn _PyObject_GetDictPtr(obj: *mut PyObject) -> *mut *mut PyObject; +// skipped 3.10 / ex-non-limited PyObject_GenericGetDict +} + +#[cfg_attr(windows, link(name = "pythonXY"))] +extern "C" { + pub static mut PyDictKeys_Type: PyTypeObject; + pub static mut PyDictValues_Type: PyTypeObject; + pub static mut PyDictItems_Type: PyTypeObject; +} + +#[inline] +pub unsafe fn PyDictKeys_Check(op: *mut PyObject) -> c_int { + (Py_TYPE(op) == &mut PyDictKeys_Type) as c_int +} + +#[inline] +pub unsafe fn PyDictValues_Check(op: *mut PyObject) -> c_int { + (Py_TYPE(op) == &mut PyDictValues_Type) as c_int +} + +#[inline] +pub unsafe fn PyDictItems_Check(op: *mut PyObject) -> c_int { + (Py_TYPE(op) == &mut PyDictItems_Type) as c_int +} + +#[inline] +pub unsafe fn PyDictViewSet_Check(op: *mut PyObject) -> c_int { + (PyDictKeys_Check(op) != 0 || PyDictItems_Check(op) != 0) as c_int +} + +#[cfg_attr(windows, link(name = "pythonXY"))] +extern "C" { + pub static mut PyDictIterKey_Type: PyTypeObject; + pub static mut PyDictIterValue_Type: PyTypeObject; + pub static mut PyDictIterItem_Type: PyTypeObject; + #[cfg(Py_3_8)] + pub static mut PyDictRevIterKey_Type: PyTypeObject; + #[cfg(Py_3_8)] + pub static mut PyDictRevIterValue_Type: PyTypeObject; + #[cfg(Py_3_8)] + pub static mut PyDictRevIterItem_Type: PyTypeObject; } + +#[repr(C)] +#[derive(Debug)] +// TODO: move to cpython/dictobject.rs +// Not moved because dict.rs uses PyDictObject extensively. +pub struct PyDictObject { + pub ob_base: PyObject, + pub ma_used: Py_ssize_t, + pub ma_version_tag: u64, + pub ma_keys: *mut PyDictKeysObject, + pub ma_values: *mut *mut PyObject, +} + +// TODO: move to cpython/dictobject.rs +opaque_struct!(PyDictKeysObject); diff --git a/src/ffi/eval.rs b/src/ffi/eval.rs index 347f1390ddb..b554cda3c32 100644 --- a/src/ffi/eval.rs +++ b/src/ffi/eval.rs @@ -21,4 +21,7 @@ extern "C" { kwdefs: *mut PyObject, closure: *mut PyObject, ) -> *mut PyObject; + +// skipped non-limited _PyEval_EvalCodeWithName +// skipped non-limited _PyEval_CallTracing } diff --git a/src/ffi/fileobject.rs b/src/ffi/fileobject.rs index 61307496d88..e2984691ffa 100644 --- a/src/ffi/fileobject.rs +++ b/src/ffi/fileobject.rs @@ -14,19 +14,23 @@ extern "C" { arg7: *const c_char, arg8: c_int, ) -> *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyFile_AsFileDescriptor")] - pub fn PyObject_AsFileDescriptor(arg1: *mut PyObject) -> c_int; #[cfg_attr(PyPy, link_name = "PyPyFile_GetLine")] pub fn PyFile_GetLine(arg1: *mut PyObject, arg2: c_int) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyFile_WriteObject")] pub fn PyFile_WriteObject(arg1: *mut PyObject, arg2: *mut PyObject, arg3: c_int) -> c_int; #[cfg_attr(PyPy, link_name = "PyPyFile_WriteString")] pub fn PyFile_WriteString(arg1: *const c_char, arg2: *mut PyObject) -> c_int; + #[cfg_attr(PyPy, link_name = "PyPyFile_AsFileDescriptor")] + pub fn PyObject_AsFileDescriptor(arg1: *mut PyObject) -> c_int; } #[cfg_attr(windows, link(name = "pythonXY"))] extern "C" { pub static mut Py_FileSystemDefaultEncoding: *const c_char; + // Part of limited API since 3.6 pub static mut Py_FileSystemDefaultEncodeErrors: *const c_char; pub static mut Py_HasFileSystemDefaultEncoding: c_int; +// skipped Python 3.7 / ex-non-limited Py_UTF8Mode } + +// skipped _PyIsSelectable_fd diff --git a/src/ffi/floatobject.rs b/src/ffi/floatobject.rs index a5928d28493..d454edcc8e9 100644 --- a/src/ffi/floatobject.rs +++ b/src/ffi/floatobject.rs @@ -1,6 +1,8 @@ use crate::ffi::object::*; use std::os::raw::{c_double, c_int}; +// TODO: mark non-limited +// currently used by types/floatob.rs #[repr(C)] pub struct PyFloatObject { pub ob_base: PyObject, @@ -23,11 +25,8 @@ pub unsafe fn PyFloat_CheckExact(op: *mut PyObject) -> c_int { (Py_TYPE(op) == &mut PyFloat_Type) as c_int } -#[cfg(not(Py_LIMITED_API))] -#[inline] -pub unsafe fn PyFloat_AS_DOUBLE(op: *mut PyObject) -> c_double { - (*(op as *mut PyFloatObject)).ob_fval -} +// skipped Py_RETURN_NAN +// skipped Py_RETURN_INF extern "C" { pub fn PyFloat_GetMax() -> c_double; @@ -40,3 +39,18 @@ extern "C" { #[cfg_attr(PyPy, link_name = "PyPyFloat_AsDouble")] pub fn PyFloat_AsDouble(arg1: *mut PyObject) -> c_double; } + +#[cfg(not(Py_LIMITED_API))] +#[inline] +pub unsafe fn PyFloat_AS_DOUBLE(op: *mut PyObject) -> c_double { + (*(op as *mut PyFloatObject)).ob_fval +} + +// skipped non-limited _PyFloat_Pack2 +// skipped non-limited _PyFloat_Pack4 +// skipped non-limited _PyFloat_Pack8 +// skipped non-limited _PyFloat_Unpack2 +// skipped non-limited _PyFloat_Unpack4 +// skipped non-limited _PyFloat_Unpack8 +// skipped non-limited _PyFloat_DebugMallocStats +// skipped non-limited _PyFloat_FormatAdvancedWriter diff --git a/src/ffi/genobject.rs b/src/ffi/genobject.rs index af7a936bde0..88e9f25fb1c 100644 --- a/src/ffi/genobject.rs +++ b/src/ffi/genobject.rs @@ -1,6 +1,6 @@ -use crate::ffi::frameobject::PyFrameObject; use crate::ffi::object::*; use crate::ffi::pyport::Py_ssize_t; +use crate::ffi::PyFrameObject; use std::os::raw::c_int; #[repr(C)] diff --git a/src/ffi/mod.rs b/src/ffi/mod.rs index 4f9b394b695..a72c25e184b 100644 --- a/src/ffi/mod.rs +++ b/src/ffi/mod.rs @@ -30,7 +30,6 @@ pub use self::enumobject::*; pub use self::eval::*; pub use self::fileobject::*; pub use self::floatobject::*; -pub use self::frameobject::PyFrameObject; pub use self::funcobject::*; pub use self::genobject::*; pub use self::import::*; @@ -53,6 +52,7 @@ pub use self::pyarena::*; pub use self::pycapsule::*; pub use self::pydebug::*; pub use self::pyerrors::*; +pub use self::pyframe::*; pub use self::pyhash::*; pub use self::pylifecycle::*; pub use self::pymem::*; @@ -79,22 +79,37 @@ pub use self::cpython::*; // skipped asdl.h // skipped ast.h mod bltinmodule; -mod boolobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 +mod boolobject; // TODO supports PEP-384 only mod bytearrayobject; mod bytesobject; // skipped cellobject.h -mod ceval; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 +mod ceval; // TODO supports PEP-384 only // skipped classobject.h mod code; -mod codecs; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 +mod codecs; // TODO supports PEP-384 only mod compile; // TODO: incomplete -mod complexobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 - +mod complexobject; // TODO supports PEP-384 only +#[cfg(all(Py_3_8, not(Py_LIMITED_API)))] +mod context; // It's actually 3.7.1, but no cfg for patches. +#[cfg(not(all(Py_3_8, not(Py_LIMITED_API))))] +mod context {} +#[cfg(not(Py_LIMITED_API))] +pub(crate) mod datetime; +mod descrobject; // TODO supports PEP-384 only +mod dictobject; // skipped dynamic_annotations.h +mod enumobject; // skipped errcode.h +mod eval; // TODO supports PEP-384 only + // skipped exports.h +mod fileobject; // TODO: incomplete + // skipped fileutils.h +mod floatobject; // TODO supports PEP-384 only + +// skipped empty frameobject.h // skipped genericaliasobject.h // skipped interpreteridobject.h // skipped longintrepr.h @@ -111,7 +126,8 @@ mod complexobject; // TODO supports PEP-384 only; needs adjustment for Python 3. // skipped pydtrace.h // skipped pyexpat.h // skipped pyfpe.h -// skipped pyframe.h +mod pyframe; // TODO: incomplete + // skipped pymacconfig.h // skipped pymacro.h // skipped pymath.h @@ -142,25 +158,20 @@ mod typeslots; mod longobject; mod unicodeobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 // mod longintrepr; TODO excluded by PEP-384 -mod dictobject; -mod floatobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 mod listobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 mod memoryobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 mod rangeobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 mod tupleobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 // mod odictobject; TODO new in 3.5 -mod enumobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 mod methodobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 mod moduleobject; mod setobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 // mod funcobject; TODO excluded by PEP-384 // mod classobject; TODO excluded by PEP-384 -mod fileobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 mod pycapsule; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 mod sliceobject; mod traceback; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 // mod cellobject; TODO excluded by PEP-384 -mod descrobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 mod genobject; // TODO excluded by PEP-384 mod iterobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 mod structseq; @@ -185,14 +196,6 @@ mod sysmodule; // TODO supports PEP-384 only; needs adjustment for Python 3.3 an mod objectabstract; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 -#[cfg(all(Py_3_8, not(Py_LIMITED_API)))] -mod context; // It's actually 3.7.1, but no cfg for patches. - -#[cfg(not(all(Py_3_8, not(Py_LIMITED_API))))] -mod context {} - -mod eval; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 - // mod pyctype; TODO excluded by PEP-384 mod pystrtod; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 // mod pystrcmp; TODO nothing interesting for Rust? @@ -203,15 +206,6 @@ mod pystrtod; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and // Additional headers that are not exported by Python.h pub mod structmember; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 -#[cfg(not(Py_LIMITED_API))] -pub mod frameobject; -#[cfg(Py_LIMITED_API)] -pub mod frameobject { - opaque_struct!(PyFrameObject); -} - -#[cfg(not(Py_LIMITED_API))] -pub(crate) mod datetime; pub(crate) mod marshal; pub(crate) mod funcobject; diff --git a/src/ffi/object.rs b/src/ffi/object.rs index aa7ec8d79a6..0c2c7792e5e 100644 --- a/src/ffi/object.rs +++ b/src/ffi/object.rs @@ -892,3 +892,8 @@ pub fn PyObject_Check(_arg1: *mut PyObject) -> c_int { pub fn PySuper_Check(_arg1: *mut PyObject) -> c_int { 0 } + +#[cfg(not(PyPy))] +extern "C" { + pub fn _PyObject_GetDictPtr(obj: *mut PyObject) -> *mut *mut PyObject; +} diff --git a/src/ffi/pyframe.rs b/src/ffi/pyframe.rs new file mode 100644 index 00000000000..007cbf759bf --- /dev/null +++ b/src/ffi/pyframe.rs @@ -0,0 +1,12 @@ +#[cfg(not(Py_LIMITED_API))] +use crate::ffi::PyFrameObject; +use std::os::raw::c_int; + +#[cfg(Py_LIMITED_API)] +opaque_struct!(PyFrameObject); + +extern "C" { + pub fn PyFrame_GetLineNumber(f: *mut PyFrameObject) -> c_int; +} +// skipped PyFrame_GetLineNumber +// skipped PyFrame_GetCode diff --git a/src/ffi/pystate.rs b/src/ffi/pystate.rs index 58e98875ab7..73bdf632017 100644 --- a/src/ffi/pystate.rs +++ b/src/ffi/pystate.rs @@ -1,7 +1,7 @@ use crate::ffi::ceval::_PyFrameEvalFunction; -use crate::ffi::frameobject::PyFrameObject; use crate::ffi::moduleobject::PyModuleDef; use crate::ffi::object::PyObject; +use crate::ffi::PyFrameObject; use std::os::raw::{c_int, c_long}; pub const MAX_CO_EXTRA_USERS: c_int = 255; From 46ca4e86e52f3fea64c23c479f43a15d0a452b86 Mon Sep 17 00:00:00 2001 From: Nicholas Sim Date: Sun, 27 Dec 2020 14:10:17 +0800 Subject: [PATCH 02/14] cpython/dictobject: exclude whole file for pypy --- src/ffi/cpython/dictobject.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ffi/cpython/dictobject.rs b/src/ffi/cpython/dictobject.rs index 9176541f2c8..16a228725e8 100644 --- a/src/ffi/cpython/dictobject.rs +++ b/src/ffi/cpython/dictobject.rs @@ -1,8 +1,8 @@ +#![cfg(not(PyPy))] use crate::ffi::object::*; use crate::ffi::pyport::Py_ssize_t; use std::os::raw::c_int; -#[cfg(not(PyPy))] extern "C" { // skipped _PyDict_GetItem_KnownHash // skipped _PyDict_GetItemIdWithError From c4f773e590f26542fa7678fdec710fd3780499cd Mon Sep 17 00:00:00 2001 From: Nicholas Sim Date: Sun, 27 Dec 2020 14:17:44 +0800 Subject: [PATCH 03/14] fix pypy compilation --- src/ffi/cpython/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ffi/cpython/mod.rs b/src/ffi/cpython/mod.rs index 7227cacb2e8..7b651c48e06 100644 --- a/src/ffi/cpython/mod.rs +++ b/src/ffi/cpython/mod.rs @@ -13,5 +13,6 @@ pub use self::abstract_::*; pub use self::bytesobject::*; pub use self::ceval::*; pub use self::code::*; +#[cfg(not(PyPy))] pub use self::dictobject::*; pub use self::frameobject::*; From 969da37b2a6bff76ce6abea3107a0c6c2958cae9 Mon Sep 17 00:00:00 2001 From: Nicholas Sim Date: Mon, 28 Dec 2020 18:02:42 +0800 Subject: [PATCH 04/14] Deprecate PyGetSetDef_DICT --- src/ffi/descrobject.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ffi/descrobject.rs b/src/ffi/descrobject.rs index b2619f83c07..211eb15e9b0 100644 --- a/src/ffi/descrobject.rs +++ b/src/ffi/descrobject.rs @@ -80,6 +80,7 @@ pub const PyGetSetDef_INIT: PyGetSetDef = PyGetSetDef { }; #[cfg(any(PyPy, Py_LIMITED_API))] +#[deprecated(note = "not present in Python headers; to be removed")] pub const PyGetSetDef_DICT: PyGetSetDef = PyGetSetDef_INIT; /// Helper initial value of [`PyGetSetDef`] for a dict-like Python class. @@ -88,6 +89,7 @@ pub const PyGetSetDef_DICT: PyGetSetDef = PyGetSetDef_INIT; // PyPy doesn't export neither PyObject_GenericGetDict/PyObject_GenericSetDict // Py_LIMITED_API exposes PyObject_GenericSetDict but not Get. #[cfg(all(not(PyPy), not(Py_LIMITED_API)))] +#[deprecated(note = "not present in Python headers; to be removed")] pub const PyGetSetDef_DICT: PyGetSetDef = PyGetSetDef { name: "__dict__\0".as_ptr() as *mut c_char, get: Some(PyObject_GenericGetDict), From 643d0af3bf0204dd4d05a710ee028aab35f171a7 Mon Sep 17 00:00:00 2001 From: Nicholas Sim Date: Mon, 28 Dec 2020 18:04:58 +0800 Subject: [PATCH 05/14] remove redundant comment --- src/ffi/fileobject.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ffi/fileobject.rs b/src/ffi/fileobject.rs index e2984691ffa..029304eb6f2 100644 --- a/src/ffi/fileobject.rs +++ b/src/ffi/fileobject.rs @@ -27,7 +27,6 @@ extern "C" { #[cfg_attr(windows, link(name = "pythonXY"))] extern "C" { pub static mut Py_FileSystemDefaultEncoding: *const c_char; - // Part of limited API since 3.6 pub static mut Py_FileSystemDefaultEncodeErrors: *const c_char; pub static mut Py_HasFileSystemDefaultEncoding: c_int; // skipped Python 3.7 / ex-non-limited Py_UTF8Mode From 72ce3081e6ca5defb76cee80b2a5faeee9e3ab41 Mon Sep 17 00:00:00 2001 From: Nicholas Sim Date: Mon, 28 Dec 2020 18:13:33 +0800 Subject: [PATCH 06/14] make PyDictObject, PyFloatObject opaque under limited API --- src/ffi/cpython/dictobject.rs | 13 +++++++++++++ src/ffi/dictobject.rs | 17 +++-------------- src/ffi/floatobject.rs | 7 +++++-- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/ffi/cpython/dictobject.rs b/src/ffi/cpython/dictobject.rs index 16a228725e8..5f1a7a0aee0 100644 --- a/src/ffi/cpython/dictobject.rs +++ b/src/ffi/cpython/dictobject.rs @@ -3,6 +3,19 @@ use crate::ffi::object::*; use crate::ffi::pyport::Py_ssize_t; use std::os::raw::c_int; +opaque_struct!(PyDictKeysObject); + +#[repr(C)] +#[derive(Debug)] +// Not moved because dict.rs uses PyDictObject extensively. +pub struct PyDictObject { + pub ob_base: PyObject, + pub ma_used: Py_ssize_t, + pub ma_version_tag: u64, + pub ma_keys: *mut PyDictKeysObject, + pub ma_values: *mut *mut PyObject, +} + extern "C" { // skipped _PyDict_GetItem_KnownHash // skipped _PyDict_GetItemIdWithError diff --git a/src/ffi/dictobject.rs b/src/ffi/dictobject.rs index 246fa0bc530..843112d3cf9 100644 --- a/src/ffi/dictobject.rs +++ b/src/ffi/dictobject.rs @@ -107,17 +107,6 @@ extern "C" { pub static mut PyDictRevIterItem_Type: PyTypeObject; } -#[repr(C)] -#[derive(Debug)] -// TODO: move to cpython/dictobject.rs -// Not moved because dict.rs uses PyDictObject extensively. -pub struct PyDictObject { - pub ob_base: PyObject, - pub ma_used: Py_ssize_t, - pub ma_version_tag: u64, - pub ma_keys: *mut PyDictKeysObject, - pub ma_values: *mut *mut PyObject, -} - -// TODO: move to cpython/dictobject.rs -opaque_struct!(PyDictKeysObject); +#[cfg(Py_LIMITED_API)] +// TODO: remove (see https://github.com/PyO3/pyo3/pull/1341#issuecomment-751515985) +opaque_struct!(PyDictObject); diff --git a/src/ffi/floatobject.rs b/src/ffi/floatobject.rs index d454edcc8e9..d33feb9aa9b 100644 --- a/src/ffi/floatobject.rs +++ b/src/ffi/floatobject.rs @@ -1,8 +1,11 @@ use crate::ffi::object::*; use std::os::raw::{c_double, c_int}; -// TODO: mark non-limited -// currently used by types/floatob.rs +#[cfg(Py_LIMITED_API)] +// TODO: remove (see https://github.com/PyO3/pyo3/pull/1341#issuecomment-751515985) +opaque_struct!(PyFloatObject); + +#[cfg(not(Py_LIMITED_API))] #[repr(C)] pub struct PyFloatObject { pub ob_base: PyObject, From 3518ac3c3f9b25510f4032b7a529ea8acf1f2952 Mon Sep 17 00:00:00 2001 From: Nicholas Sim Date: Mon, 28 Dec 2020 18:16:56 +0800 Subject: [PATCH 07/14] Update changelog, allow use of deprecated PyGetSetDef_DICT --- CHANGELOG.md | 15 ++++++++++++--- src/pyclass.rs | 1 + 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d51ddfb17e..cc2163db355 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,13 +6,22 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Changed +- Deprecate FFI definition `PyCoro_Check` and `PyAsyncGen_Check` in favor of `PyCoro_CheckExact` and `PyAsyncGen_CheckExact` respectively, as these are the correct name in the Python headers. [#1341](https://github.com/PyO3/pyo3/pull/1341) +- Deprecate FFI definition `PyCoroWrapper_Check` and `PyGetSetDef_DICT` which have never been defined in the Python headers. [#1341](https://github.com/PyO3/pyo3/pull/1341) +- Deprecate FFI definition `PyImport_Cleanup`, which was removed in 3.9 and previously marked "for internal use only". [#1341](https://github.com/PyO3/pyo3/pull/1341) +- Deprecate FFI definition `PyOS_InitInterrupts`, which was removed in 3.10 and previously undocumented. [#1341](https://github.com/PyO3/pyo3/pull/1341) +- Deprecate FFI definition `PyOS_AfterFork`; introduce `PyOS_BeforeFork`, `PyOS_AfterFork_Parent`, `PyOS_AfterFork_Child` when building for Python 3.7. [#1341](https://github.com/PyO3/pyo3/pull/1341) +- Deprecate FFI definitions `PyEval_CallObjectWithKeywords`, `PyEval_CallObject`, `PyEval_CallFunction`, `PyEval_CallMethod` when building for Python 3.9. [#1338](https://github.com/PyO3/pyo3/pull/1338) + +### Removed +- Remove FFI definition `PyImport_cleanup` when building for Python 3.9 or later, to mirror Python headers. [#1341](https://github.com/PyO3/pyo3/pull/1341) +- Remove FFI definition `PyOS_InitInterrupts` when building for Python 3.10 or later, to mirror Python headers. [#1341](https://github.com/PyO3/pyo3/pull/1341) + ### Fixed - Stop including `Py_TRACE_REFS` config setting automatically if `Py_DEBUG` is set on Python 3.8 and up. [#1334](https://github.com/PyO3/pyo3/pull/1334) - Remove `#[deny(warnings)]` attribute (and instead refuse warnings only in CI). [#1340](https://github.com/PyO3/pyo3/pull/1340) -### Changed -- Deprecate FFI definitions `PyEval_CallObjectWithKeywords`, `PyEval_CallObject`, `PyEval_CallFunction`, `PyEval_CallMethod` when building for Python 3.9. [#1338](https://github.com/PyO3/pyo3/pull/1338) - ## [0.13.0] - 2020-12-22 ### Packaging - Drop support for Python 3.5 (as it is now end-of-life). [#1250](https://github.com/PyO3/pyo3/pull/1250) diff --git a/src/pyclass.rs b/src/pyclass.rs index 67f5ba6e660..7b8a7105896 100644 --- a/src/pyclass.rs +++ b/src/pyclass.rs @@ -358,6 +358,7 @@ fn py_class_properties() -> Vec { let mut props: Vec<_> = defs.values().cloned().collect(); if !T::Dict::IS_DUMMY { + #[allow(deprecated)] props.push(ffi::PyGetSetDef_DICT); } if !props.is_empty() { From f68da84095dd4c9b7e4a3035b6c7c1a89eace734 Mon Sep 17 00:00:00 2001 From: Nicholas Sim Date: Mon, 28 Dec 2020 19:55:43 +0800 Subject: [PATCH 08/14] fix pypy non-limited build --- src/ffi/cpython/dictobject.rs | 1 - src/ffi/cpython/mod.rs | 1 + src/ffi/dictobject.rs | 2 +- src/ffi/floatobject.rs | 4 ++-- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ffi/cpython/dictobject.rs b/src/ffi/cpython/dictobject.rs index 5f1a7a0aee0..ef3d0be2e6f 100644 --- a/src/ffi/cpython/dictobject.rs +++ b/src/ffi/cpython/dictobject.rs @@ -1,4 +1,3 @@ -#![cfg(not(PyPy))] use crate::ffi::object::*; use crate::ffi::pyport::Py_ssize_t; use std::os::raw::c_int; diff --git a/src/ffi/cpython/mod.rs b/src/ffi/cpython/mod.rs index 7b651c48e06..2e3ff22ab1b 100644 --- a/src/ffi/cpython/mod.rs +++ b/src/ffi/cpython/mod.rs @@ -4,6 +4,7 @@ pub mod abstract_; pub mod bytesobject; pub mod ceval; pub mod code; +#[cfg(not(PyPy))] pub mod dictobject; // skipped fileobject.h pub mod frameobject; diff --git a/src/ffi/dictobject.rs b/src/ffi/dictobject.rs index 843112d3cf9..cfb579952f5 100644 --- a/src/ffi/dictobject.rs +++ b/src/ffi/dictobject.rs @@ -107,6 +107,6 @@ extern "C" { pub static mut PyDictRevIterItem_Type: PyTypeObject; } -#[cfg(Py_LIMITED_API)] +#[cfg(any(PyPy, Py_LIMITED_API))] // TODO: remove (see https://github.com/PyO3/pyo3/pull/1341#issuecomment-751515985) opaque_struct!(PyDictObject); diff --git a/src/ffi/floatobject.rs b/src/ffi/floatobject.rs index d33feb9aa9b..c62e7f8fd9f 100644 --- a/src/ffi/floatobject.rs +++ b/src/ffi/floatobject.rs @@ -1,11 +1,11 @@ use crate::ffi::object::*; use std::os::raw::{c_double, c_int}; -#[cfg(Py_LIMITED_API)] +#[cfg(any(PyPy, Py_LIMITED_API))] // TODO: remove (see https://github.com/PyO3/pyo3/pull/1341#issuecomment-751515985) opaque_struct!(PyFloatObject); -#[cfg(not(Py_LIMITED_API))] +#[cfg(not(any(PyPy, Py_LIMITED_API)))] #[repr(C)] pub struct PyFloatObject { pub ob_base: PyObject, From f24e48a00c1f5a43c916e06d07c4a794c6acec37 Mon Sep 17 00:00:00 2001 From: Nicholas Sim Date: Mon, 28 Dec 2020 20:11:11 +0800 Subject: [PATCH 09/14] fix pypy3 build --- src/ffi/floatobject.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ffi/floatobject.rs b/src/ffi/floatobject.rs index c62e7f8fd9f..946357a1f51 100644 --- a/src/ffi/floatobject.rs +++ b/src/ffi/floatobject.rs @@ -1,11 +1,13 @@ use crate::ffi::object::*; use std::os::raw::{c_double, c_int}; -#[cfg(any(PyPy, Py_LIMITED_API))] +// #[cfg(all(not(PyPy), Py_LIMITED_API))] +#[cfg(Py_LIMITED_API)] // TODO: remove (see https://github.com/PyO3/pyo3/pull/1341#issuecomment-751515985) opaque_struct!(PyFloatObject); -#[cfg(not(any(PyPy, Py_LIMITED_API)))] +// #[cfg(any(PyPy, not(Py_LIMITED_API)))] +#[cfg(not(Py_LIMITED_API))] #[repr(C)] pub struct PyFloatObject { pub ob_base: PyObject, From 55a602462dda23b0d393e30f70093d0a1dd0898a Mon Sep 17 00:00:00 2001 From: Nicholas Sim Date: Mon, 28 Dec 2020 20:51:08 +0800 Subject: [PATCH 10/14] Apply suggestions from code review Co-authored-by: David Hewitt <1939362+davidhewitt@users.noreply.github.com> --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36f6e8eeb7c..6af92e956ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,8 +9,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Changed - Deprecate FFI definition `PyCoro_Check` and `PyAsyncGen_Check` in favor of `PyCoro_CheckExact` and `PyAsyncGen_CheckExact` respectively, as these are the correct name in the Python headers. [#1341](https://github.com/PyO3/pyo3/pull/1341) - Deprecate FFI definition `PyCoroWrapper_Check` and `PyGetSetDef_DICT` which have never been defined in the Python headers. [#1341](https://github.com/PyO3/pyo3/pull/1341) -- Deprecate FFI definition `PyImport_Cleanup`, which was removed in 3.9 and previously marked "for internal use only". [#1341](https://github.com/PyO3/pyo3/pull/1341) -- Deprecate FFI definition `PyOS_InitInterrupts`, which was removed in 3.10 and previously undocumented. [#1341](https://github.com/PyO3/pyo3/pull/1341) +- Deprecate FFI definition `PyImport_Cleanup` (removed in Python 3.9). [#1341](https://github.com/PyO3/pyo3/pull/1341) +- Deprecate FFI definition `PyOS_InitInterrupts` (removed in Python 3.10). [#1341](https://github.com/PyO3/pyo3/pull/1341) - Deprecate FFI definition `PyOS_AfterFork`; introduce `PyOS_BeforeFork`, `PyOS_AfterFork_Parent`, `PyOS_AfterFork_Child` when building for Python 3.7. [#1341](https://github.com/PyO3/pyo3/pull/1341) - Deprecate FFI definitions `PyEval_CallObjectWithKeywords`, `PyEval_CallObject`, `PyEval_CallFunction`, `PyEval_CallMethod` when building for Python 3.9. [#1338](https://github.com/PyO3/pyo3/pull/1338) From 1fd86132e0f868012c20849021232ff890ba7048 Mon Sep 17 00:00:00 2001 From: Nicholas Sim Date: Mon, 28 Dec 2020 20:54:56 +0800 Subject: [PATCH 11/14] CHANGELOG: update as requested --- CHANGELOG.md | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6af92e956ef..02551cc20a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,16 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] ### Changed -- Deprecate FFI definition `PyCoro_Check` and `PyAsyncGen_Check` in favor of `PyCoro_CheckExact` and `PyAsyncGen_CheckExact` respectively, as these are the correct name in the Python headers. [#1341](https://github.com/PyO3/pyo3/pull/1341) -- Deprecate FFI definition `PyCoroWrapper_Check` and `PyGetSetDef_DICT` which have never been defined in the Python headers. [#1341](https://github.com/PyO3/pyo3/pull/1341) -- Deprecate FFI definition `PyImport_Cleanup` (removed in Python 3.9). [#1341](https://github.com/PyO3/pyo3/pull/1341) -- Deprecate FFI definition `PyOS_InitInterrupts` (removed in Python 3.10). [#1341](https://github.com/PyO3/pyo3/pull/1341) -- Deprecate FFI definition `PyOS_AfterFork`; introduce `PyOS_BeforeFork`, `PyOS_AfterFork_Parent`, `PyOS_AfterFork_Child` when building for Python 3.7. [#1341](https://github.com/PyO3/pyo3/pull/1341) - Deprecate FFI definitions `PyEval_CallObjectWithKeywords`, `PyEval_CallObject`, `PyEval_CallFunction`, `PyEval_CallMethod` when building for Python 3.9. [#1338](https://github.com/PyO3/pyo3/pull/1338) - -### Removed -- Remove FFI definition `PyImport_cleanup` when building for Python 3.9 or later, to mirror Python headers. [#1341](https://github.com/PyO3/pyo3/pull/1341) -- Remove FFI definition `PyOS_InitInterrupts` when building for Python 3.10 or later, to mirror Python headers. [#1341](https://github.com/PyO3/pyo3/pull/1341) +- Deprecate FFI definition `PyGetSetDef_DICT` and `PyGetSetDef_INIT` which have never been in the Python API. [#1341](https://github.com/PyO3/pyo3/pull/1341) ### Fixed - Stop including `Py_TRACE_REFS` config setting automatically if `Py_DEBUG` is set on Python 3.8 and up. [#1334](https://github.com/PyO3/pyo3/pull/1334) From 6c3a241dd458e9242ce344917921f87a92f3c083 Mon Sep 17 00:00:00 2001 From: Nicholas Sim Date: Mon, 28 Dec 2020 20:55:23 +0800 Subject: [PATCH 12/14] ffi cleanup: add missing deprecation --- src/ffi/descrobject.rs | 1 + src/pyclass.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/ffi/descrobject.rs b/src/ffi/descrobject.rs index 211eb15e9b0..0709e332bf6 100644 --- a/src/ffi/descrobject.rs +++ b/src/ffi/descrobject.rs @@ -71,6 +71,7 @@ extern "C" { /// Helper initial value of [`PyGetSetDef`] for a Python class. /// /// Not present in `cpython/Include/descrobject`. +#[deprecated(note = "not present in Python headers; to be removed")] pub const PyGetSetDef_INIT: PyGetSetDef = PyGetSetDef { name: ptr::null_mut(), get: None, diff --git a/src/pyclass.rs b/src/pyclass.rs index 164d1580a90..1a9cd96e38a 100644 --- a/src/pyclass.rs +++ b/src/pyclass.rs @@ -333,6 +333,7 @@ fn py_class_method_defs() -> ( (new, call, defs) } +#[allow(deprecated)] fn py_class_properties() -> Vec { let mut defs = std::collections::HashMap::new(); From aadb58621c707cf407d60579b56e63f46cd0d888 Mon Sep 17 00:00:00 2001 From: Nicholas Sim Date: Mon, 28 Dec 2020 21:18:27 +0800 Subject: [PATCH 13/14] fix errors in PR --- CHANGELOG.md | 6 +++++- src/ffi/cpython/dictobject.rs | 2 +- src/ffi/cpython/frameobject.rs | 2 +- src/ffi/descrobject.rs | 1 + src/pyclass.rs | 4 +++- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02551cc20a7..347ea44440d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] ### Changed - Deprecate FFI definitions `PyEval_CallObjectWithKeywords`, `PyEval_CallObject`, `PyEval_CallFunction`, `PyEval_CallMethod` when building for Python 3.9. [#1338](https://github.com/PyO3/pyo3/pull/1338) -- Deprecate FFI definition `PyGetSetDef_DICT` and `PyGetSetDef_INIT` which have never been in the Python API. [#1341](https://github.com/PyO3/pyo3/pull/1341) +- Deprecate FFI definitions `PyGetSetDef_DICT` and `PyGetSetDef_INIT` which have never been in the Python API. [#1341](https://github.com/PyO3/pyo3/pull/1341) + +### Removed +- Remove FFI definition `PyFrame_ClearFreeList` when building for Python 3.9. [#1341](https://github.com/PyO3/pyo3/pull/1341) +- Remove FFI definition `_PyDict_Contains` when building for Python 3.10. [#1341](https://github.com/PyO3/pyo3/pull/1341) ### Fixed - Stop including `Py_TRACE_REFS` config setting automatically if `Py_DEBUG` is set on Python 3.8 and up. [#1334](https://github.com/PyO3/pyo3/pull/1334) diff --git a/src/ffi/cpython/dictobject.rs b/src/ffi/cpython/dictobject.rs index ef3d0be2e6f..3e58e7b90b8 100644 --- a/src/ffi/cpython/dictobject.rs +++ b/src/ffi/cpython/dictobject.rs @@ -58,6 +58,6 @@ extern "C" { // skipped _PyDictViewObject // skipped _PyDictView_New // skipped _PyDictView_Intersect - // FIXME: PyDict_Contains is defined in dictobject.c + #[cfg(not(Py_3_10))] pub fn _PyDict_Contains(mp: *mut PyObject, key: *mut PyObject, hash: Py_ssize_t) -> c_int; } diff --git a/src/ffi/cpython/frameobject.rs b/src/ffi/cpython/frameobject.rs index fbe06b2e51f..2f7d2b1df90 100644 --- a/src/ffi/cpython/frameobject.rs +++ b/src/ffi/cpython/frameobject.rs @@ -83,6 +83,6 @@ extern "C" { // skipped _PyFrame_DebugMallocStats // skipped PyFrame_GetBack - // FIXME: PyFrame_ClearFreeList is defined in frameobject.c + #[cfg(not(Py_3_9))] pub fn PyFrame_ClearFreeList() -> c_int; } diff --git a/src/ffi/descrobject.rs b/src/ffi/descrobject.rs index 0709e332bf6..177387723c0 100644 --- a/src/ffi/descrobject.rs +++ b/src/ffi/descrobject.rs @@ -82,6 +82,7 @@ pub const PyGetSetDef_INIT: PyGetSetDef = PyGetSetDef { #[cfg(any(PyPy, Py_LIMITED_API))] #[deprecated(note = "not present in Python headers; to be removed")] +#[allow(deprecated)] pub const PyGetSetDef_DICT: PyGetSetDef = PyGetSetDef_INIT; /// Helper initial value of [`PyGetSetDef`] for a dict-like Python class. diff --git a/src/pyclass.rs b/src/pyclass.rs index 1a9cd96e38a..867cfc5da64 100644 --- a/src/pyclass.rs +++ b/src/pyclass.rs @@ -333,7 +333,6 @@ fn py_class_method_defs() -> ( (new, call, defs) } -#[allow(deprecated)] fn py_class_properties() -> Vec { let mut defs = std::collections::HashMap::new(); @@ -341,6 +340,7 @@ fn py_class_properties() -> Vec { match def { PyMethodDefType::Getter(getter) => { if !defs.contains_key(getter.name) { + #[allow(deprecated)] let _ = defs.insert(getter.name.to_owned(), ffi::PyGetSetDef_INIT); } let def = defs.get_mut(getter.name).expect("Failed to call get_mut"); @@ -348,6 +348,7 @@ fn py_class_properties() -> Vec { } PyMethodDefType::Setter(setter) => { if !defs.contains_key(setter.name) { + #[allow(deprecated)] let _ = defs.insert(setter.name.to_owned(), ffi::PyGetSetDef_INIT); } let def = defs.get_mut(setter.name).expect("Failed to call get_mut"); @@ -363,6 +364,7 @@ fn py_class_properties() -> Vec { props.push(ffi::PyGetSetDef_DICT); } if !props.is_empty() { + #[allow(deprecated)] props.push(ffi::PyGetSetDef_INIT); } props From f26a1ea8b17e31419d00062efc7dc99e6734abde Mon Sep 17 00:00:00 2001 From: Nicholas Sim Date: Mon, 28 Dec 2020 21:25:18 +0800 Subject: [PATCH 14/14] remove bad comments --- src/ffi/floatobject.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ffi/floatobject.rs b/src/ffi/floatobject.rs index 946357a1f51..d33feb9aa9b 100644 --- a/src/ffi/floatobject.rs +++ b/src/ffi/floatobject.rs @@ -1,12 +1,10 @@ use crate::ffi::object::*; use std::os::raw::{c_double, c_int}; -// #[cfg(all(not(PyPy), Py_LIMITED_API))] #[cfg(Py_LIMITED_API)] // TODO: remove (see https://github.com/PyO3/pyo3/pull/1341#issuecomment-751515985) opaque_struct!(PyFloatObject); -// #[cfg(any(PyPy, not(Py_LIMITED_API)))] #[cfg(not(Py_LIMITED_API))] #[repr(C)] pub struct PyFloatObject {