diff --git a/CHANGELOG.md b/CHANGELOG.md index a6f53bf0..89ba0653 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,10 +9,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Added - Add support for `#[pyclass(dict)]` and `#[pyclass(weakref)]` with the `abi3` feature on Python 3.9 and up. [#1342](https://github.com/PyO3/pyo3/pull/1342) +### 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 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) - Remove `#[deny(warnings)]` attribute (and instead refuse warnings only in CI). [#1340](https://github.com/PyO3/pyo3/pull/1340) -- 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) - Fix deprecation warning for missing `__module__` with `#[pyclass]`. [#1343](https://github.com/PyO3/pyo3/pull/1343) ## [0.13.0] - 2020-12-22 diff --git a/src/ffi/context.rs b/src/ffi/context.rs index 20778e74..cbb58f39 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 00000000..3e58e7b9 --- /dev/null +++ b/src/ffi/cpython/dictobject.rs @@ -0,0 +1,63 @@ +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 + // 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 + #[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/frameobject.rs b/src/ffi/cpython/frameobject.rs similarity index 90% rename from src/ffi/frameobject.rs rename to src/ffi/cpython/frameobject.rs index 6178ab87..2f7d2b1d 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 + + #[cfg(not(Py_3_9))] 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 76513bde..2e3ff22a 100644 --- a/src/ffi/cpython/mod.rs +++ b/src/ffi/cpython/mod.rs @@ -1,11 +1,19 @@ pub mod abstract_; +// skipped bytearrayobject.h #[cfg(not(PyPy))] pub mod bytesobject; pub mod ceval; pub mod code; +#[cfg(not(PyPy))] +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::*; +#[cfg(not(PyPy))] +pub use self::dictobject::*; +pub use self::frameobject::*; diff --git a/src/ffi/datetime.rs b/src/ffi/datetime.rs index 4b17e3ef..daa8f0e1 100644 --- a/src/ffi/datetime.rs +++ b/src/ffi/datetime.rs @@ -23,134 +23,42 @@ use { std::ffi::CString, }; -#[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(all(Py_3_7, not(PyPy)))] - pub TimeZone_UTC: *mut PyObject, - #[cfg_attr(PyPy, link_name = "_PyPyDate_FromDate")] - pub Date_FromDate: unsafe extern "C" fn( - year: c_int, - month: c_int, - day: c_int, - cls: *mut PyTypeObject, - ) -> *mut PyObject, - #[cfg_attr(PyPy, link_name = "_PyPyDateTime_FromDateAndTime")] - 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, - #[cfg_attr(PyPy, link_name = "_PyPyTime_FromTime")] - 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, - #[cfg_attr(PyPy, link_name = "_PyPyDelta_FromDelta")] - 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(all(Py_3_7, not(PyPy)))] - pub TimeZone_FromTimeZone: - unsafe extern "C" fn(offset: *mut PyObject, name: *mut PyObject) -> *mut PyObject, - - // Defined for PyPy as `PyDateTime_FromTimestamp` - pub DateTime_FromTimestamp: unsafe extern "C" fn( - cls: *mut PyTypeObject, - args: *mut PyObject, - kwargs: *mut PyObject, - ) -> *mut PyObject, - // Defined for PyPy as `PyDate_FromTimestamp` - 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, -} - -#[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.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` @@ -162,20 +70,7 @@ pub struct PyDateTime_Date { 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, -} +// skipped non-limited _PyDateTime_BaseDateTime #[repr(C)] #[derive(Debug, Copy, Clone)] @@ -192,142 +87,7 @@ pub struct PyDateTime_DateTime { pub tzinfo: *mut PyObject, } -#[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, -} - -// 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 {} -static PY_DATETIME_API: GILOnceCell<&'static PyDateTime_CAPI> = GILOnceCell::new(); - -#[derive(Debug)] -pub struct PyDateTimeAPI { - __private_field: (), -} - -pub static PyDateTimeAPI: PyDateTimeAPI = PyDateTimeAPI { - __private_field: (), -}; - -impl Deref for PyDateTimeAPI { - type Target = PyDateTime_CAPI; - - fn deref(&self) -> &'static PyDateTime_CAPI { - unsafe { PyDateTime_IMPORT() } - } -} - -#[inline] -/// Populates the `PyDateTimeAPI` object -/// -/// Unlike in C, this does *not* need to be actively invoked in Rust, which -/// will populate the `PyDateTimeAPI` struct automatically on first use. -/// Use this function only if you want to eagerly load the datetime module, -/// such as if you do not want the first call to a datetime function to be -/// slightly slower than subsequent calls. -/// -/// # Safety -/// The Python GIL must be held. -pub unsafe fn PyDateTime_IMPORT() -> &'static PyDateTime_CAPI { - let py = Python::assume_gil_acquired(); - PY_DATETIME_API.get_or_init(py, || { - // PyPy expects the C-API to be initialized via PyDateTime_Import, so trying to use - // `PyCapsule_Import` will behave unexpectedly in pypy. - #[cfg(PyPy)] - let py_datetime_c_api = PyDateTime_Import(); - - #[cfg(not(PyPy))] - let py_datetime_c_api = { - // PyDateTime_CAPSULE_NAME is a macro in C - let PyDateTime_CAPSULE_NAME = CString::new("datetime.datetime_CAPI").unwrap(); - - &*(PyCapsule_Import(PyDateTime_CAPSULE_NAME.as_ptr(), 1) as *const PyDateTime_CAPI) - }; - - py_datetime_c_api - }) -} - -/// Type Check macros -/// -/// These are bindings around the C API typecheck macros, all of them return -/// `1` if True and `0` if False. In all type check macros, the argument (`op`) -/// must not be `NULL`. -#[inline] -/// Check if `op` is a `PyDateTimeAPI.DateType` or subtype. -pub unsafe fn PyDate_Check(op: *mut PyObject) -> c_int { - PyObject_TypeCheck(op, PyDateTimeAPI.DateType) as c_int -} - -#[inline] -/// Check if `op`'s type is exactly `PyDateTimeAPI.DateType`. -pub unsafe fn PyDate_CheckExact(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == PyDateTimeAPI.DateType) as c_int -} - -#[inline] -/// Check if `op` is a `PyDateTimeAPI.DateTimeType` or subtype. -pub unsafe fn PyDateTime_Check(op: *mut PyObject) -> c_int { - PyObject_TypeCheck(op, PyDateTimeAPI.DateTimeType) as c_int -} - -#[inline] -/// Check if `op`'s type is exactly `PyDateTimeAPI.DateTimeType`. -pub unsafe fn PyDateTime_CheckExact(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == PyDateTimeAPI.DateTimeType) as c_int -} - -#[inline] -/// Check if `op` is a `PyDateTimeAPI.TimeType` or subtype. -pub unsafe fn PyTime_Check(op: *mut PyObject) -> c_int { - PyObject_TypeCheck(op, PyDateTimeAPI.TimeType) as c_int -} - -#[inline] -/// Check if `op`'s type is exactly `PyDateTimeAPI.TimeType`. -pub unsafe fn PyTime_CheckExact(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == PyDateTimeAPI.TimeType) as c_int -} - -#[inline] -/// Check if `op` is a `PyDateTimeAPI.DetaType` or subtype. -pub unsafe fn PyDelta_Check(op: *mut PyObject) -> c_int { - PyObject_TypeCheck(op, PyDateTimeAPI.DeltaType) as c_int -} - -#[inline] -/// Check if `op`'s type is exactly `PyDateTimeAPI.DeltaType`. -pub unsafe fn PyDelta_CheckExact(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == PyDateTimeAPI.DeltaType) as c_int -} - -#[inline] -/// Check if `op` is a `PyDateTimeAPI.TZInfoType` or subtype. -pub unsafe fn PyTZInfo_Check(op: *mut PyObject) -> c_int { - PyObject_TypeCheck(op, PyDateTimeAPI.TZInfoType) as c_int -} - -#[inline] -/// Check if `op`'s type is exactly `PyDateTimeAPI.TZInfoType`. -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 - }; -} +// skipped non-limited _PyDateTime_HAS_TZINFO // Accessor functions for PyDateTime_Date and PyDateTime_DateTime #[inline] @@ -503,6 +263,14 @@ 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 { @@ -546,3 +314,268 @@ pub unsafe fn PyDateTime_DELTA_GET_SECONDS(o: *mut PyObject) -> c_int { 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(all(Py_3_7, not(PyPy)))] + pub TimeZone_UTC: *mut PyObject, + #[cfg_attr(PyPy, link_name = "_PyPyDate_FromDate")] + pub Date_FromDate: unsafe extern "C" fn( + year: c_int, + month: c_int, + day: c_int, + cls: *mut PyTypeObject, + ) -> *mut PyObject, + #[cfg_attr(PyPy, link_name = "_PyPyDateTime_FromDateAndTime")] + 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, + #[cfg_attr(PyPy, link_name = "_PyPyTime_FromTime")] + 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, + #[cfg_attr(PyPy, link_name = "_PyPyDelta_FromDelta")] + 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(all(Py_3_7, not(PyPy)))] + pub TimeZone_FromTimeZone: + unsafe extern "C" fn(offset: *mut PyObject, name: *mut PyObject) -> *mut PyObject, + + // Defined for PyPy as `PyDateTime_FromTimestamp` + pub DateTime_FromTimestamp: unsafe extern "C" fn( + cls: *mut PyTypeObject, + args: *mut PyObject, + kwargs: *mut PyObject, + ) -> *mut PyObject, + // Defined for PyPy as `PyDate_FromTimestamp` + 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 {} +static PY_DATETIME_API: GILOnceCell<&'static PyDateTime_CAPI> = GILOnceCell::new(); + +#[derive(Debug)] +pub struct PyDateTimeAPI { + __private_field: (), +} + +pub static PyDateTimeAPI: PyDateTimeAPI = PyDateTimeAPI { + __private_field: (), +}; + +impl Deref for PyDateTimeAPI { + type Target = PyDateTime_CAPI; + + fn deref(&self) -> &'static PyDateTime_CAPI { + unsafe { PyDateTime_IMPORT() } + } +} + +#[inline] +/// Populates the `PyDateTimeAPI` object +/// +/// Unlike in C, this does *not* need to be actively invoked in Rust, which +/// will populate the `PyDateTimeAPI` struct automatically on first use. +/// Use this function only if you want to eagerly load the datetime module, +/// such as if you do not want the first call to a datetime function to be +/// slightly slower than subsequent calls. +/// +/// # Safety +/// The Python GIL must be held. +pub unsafe fn PyDateTime_IMPORT() -> &'static PyDateTime_CAPI { + let py = Python::assume_gil_acquired(); + PY_DATETIME_API.get_or_init(py, || { + // PyPy expects the C-API to be initialized via PyDateTime_Import, so trying to use + // `PyCapsule_Import` will behave unexpectedly in pypy. + #[cfg(PyPy)] + let py_datetime_c_api = PyDateTime_Import(); + + #[cfg(not(PyPy))] + let py_datetime_c_api = { + // PyDateTime_CAPSULE_NAME is a macro in C + let PyDateTime_CAPSULE_NAME = CString::new("datetime.datetime_CAPI").unwrap(); + + &*(PyCapsule_Import(PyDateTime_CAPSULE_NAME.as_ptr(), 1) as *const PyDateTime_CAPI) + }; + + py_datetime_c_api + }) +} + +// skipped non-limited PyDateTime_TimeZone_UTC + +/// Type Check macros +/// +/// These are bindings around the C API typecheck macros, all of them return +/// `1` if True and `0` if False. In all type check macros, the argument (`op`) +/// must not be `NULL`. +#[inline] +/// Check if `op` is a `PyDateTimeAPI.DateType` or subtype. +pub unsafe fn PyDate_Check(op: *mut PyObject) -> c_int { + PyObject_TypeCheck(op, PyDateTimeAPI.DateType) as c_int +} + +#[inline] +/// Check if `op`'s type is exactly `PyDateTimeAPI.DateType`. +pub unsafe fn PyDate_CheckExact(op: *mut PyObject) -> c_int { + (Py_TYPE(op) == PyDateTimeAPI.DateType) as c_int +} + +#[inline] +/// Check if `op` is a `PyDateTimeAPI.DateTimeType` or subtype. +pub unsafe fn PyDateTime_Check(op: *mut PyObject) -> c_int { + PyObject_TypeCheck(op, PyDateTimeAPI.DateTimeType) as c_int +} + +#[inline] +/// Check if `op`'s type is exactly `PyDateTimeAPI.DateTimeType`. +pub unsafe fn PyDateTime_CheckExact(op: *mut PyObject) -> c_int { + (Py_TYPE(op) == PyDateTimeAPI.DateTimeType) as c_int +} + +#[inline] +/// Check if `op` is a `PyDateTimeAPI.TimeType` or subtype. +pub unsafe fn PyTime_Check(op: *mut PyObject) -> c_int { + PyObject_TypeCheck(op, PyDateTimeAPI.TimeType) as c_int +} + +#[inline] +/// Check if `op`'s type is exactly `PyDateTimeAPI.TimeType`. +pub unsafe fn PyTime_CheckExact(op: *mut PyObject) -> c_int { + (Py_TYPE(op) == PyDateTimeAPI.TimeType) as c_int +} + +#[inline] +/// Check if `op` is a `PyDateTimeAPI.DetaType` or subtype. +pub unsafe fn PyDelta_Check(op: *mut PyObject) -> c_int { + PyObject_TypeCheck(op, PyDateTimeAPI.DeltaType) as c_int +} + +#[inline] +/// Check if `op`'s type is exactly `PyDateTimeAPI.DeltaType`. +pub unsafe fn PyDelta_CheckExact(op: *mut PyObject) -> c_int { + (Py_TYPE(op) == PyDateTimeAPI.DeltaType) as c_int +} + +#[inline] +/// Check if `op` is a `PyDateTimeAPI.TZInfoType` or subtype. +pub unsafe fn PyTZInfo_Check(op: *mut PyObject) -> c_int { + PyObject_TypeCheck(op, PyDateTimeAPI.TZInfoType) as c_int +} + +#[inline] +/// Check if `op`'s type is exactly `PyDateTimeAPI.TZInfoType`. +pub unsafe fn PyTZInfo_CheckExact(op: *mut PyObject) -> c_int { + (Py_TYPE(op) == PyDateTimeAPI.TZInfoType) as c_int +} + +// 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 + +#[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; +} +#[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 6cdb91a4..17738772 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,35 @@ 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`. +#[deprecated(note = "not present in Python headers; to be removed")] +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))] +#[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. +/// +/// 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)))] +#[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), + 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 fa37ed1e..cfb57995 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,49 @@ 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; +} + +#[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/eval.rs b/src/ffi/eval.rs index 347f1390..b554cda3 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 61307496..029304eb 100644 --- a/src/ffi/fileobject.rs +++ b/src/ffi/fileobject.rs @@ -14,14 +14,14 @@ 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"))] @@ -29,4 +29,7 @@ extern "C" { pub static mut Py_FileSystemDefaultEncoding: *const c_char; 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 a5928d28..d33feb9a 100644 --- a/src/ffi/floatobject.rs +++ b/src/ffi/floatobject.rs @@ -1,6 +1,11 @@ use crate::ffi::object::*; use std::os::raw::{c_double, c_int}; +#[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, @@ -23,11 +28,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 +42,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 af7a936b..88e9f25f 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 4f9b394b..a72c25e1 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 b16e1a12..ddc608d1 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 00000000..007cbf75 --- /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 58e98875..73bdf632 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; diff --git a/src/pyclass.rs b/src/pyclass.rs index f82c4e82..22287a52 100644 --- a/src/pyclass.rs +++ b/src/pyclass.rs @@ -391,6 +391,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"); @@ -398,6 +399,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");