diff --git a/CHANGELOG.md b/CHANGELOG.md index 09a06fe9..a9b09c11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Fixed * `__radd__` and other `__r*__` methods now correctly work with operators. [#839](https://github.com/PyO3/pyo3/pull/839) +* Garbage Collector causing random panics when traversing objects that were mutably borrowed. [#855](https://github.com/PyO3/pyo3/pull/855) ## [0.9.2] @@ -42,6 +43,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. * `PyAny` is now on the top level module and prelude. [#816](https://github.com/PyO3/pyo3/pull/816) ### Added + * `PyCell`, which has RefCell-like features. [#770](https://github.com/PyO3/pyo3/pull/770) * `PyClass`, `PyLayout`, `PyClassInitializer`. [#683](https://github.com/PyO3/pyo3/pull/683) * Implemented `IntoIterator` for `PySet` and `PyFrozenSet`. [#716](https://github.com/PyO3/pyo3/pull/716) @@ -113,14 +115,12 @@ and `PyString::to_string_lossy` [#642](https://github.com/PyO3/pyo3/pull/642). * Remove `__contains__` and `__iter__` from PyMappingProtocol. [#644](https://github.com/PyO3/pyo3/pull/644) * Fix proc-macro definition of PySetAttrProtocol. [#645](https://github.com/PyO3/pyo3/pull/645) - ## [0.8.1] ### Added * Conversion between [num-bigint](https://github.com/rust-num/num-bigint) and Python int. [#608](https://github.com/PyO3/pyo3/pull/608) - ### Fixed * Make sure the right Python interpreter is used in OSX builds. [#604](https://github.com/PyO3/pyo3/pull/604) @@ -403,7 +403,6 @@ Yanked * Remove use of now unneeded 'AsciiExt' trait - ## [0.2.2] - 09-26-2017 ### Changed diff --git a/README.md b/README.md index 7d715742..dda19fd2 100644 --- a/README.md +++ b/README.md @@ -128,13 +128,18 @@ fn main_(py: Python) -> PyResult<()> { Our guide has [a section](https://pyo3.rs/master/python_from_rust.html) with lots of examples about this topic. -## Examples and tooling +## Tools and libraries + * [maturin](https://github.com/PyO3/maturin) _Zero configuration build tool for Rust-made Python extensions_. + * [setuptools-rust](https://github.com/PyO3/setuptools-rust) _Setuptools plugin for Rust support_. + * [pyo3-built](https://github.com/PyO3/pyo3-built) _Simple macro to expose metadata obtained with the [`built`](https://crates.io/crates/built) crate as a [`PyDict`](https://pyo3.github.io/pyo3/pyo3/struct.PyDict.html)_ + * [rust-numpy](https://github.com/PyO3/rust-numpy) _Rust binding of NumPy C-API_ + * [dict-derive](https://github.com/gperinazzo/dict-derive) _Derive FromPyObject to automatically transform Python dicts into Rust structs_ + +## Examples * [examples/word-count](examples/word-count) _Counting the occurrences of a word in a text file_ * [hyperjson](https://github.com/mre/hyperjson) _A hyper-fast Python module for reading/writing JSON data using Rust's serde-json_ - * [rust-numpy](https://github.com/PyO3/rust-numpy) _Rust binding of NumPy C-API_ * [html-py-ever](https://github.com/PyO3/setuptools-rust/tree/master/html-py-ever) _Using [html5ever](https://github.com/servo/html5ever) through [kuchiki](https://github.com/kuchiki-rs/kuchiki) to speed up html parsing and css-selecting._ - * [pyo3-built](https://github.com/PyO3/pyo3-built) _Simple macro to expose metadata obtained with the [`built`](https://crates.io/crates/built) crate as a [`PyDict`](https://pyo3.github.io/pyo3/pyo3/struct.PyDict.html)_ * [point-process](https://github.com/ManifoldFR/point-process-rust/tree/master/pylib) _High level API for pointprocesses as a Python library_ * [autopy](https://github.com/autopilot-rs/autopy) _A simple, cross-platform GUI automation library for Python and Rust._ * Contains an example of building wheels on TravisCI and appveyor using [cibuildwheel](https://github.com/joerick/cibuildwheel) @@ -144,7 +149,6 @@ about this topic. * Contains an example of building wheels on Azure Pipelines * [fastuuid](https://github.com/thedrow/fastuuid/) _Python bindings to Rust's UUID library_ * [python-ext-wasm](https://github.com/wasmerio/python-ext-wasm) _Python library to run WebAssembly binaries_ - * [dict-derive](https://github.com/gperinazzo/dict-derive) _Derive FromPyObject to automatically transform Python dicts into Rust structs_ * [mocpy](https://github.com/cds-astro/mocpy) _Astronomical Python library offering data structures for describing any arbitrary coverage regions on the unit sphere_ * [tokenizers](https://github.com/huggingface/tokenizers/tree/master/bindings/python) _Python bindings to the Hugging Face tokenizers (NLP) written in Rust_ diff --git a/guide/src/get_started.md b/guide/src/get_started.md index 4c55f896..2a17b85c 100644 --- a/guide/src/get_started.md +++ b/guide/src/get_started.md @@ -123,13 +123,18 @@ fn main_(py: Python) -> PyResult<()> { Our guide has [a section](https://pyo3.rs/master/python_from_rust.html) with lots of examples about this topic. -## Examples and tooling - - * [examples/word-count](https://github.com/PyO3/pyo3/tree/master/examples/word-count) _Counting the occurrences of a word in a text file_ - * [hyperjson](https://github.com/mre/hyperjson) _A hyper-fast Python module for reading/writing JSON data using Rust's serde-json_ - * [rust-numpy](https://github.com/PyO3/rust-numpy) _Rust binding of NumPy C-API_ - * [html-py-ever](https://github.com/PyO3/setuptools-rust/tree/master/html-py-ever) _Using [html5ever](https://github.com/servo/html5ever) through [kuchiki](https://github.com/kuchiki-rs/kuchiki) to speed up html parsing and css-selecting._ +## Tools and libraries + * [maturin](https://github.com/PyO3/maturin) _Zero configuration build tool for Rust-made Python extensions_. + * [setuptools-rust](https://github.com/PyO3/setuptools-rust) _Setuptools plugin for Rust support_. * [pyo3-built](https://github.com/PyO3/pyo3-built) _Simple macro to expose metadata obtained with the [`built`](https://crates.io/crates/built) crate as a [`PyDict`](https://pyo3.github.io/pyo3/pyo3/struct.PyDict.html)_ + * [rust-numpy](https://github.com/PyO3/rust-numpy) _Rust binding of NumPy C-API_ + * [dict-derive](https://github.com/gperinazzo/dict-derive) _Derive FromPyObject to automatically transform Python dicts into Rust structs_ + +## Examples + + * [examples/word-count](examples/word-count) _Counting the occurrences of a word in a text file_ + * [hyperjson](https://github.com/mre/hyperjson) _A hyper-fast Python module for reading/writing JSON data using Rust's serde-json_ + * [html-py-ever](https://github.com/PyO3/setuptools-rust/tree/master/html-py-ever) _Using [html5ever](https://github.com/servo/html5ever) through [kuchiki](https://github.com/kuchiki-rs/kuchiki) to speed up html parsing and css-selecting._ * [point-process](https://github.com/ManifoldFR/point-process-rust/tree/master/pylib) _High level API for pointprocesses as a Python library_ * [autopy](https://github.com/autopilot-rs/autopy) _A simple, cross-platform GUI automation library for Python and Rust._ * Contains an example of building wheels on TravisCI and appveyor using [cibuildwheel](https://github.com/joerick/cibuildwheel) @@ -139,4 +144,5 @@ about this topic. * Contains an example of building wheels on Azure Pipelines * [fastuuid](https://github.com/thedrow/fastuuid/) _Python bindings to Rust's UUID library_ * [python-ext-wasm](https://github.com/wasmerio/python-ext-wasm) _Python library to run WebAssembly binaries_ - * [dict-derive](https://github.com/gperinazzo/dict-derive) _Derive FromPyObject to automatically transform Python dicts into Rust structs_ + * [mocpy](https://github.com/cds-astro/mocpy) _Astronomical Python library offering data structures for describing any arbitrary coverage regions on the unit sphere_ + * [tokenizers](https://github.com/huggingface/tokenizers/tree/master/bindings/python) _Python bindings to the Hugging Face tokenizers (NLP) written in Rust_ diff --git a/pyo3-derive-backend/src/defs.rs b/pyo3-derive-backend/src/defs.rs index 145b56f5..02a5ca74 100644 --- a/pyo3-derive-backend/src/defs.rs +++ b/pyo3-derive-backend/src/defs.rs @@ -7,9 +7,44 @@ pub struct Proto { pub py_methods: &'static [PyMethod], } +impl Proto { + pub(crate) fn get_proto(&self, query: Q) -> Option<&'static MethodProto> + where + Q: PartialEq<&'static str>, + { + self.methods.iter().find(|m| query == m.name()) + } + pub(crate) fn get_method(&self, query: Q) -> Option<&'static PyMethod> + where + Q: PartialEq<&'static str>, + { + self.py_methods.iter().find(|m| query == m.name) + } +} + +// TODO(kngwyu): Currently only __radd__-like methods use METH_COEXIST to prevent +// __add__-like methods from overriding them. pub struct PyMethod { pub name: &'static str, pub proto: &'static str, + pub can_coexist: bool, +} + +impl PyMethod { + const fn coexist(name: &'static str, proto: &'static str) -> Self { + PyMethod { + name, + proto, + can_coexist: true, + } + } + const fn new(name: &'static str, proto: &'static str) -> Self { + PyMethod { + name, + proto, + can_coexist: false, + } + } } pub const OBJECT: Proto = Proto { @@ -73,18 +108,9 @@ pub const OBJECT: Proto = Proto { }, ], py_methods: &[ - PyMethod { - name: "__format__", - proto: "pyo3::class::basic::FormatProtocolImpl", - }, - PyMethod { - name: "__bytes__", - proto: "pyo3::class::basic::BytesProtocolImpl", - }, - PyMethod { - name: "__unicode__", - proto: "pyo3::class::basic::UnicodeProtocolImpl", - }, + PyMethod::new("__format__", "pyo3::class::basic::FormatProtocolImpl"), + PyMethod::new("__bytes__", "pyo3::class::basic::BytesProtocolImpl"), + PyMethod::new("__unicode__", "pyo3::class::basic::UnicodeProtocolImpl"), ], }; @@ -120,14 +146,14 @@ pub const ASYNC: Proto = Proto { }, ], py_methods: &[ - PyMethod { - name: "__aenter__", - proto: "pyo3::class::pyasync::PyAsyncAenterProtocolImpl", - }, - PyMethod { - name: "__aexit__", - proto: "pyo3::class::pyasync::PyAsyncAexitProtocolImpl", - }, + PyMethod::new( + "__aenter__", + "pyo3::class::pyasync::PyAsyncAenterProtocolImpl", + ), + PyMethod::new( + "__aexit__", + "pyo3::class::pyasync::PyAsyncAexitProtocolImpl", + ), ], }; @@ -165,14 +191,14 @@ pub const CONTEXT: Proto = Proto { }, ], py_methods: &[ - PyMethod { - name: "__enter__", - proto: "pyo3::class::context::PyContextEnterProtocolImpl", - }, - PyMethod { - name: "__exit__", - proto: "pyo3::class::context::PyContextExitProtocolImpl", - }, + PyMethod::new( + "__enter__", + "pyo3::class::context::PyContextEnterProtocolImpl", + ), + PyMethod::new( + "__exit__", + "pyo3::class::context::PyContextExitProtocolImpl", + ), ], }; @@ -222,14 +248,11 @@ pub const DESCR: Proto = Proto { }, ], py_methods: &[ - PyMethod { - name: "__del__", - proto: "pyo3::class::context::PyDescrDelProtocolImpl", - }, - PyMethod { - name: "__set_name__", - proto: "pyo3::class::context::PyDescrNameProtocolImpl", - }, + PyMethod::new("__del__", "pyo3::class::context::PyDescrDelProtocolImpl"), + PyMethod::new( + "__set_name__", + "pyo3::class::context::PyDescrNameProtocolImpl", + ), ], }; @@ -283,10 +306,10 @@ pub const MAPPING: Proto = Proto { proto: "pyo3::class::mapping::PyMappingReversedProtocol", }, ], - py_methods: &[PyMethod { - name: "__reversed__", - proto: "pyo3::class::mapping::PyMappingReversedProtocolImpl", - }], + py_methods: &[PyMethod::new( + "__reversed__", + "pyo3::class::mapping::PyMappingReversedProtocolImpl", + )], }; pub const SEQ: Proto = Proto { @@ -579,10 +602,9 @@ pub const NUM: Proto = Proto { pyres: false, proto: "pyo3::class::number::PyNumberIModProtocol", }, - MethodProto::Ternary { + MethodProto::Binary { name: "__ipow__", - arg1: "Other", - arg2: "Modulo", + arg: "Other", pyres: false, proto: "pyo3::class::number::PyNumberIPowProtocol", }, @@ -651,81 +673,58 @@ pub const NUM: Proto = Proto { pyres: true, proto: "pyo3::class::number::PyNumberFloatProtocol", }, - MethodProto::Unary { - name: "__round__", - pyres: true, - proto: "pyo3::class::number::PyNumberRoundProtocol", - }, MethodProto::Unary { name: "__index__", pyres: true, proto: "pyo3::class::number::PyNumberIndexProtocol", }, + MethodProto::Binary { + name: "__round__", + arg: "NDigits", + pyres: true, + proto: "pyo3::class::number::PyNumberRoundProtocol", + }, ], py_methods: &[ - PyMethod { - name: "__radd__", - proto: "pyo3::class::number::PyNumberRAddProtocolImpl", - }, - PyMethod { - name: "__rsub__", - proto: "pyo3::class::number::PyNumberRSubProtocolImpl", - }, - PyMethod { - name: "__rmul__", - proto: "pyo3::class::number::PyNumberRMulProtocolImpl", - }, - PyMethod { - name: "__rmatmul__", - proto: "pyo3::class::number::PyNumberRMatmulProtocolImpl", - }, - PyMethod { - name: "__rtruediv__", - proto: "pyo3::class::number::PyNumberRTruedivProtocolImpl", - }, - PyMethod { - name: "__rfloordiv__", - proto: "pyo3::class::number::PyNumberRFloordivProtocolImpl", - }, - PyMethod { - name: "__rmod__", - proto: "pyo3::class::number::PyNumberRModProtocolImpl", - }, - PyMethod { - name: "__rdivmod__", - proto: "pyo3::class::number::PyNumberRDivmodProtocolImpl", - }, - PyMethod { - name: "__rpow__", - proto: "pyo3::class::number::PyNumberRPowProtocolImpl", - }, - PyMethod { - name: "__rlshift__", - proto: "pyo3::class::number::PyNumberRLShiftProtocolImpl", - }, - PyMethod { - name: "__rrshift__", - proto: "pyo3::class::number::PyNumberRRShiftProtocolImpl", - }, - PyMethod { - name: "__rand__", - proto: "pyo3::class::number::PyNumberRAndProtocolImpl", - }, - PyMethod { - name: "__rxor__", - proto: "pyo3::class::number::PyNumberRXorProtocolImpl", - }, - PyMethod { - name: "__ror__", - proto: "pyo3::class::number::PyNumberROrProtocolImpl", - }, - PyMethod { - name: "__complex__", - proto: "pyo3::class::number::PyNumberComplexProtocolImpl", - }, - PyMethod { - name: "__round__", - proto: "pyo3::class::number::PyNumberRoundProtocolImpl", - }, + PyMethod::coexist("__radd__", "pyo3::class::number::PyNumberRAddProtocolImpl"), + PyMethod::coexist("__rsub__", "pyo3::class::number::PyNumberRSubProtocolImpl"), + PyMethod::coexist("__rmul__", "pyo3::class::number::PyNumberRMulProtocolImpl"), + PyMethod::coexist( + "__rmatmul__", + "pyo3::class::number::PyNumberRMatmulProtocolImpl", + ), + PyMethod::coexist( + "__rtruediv__", + "pyo3::class::number::PyNumberRTruedivProtocolImpl", + ), + PyMethod::coexist( + "__rfloordiv__", + "pyo3::class::number::PyNumberRFloordivProtocolImpl", + ), + PyMethod::coexist("__rmod__", "pyo3::class::number::PyNumberRModProtocolImpl"), + PyMethod::coexist( + "__rdivmod__", + "pyo3::class::number::PyNumberRDivmodProtocolImpl", + ), + PyMethod::coexist("__rpow__", "pyo3::class::number::PyNumberRPowProtocolImpl"), + PyMethod::coexist( + "__rlshift__", + "pyo3::class::number::PyNumberRLShiftProtocolImpl", + ), + PyMethod::coexist( + "__rrshift__", + "pyo3::class::number::PyNumberRRShiftProtocolImpl", + ), + PyMethod::coexist("__rand__", "pyo3::class::number::PyNumberRAndProtocolImpl"), + PyMethod::coexist("__rxor__", "pyo3::class::number::PyNumberRXorProtocolImpl"), + PyMethod::coexist("__ror__", "pyo3::class::number::PyNumberROrProtocolImpl"), + PyMethod::new( + "__complex__", + "pyo3::class::number::PyNumberComplexProtocolImpl", + ), + PyMethod::new( + "__round__", + "pyo3::class::number::PyNumberRoundProtocolImpl", + ), ], }; diff --git a/pyo3-derive-backend/src/func.rs b/pyo3-derive-backend/src/func.rs index c8e3c83b..fbc48cb7 100644 --- a/pyo3-derive-backend/src/func.rs +++ b/pyo3-derive-backend/src/func.rs @@ -69,7 +69,7 @@ impl MethodProto { } } -pub fn impl_method_proto( +pub(crate) fn impl_method_proto( cls: &syn::Type, sig: &mut syn::Signature, meth: &MethodProto, diff --git a/pyo3-derive-backend/src/method.rs b/pyo3-derive-backend/src/method.rs index 20b06c61..aa02a90b 100644 --- a/pyo3-derive-backend/src/method.rs +++ b/pyo3-derive-backend/src/method.rs @@ -63,7 +63,7 @@ impl<'a> FnSpec<'a> { let is_mut = self .self_ .expect("impl_borrow_self is called for non-self fn"); - crate::utils::borrow_self(is_mut, true) + crate::utils::borrow_self(is_mut) } /// Parser function signature and function attributes diff --git a/pyo3-derive-backend/src/module.rs b/pyo3-derive-backend/src/module.rs index bd9d601a..d6180c5b 100644 --- a/pyo3-derive-backend/src/module.rs +++ b/pyo3-derive-backend/src/module.rs @@ -221,13 +221,15 @@ fn function_c_wrapper(name: &Ident, spec: &method::FnSpec<'_>) -> TokenStream { const _LOCATION: &'static str = concat!(stringify!(#name), "()"); let _py = pyo3::Python::assume_gil_acquired(); - let _pool = pyo3::GILPool::new(_py); - let _args = _py.from_borrowed_ptr::(_args); - let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs); + pyo3::run_callback(_py, || { + let _pool = pyo3::GILPool::new(_py); + let _args = _py.from_borrowed_ptr::(_args); + let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs); - #body + #body - pyo3::callback::cb_obj_convert(_py, _result) + pyo3::callback::convert(_py, _result) + }) } } } diff --git a/pyo3-derive-backend/src/pyclass.rs b/pyo3-derive-backend/src/pyclass.rs index 23697a76..5c92a75b 100644 --- a/pyo3-derive-backend/src/pyclass.rs +++ b/pyo3-derive-backend/src/pyclass.rs @@ -459,7 +459,6 @@ fn impl_descriptors( .collect::>()?; Ok(quote! { - pyo3::inventory::submit! { #![crate = pyo3] { type ClsInventory = <#cls as pyo3::class::methods::PyMethodsInventoryDispatch>::InventoryType; diff --git a/pyo3-derive-backend/src/pymethod.rs b/pyo3-derive-backend/src/pymethod.rs index d590d2b2..729384c0 100644 --- a/pyo3-derive-backend/src/pymethod.rs +++ b/pyo3-derive-backend/src/pymethod.rs @@ -83,10 +83,7 @@ pub fn impl_wrap_pyslf( }; let slf = quote! { let _cell = _py.from_borrowed_ptr::>(_slf); - let _slf: #self_ty = match std::convert::TryFrom::try_from(_cell) { - Ok(_slf) => _slf, - Err(e) => return pyo3::PyErr::from(e).restore_and_null(_py), - }; + let _slf: #self_ty = std::convert::TryFrom::try_from(_cell)?; }; impl_wrap_common(cls, spec, noargs, slf, body) } @@ -109,13 +106,11 @@ fn impl_wrap_common( const _LOCATION: &'static str = concat!( stringify!(#cls), ".", stringify!(#python_name), "()"); let _py = pyo3::Python::assume_gil_acquired(); - let _pool = pyo3::GILPool::new(_py); - #slf - let _result = { - pyo3::derive_utils::IntoPyResult::into_py_result(#body) - }; - - pyo3::callback::cb_obj_convert(_py, _result) + pyo3::run_callback(_py, || { + let _pool = pyo3::GILPool::new(_py); + #slf + pyo3::callback::convert(_py, #body) + }) } } } else { @@ -130,14 +125,16 @@ fn impl_wrap_common( const _LOCATION: &'static str = concat!( stringify!(#cls), ".", stringify!(#python_name), "()"); let _py = pyo3::Python::assume_gil_acquired(); - let _pool = pyo3::GILPool::new(_py); - #slf - let _args = _py.from_borrowed_ptr::(_args); - let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs); + pyo3::run_callback(_py, || { + let _pool = pyo3::GILPool::new(_py); + #slf + let _args = _py.from_borrowed_ptr::(_args); + let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs); - #body + #body - pyo3::callback::cb_obj_convert(_py, _result) + pyo3::callback::convert(_py, _result) + }) } } } @@ -159,15 +156,17 @@ pub fn impl_proto_wrap(cls: &syn::Type, spec: &FnSpec<'_>) -> TokenStream { { const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#python_name),"()"); let _py = pyo3::Python::assume_gil_acquired(); - let _pool = pyo3::GILPool::new(_py); - let _slf = _py.from_borrowed_ptr::>(_slf); - #borrow_self - let _args = _py.from_borrowed_ptr::(_args); - let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs); + pyo3::run_callback(_py, || { + let _pool = pyo3::GILPool::new(_py); + let _slf = _py.from_borrowed_ptr::>(_slf); + #borrow_self + let _args = _py.from_borrowed_ptr::(_args); + let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs); - #body + #body - pyo3::callback::cb_obj_convert(_py, _result) + pyo3::callback::convert(_py, _result) + }) } } } @@ -195,16 +194,16 @@ pub fn impl_wrap_new(cls: &syn::Type, spec: &FnSpec<'_>) -> TokenStream { const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#python_name),"()"); let _py = pyo3::Python::assume_gil_acquired(); - let _pool = pyo3::GILPool::new(_py); - let _args = _py.from_borrowed_ptr::(_args); - let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs); + pyo3::run_callback(_py, || { + let _pool = pyo3::GILPool::new(_py); + let _args = _py.from_borrowed_ptr::(_args); + let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs); - #body + #body - match _result.and_then(|init| pyo3::PyClassInitializer::from(init).create_cell(_py)) { - Ok(slf) => slf as _, - Err(e) => e.restore_and_null(_py), - } + let cell = pyo3::PyClassInitializer::from(_result?).create_cell(_py)?; + Ok(cell as *mut pyo3::ffi::PyObject) + }) } } } @@ -227,14 +226,16 @@ pub fn impl_wrap_class(cls: &syn::Type, spec: &FnSpec<'_>) -> TokenStream { { const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#python_name),"()"); let _py = pyo3::Python::assume_gil_acquired(); - let _pool = pyo3::GILPool::new(_py); - let _cls = pyo3::types::PyType::from_type_ptr(_py, _cls as *mut pyo3::ffi::PyTypeObject); - let _args = _py.from_borrowed_ptr::(_args); - let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs); + pyo3::run_callback(_py, || { + let _pool = pyo3::GILPool::new(_py); + let _cls = pyo3::types::PyType::from_type_ptr(_py, _cls as *mut pyo3::ffi::PyTypeObject); + let _args = _py.from_borrowed_ptr::(_args); + let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs); - #body + #body - pyo3::callback::cb_obj_convert(_py, _result) + pyo3::callback::convert(_py, _result) + }) } } } @@ -257,13 +258,15 @@ pub fn impl_wrap_static(cls: &syn::Type, spec: &FnSpec<'_>) -> TokenStream { { const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#python_name),"()"); let _py = pyo3::Python::assume_gil_acquired(); - let _pool = pyo3::GILPool::new(_py); - let _args = _py.from_borrowed_ptr::(_args); - let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs); + pyo3::run_callback(_py, || { + let _pool = pyo3::GILPool::new(_py); + let _args = _py.from_borrowed_ptr::(_args); + let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs); - #body + #body - pyo3::callback::cb_obj_convert(_py, _result) + pyo3::callback::convert(_py, _result) + }) } } } @@ -305,7 +308,7 @@ pub(crate) fn impl_wrap_getter( PropertyType::Function(spec) => (spec.python_name.clone(), impl_call_getter(&spec)?), }; - let borrow_self = crate::utils::borrow_self(false, true); + let borrow_self = crate::utils::borrow_self(false); Ok(quote! { unsafe extern "C" fn __wrap( _slf: *mut pyo3::ffi::PyObject, _: *mut ::std::os::raw::c_void) -> *mut pyo3::ffi::PyObject @@ -313,16 +316,12 @@ pub(crate) fn impl_wrap_getter( const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#python_name),"()"); let _py = pyo3::Python::assume_gil_acquired(); - let _pool = pyo3::GILPool::new(_py); - let _slf = _py.from_borrowed_ptr::>(_slf); - #borrow_self - - let result = pyo3::derive_utils::IntoPyResult::into_py_result(#getter_impl); - - match result { - Ok(val) => pyo3::IntoPyPointer::into_ptr(pyo3::IntoPy::::into_py(val, _py)), - Err(e) => e.restore_and_null(_py), - } + pyo3::run_callback(_py, || { + let _pool = pyo3::GILPool::new(_py); + let _slf = _py.from_borrowed_ptr::>(_slf); + #borrow_self + pyo3::callback::convert(_py, #getter_impl) + }) } }) } @@ -344,9 +343,9 @@ fn impl_call_setter(spec: &FnSpec) -> syn::Result { let name = &spec.name; let fncall = if py_arg.is_some() { - quote!(pyo3::derive_utils::IntoPyResult::into_py_result(_slf.#name(_py, _val))) + quote!(pyo3::derive_utils::IntoPyResult::into_py_result(_slf.#name(_py, _val))?;) } else { - quote!(pyo3::derive_utils::IntoPyResult::into_py_result(_slf.#name(_val))) + quote!(pyo3::derive_utils::IntoPyResult::into_py_result(_slf.#name(_val))?;) }; Ok(fncall) @@ -360,12 +359,12 @@ pub(crate) fn impl_wrap_setter( let (python_name, setter_impl) = match property_type { PropertyType::Descriptor(field) => { let name = field.ident.as_ref().unwrap(); - (name.unraw(), quote!({ _slf.#name = _val; Ok(()) })) + (name.unraw(), quote!(_slf.#name = _val;)) } PropertyType::Function(spec) => (spec.python_name.clone(), impl_call_setter(&spec)?), }; - let borrow_self = crate::utils::borrow_self(true, false); + let borrow_self = crate::utils::borrow_self(true); Ok(quote! { #[allow(unused_mut)] unsafe extern "C" fn __wrap( @@ -374,21 +373,14 @@ pub(crate) fn impl_wrap_setter( { const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#python_name),"()"); let _py = pyo3::Python::assume_gil_acquired(); - let _pool = pyo3::GILPool::new(_py); - let _slf = _py.from_borrowed_ptr::>(_slf); - #borrow_self - let _value = _py.from_borrowed_ptr(_value); - - let _result = match pyo3::FromPyObject::extract(_value) { - Ok(_val) => { - #setter_impl - } - Err(e) => Err(e) - }; - match _result { - Ok(_) => 0, - Err(e) => e.restore_and_minus1(_py), - } + pyo3::run_callback(_py, || { + let _pool = pyo3::GILPool::new(_py); + let _slf = _py.from_borrowed_ptr::>(_slf); + #borrow_self + let _value = _py.from_borrowed_ptr::(_value); + let _val = pyo3::FromPyObject::extract(_value)?; + pyo3::callback::convert(_py, {#setter_impl}) + }) } }) } @@ -462,22 +454,19 @@ fn impl_arg_params_(spec: &FnSpec<'_>, body: TokenStream, into_result: TokenStre let mut _args = _args; let mut _kwargs = _kwargs; - // Workaround to use the question mark operator without rewriting everything - let _result = (|| { - let (_args, _kwargs) = pyo3::derive_utils::parse_fn_args( - Some(_LOCATION), - PARAMS, - _args, - _kwargs, - #accept_args, - #accept_kwargs, - &mut output - )?; + let (_args, _kwargs) = pyo3::derive_utils::parse_fn_args( + Some(_LOCATION), + PARAMS, + _args, + _kwargs, + #accept_args, + #accept_kwargs, + &mut output + )?; - #(#param_conversion)* + #(#param_conversion)* - #into_result(#body) - })(); + let _result = #into_result(#body); } } diff --git a/pyo3-derive-backend/src/pyproto.rs b/pyo3-derive-backend/src/pyproto.rs index 5cd32c6e..8f0d9330 100644 --- a/pyo3-derive-backend/src/pyproto.rs +++ b/pyo3-derive-backend/src/pyproto.rs @@ -63,39 +63,40 @@ fn impl_proto_impl( for iimpl in impls.iter_mut() { if let syn::ImplItem::Method(ref mut met) = iimpl { - for m in proto.methods { - if met.sig.ident == m.name() { - impl_method_proto(ty, &mut met.sig, m).to_tokens(&mut tokens); - } + if let Some(m) = proto.get_proto(&met.sig.ident) { + impl_method_proto(ty, &mut met.sig, m).to_tokens(&mut tokens); } - for m in proto.py_methods { - if met.sig.ident == m.name { - let name = &met.sig.ident; - let proto: syn::Path = syn::parse_str(m.proto).unwrap(); + if let Some(m) = proto.get_method(&met.sig.ident) { + let name = &met.sig.ident; + let proto: syn::Path = syn::parse_str(m.proto).unwrap(); - let fn_spec = match FnSpec::parse(&met.sig, &mut met.attrs, false) { - Ok(fn_spec) => fn_spec, - Err(err) => return err.to_compile_error(), - }; - let meth = pymethod::impl_proto_wrap(ty, &fn_spec); + let fn_spec = match FnSpec::parse(&met.sig, &mut met.attrs, false) { + Ok(fn_spec) => fn_spec, + Err(err) => return err.to_compile_error(), + }; + let meth = pymethod::impl_proto_wrap(ty, &fn_spec); + let coexist = if m.can_coexist { + quote!(pyo3::ffi::METH_COEXIST) + } else { + quote!(0) + }; + py_methods.push(quote! { + impl #proto for #ty + { + #[inline] + fn #name() -> Option { + #meth - py_methods.push(quote! { - impl #proto for #ty - { - #[inline] - fn #name() -> Option { - #meth - - Some(pyo3::class::PyMethodDef { - ml_name: stringify!(#name), - ml_meth: pyo3::class::PyMethodType::PyCFunctionWithKeywords(__wrap), - ml_flags: pyo3::ffi::METH_VARARGS | pyo3::ffi::METH_KEYWORDS, - ml_doc: "" - }) - } + Some(pyo3::class::PyMethodDef { + ml_name: stringify!(#name), + ml_meth: pyo3::class::PyMethodType::PyCFunctionWithKeywords(__wrap), + // We need METH_COEXIST here to prevent __add__ from overriding __radd__ + ml_flags: pyo3::ffi::METH_VARARGS | pyo3::ffi::METH_KEYWORDS | #coexist, + ml_doc: "" + }) } - }); - } + } + }); } } } diff --git a/pyo3-derive-backend/src/utils.rs b/pyo3-derive-backend/src/utils.rs index 32b66b25..d051a634 100644 --- a/pyo3-derive-backend/src/utils.rs +++ b/pyo3-derive-backend/src/utils.rs @@ -4,25 +4,14 @@ use proc_macro2::TokenStream; use quote::quote; use std::fmt::Display; -pub(crate) fn borrow_self(is_mut: bool, return_null: bool) -> TokenStream { - let ret = if return_null { - quote! { restore_and_null } - } else { - quote! { restore_and_minus1 } - }; +pub(crate) fn borrow_self(is_mut: bool) -> TokenStream { if is_mut { quote! { - let mut _slf = match _slf.try_borrow_mut() { - Ok(ref_) => ref_, - Err(e) => return pyo3::PyErr::from(e).#ret(_py), - }; + let mut _slf = _slf.try_borrow_mut()?; } } else { quote! { - let _slf = match _slf.try_borrow() { - Ok(ref_) => ref_, - Err(e) => return pyo3::PyErr::from(e).#ret(_py), - }; + let _slf = _slf.try_borrow()?; } } } diff --git a/src/callback.rs b/src/callback.rs index edeca66c..68603d30 100644 --- a/src/callback.rs +++ b/src/callback.rs @@ -7,89 +7,91 @@ use crate::exceptions::OverflowError; use crate::ffi::{self, Py_hash_t}; use crate::IntoPyPointer; use crate::{IntoPy, PyObject, Python}; +use std::isize; use std::os::raw::c_int; -use std::{isize, ptr}; + +/// A type which can be the return type of a python C-API callback +pub trait PyCallbackOutput: Copy { + /// The error value to return to python if the callback raised an exception + const ERR_VALUE: Self; +} + +impl PyCallbackOutput for *mut ffi::PyObject { + const ERR_VALUE: Self = std::ptr::null_mut(); +} + +impl PyCallbackOutput for libc::c_int { + const ERR_VALUE: Self = -1; +} + +impl PyCallbackOutput for ffi::Py_ssize_t { + const ERR_VALUE: Self = -1; +} + +impl PyCallbackOutput for () { + const ERR_VALUE: Self = (); +} /// Convert the result of callback function into the appropriate return value. -/// -/// Used by PyO3 macros. -pub trait CallbackConverter { - type Source; - type Result: Copy; - const ERR_VALUE: Self::Result; +pub trait IntoPyCallbackOutput { + fn convert(self, py: Python) -> PyResult; +} - fn convert(s: Self::Source, py: Python) -> Self::Result; - - #[inline] - fn convert_result(py: Python, value: PyResult) -> Self::Result { - match value { - Ok(val) => Self::convert(val, py), - Err(e) => { - e.restore(py); - Self::ERR_VALUE - } - } +impl IntoPyCallbackOutput for PyResult +where + T: IntoPyCallbackOutput, +{ + fn convert(self, py: Python) -> PyResult { + self.and_then(|t| t.convert(py)) } } -pub struct PyObjectCallbackConverter(pub std::marker::PhantomData); - -impl CallbackConverter for PyObjectCallbackConverter +impl IntoPyCallbackOutput<*mut ffi::PyObject> for T where T: IntoPy, { - type Source = T; - type Result = *mut ffi::PyObject; - const ERR_VALUE: Self::Result = ptr::null_mut(); - - fn convert(s: Self::Source, py: Python) -> Self::Result { - s.into_py(py).into_ptr() + fn convert(self, py: Python) -> PyResult<*mut ffi::PyObject> { + Ok(self.into_py(py).into_ptr()) } } -pub struct BoolCallbackConverter; +impl IntoPyCallbackOutput for *mut ffi::PyObject { + fn convert(self, _: Python) -> PyResult { + Ok(self) + } +} -impl CallbackConverter for BoolCallbackConverter { - type Source = bool; - type Result = c_int; - const ERR_VALUE: Self::Result = -1; +impl IntoPyCallbackOutput for () { + fn convert(self, _: Python) -> PyResult { + Ok(0) + } +} +impl IntoPyCallbackOutput for bool { + fn convert(self, _: Python) -> PyResult { + Ok(self as c_int) + } +} + +impl IntoPyCallbackOutput<()> for () { + fn convert(self, _: Python) -> PyResult<()> { + Ok(()) + } +} + +pub struct LenCallbackOutput(pub usize); + +impl IntoPyCallbackOutput for LenCallbackOutput { #[inline] - fn convert(s: Self::Source, _py: Python) -> Self::Result { - s as c_int - } -} - -pub struct LenResultConverter; - -impl CallbackConverter for LenResultConverter { - type Source = usize; - type Result = isize; - const ERR_VALUE: Self::Result = -1; - - fn convert(val: Self::Source, py: Python) -> Self::Result { - if val <= (isize::MAX as usize) { - val as isize + fn convert(self, _py: Python) -> PyResult { + if self.0 <= (isize::MAX as usize) { + Ok(self.0 as isize) } else { - OverflowError::py_err(()).restore(py); - -1 + Err(OverflowError::py_err(())) } } } -pub struct UnitCallbackConverter; - -impl CallbackConverter for UnitCallbackConverter { - type Source = (); - type Result = c_int; - const ERR_VALUE: Self::Result = -1; - - #[inline] - fn convert(_s: Self::Source, _py: Python) -> Self::Result { - 0 - } -} - pub trait WrappingCastTo { fn wrapping_cast(self) -> T; } @@ -115,50 +117,49 @@ wrapping_cast!(i32, Py_hash_t); wrapping_cast!(isize, Py_hash_t); wrapping_cast!(i64, Py_hash_t); -pub struct HashConverter(pub std::marker::PhantomData); +pub struct HashCallbackOutput(pub T); -impl CallbackConverter for HashConverter +impl IntoPyCallbackOutput for HashCallbackOutput where T: WrappingCastTo, { - type Source = T; - type Result = Py_hash_t; - const ERR_VALUE: Self::Result = -1; - #[inline] - fn convert(val: T, _py: Python) -> Py_hash_t { - let hash = val.wrapping_cast(); + fn convert(self, _py: Python) -> PyResult { + let hash = self.0.wrapping_cast(); if hash == -1 { - -2 + Ok(-2) } else { - hash + Ok(hash) } } } -// Short hands methods for macros +#[doc(hidden)] #[inline] -pub fn cb_convert(_c: C, py: Python, value: PyResult) -> C::Result +pub fn convert(py: Python, value: T) -> PyResult where - C: CallbackConverter, + T: IntoPyCallbackOutput, { - C::convert_result(py, value) + value.convert(py) } -// Same as cb_convert(PyObjectCallbackConverter, py, value) +#[doc(hidden)] #[inline] -pub fn cb_obj_convert>( - py: Python, - value: PyResult, -) -> as CallbackConverter>::Result { - PyObjectCallbackConverter::::convert_result(py, value) +pub fn callback_error() -> T +where + T: PyCallbackOutput, +{ + T::ERR_VALUE } -#[inline] -pub unsafe fn cb_err(_c: C, py: Python, err: impl Into) -> C::Result +#[doc(hidden)] +pub fn run_callback(py: Python, callback: F) -> T where - C: CallbackConverter, + F: FnOnce() -> PyResult, + T: PyCallbackOutput, { - err.into().restore(py); - C::ERR_VALUE + callback().unwrap_or_else(|e| { + e.restore(py); + T::ERR_VALUE + }) } diff --git a/src/class/basic.rs b/src/class/basic.rs index 722d5a31..2f1a16b5 100644 --- a/src/class/basic.rs +++ b/src/class/basic.rs @@ -8,11 +8,11 @@ //! Parts of the documentation are copied from the respective methods from the //! [typeobj docs](https://docs.python.org/3/c-api/typeobj.html) -use crate::callback::{BoolCallbackConverter, HashConverter, PyObjectCallbackConverter}; +use crate::callback::HashCallbackOutput; use crate::class::methods::PyMethodDef; use crate::{ - exceptions, ffi, FromPyObject, IntoPy, IntoPyPointer, ObjectProtocol, PyAny, PyClass, PyErr, - PyObject, PyResult, Python, + callback, exceptions, ffi, run_callback, FromPyObject, GILPool, IntoPy, ObjectProtocol, PyAny, + PyCell, PyClass, PyErr, PyObject, PyResult, Python, }; use std::os::raw::c_int; @@ -219,27 +219,23 @@ where T: for<'p> PyObjectGetAttrProtocol<'p>, { let py = Python::assume_gil_acquired(); - let _pool = crate::GILPool::new(py); + run_callback(py, || { + let _pool = GILPool::new(py); - // Behave like python's __getattr__ (as opposed to __getattribute__) and check - // for existing fields and methods first - let existing = ffi::PyObject_GenericGetAttr(slf, arg); - if existing.is_null() { - // PyObject_HasAttr also tries to get an object and clears the error if it fails - ffi::PyErr_Clear(); - } else { - return existing; - } + // Behave like python's __getattr__ (as opposed to __getattribute__) and check + // for existing fields and methods first + let existing = ffi::PyObject_GenericGetAttr(slf, arg); + if existing.is_null() { + // PyObject_HasAttr also tries to get an object and clears the error if it fails + ffi::PyErr_Clear(); + } else { + return Ok(existing); + } - let slf = py.from_borrowed_ptr::>(slf); - let arg = py.from_borrowed_ptr::(arg); - call_ref_with_converter!( - slf, - PyObjectCallbackConverter::(std::marker::PhantomData), - py, - __getattr__, - arg - ) + let slf = py.from_borrowed_ptr::>(slf); + let arg = py.from_borrowed_ptr::(arg); + callback::convert(py, call_ref!(slf, __getattr__, arg)) + }) } Some(wrap::) } @@ -357,11 +353,7 @@ where T: for<'p> PyObjectStrProtocol<'p>, { fn tp_str() -> Option { - py_unary_func!( - PyObjectStrProtocol, - T::__str__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_unary_func!(PyObjectStrProtocol, T::__str__) } } @@ -381,11 +373,7 @@ where T: for<'p> PyObjectReprProtocol<'p>, { fn tp_repr() -> Option { - py_unary_func!( - PyObjectReprProtocol, - T::__repr__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_unary_func!(PyObjectReprProtocol, T::__repr__) } } @@ -447,8 +435,8 @@ where py_unary_func!( PyObjectHashProtocol, T::__hash__, - HashConverter::(std::marker::PhantomData), - ffi::Py_hash_t + ffi::Py_hash_t, + HashCallbackOutput ) } } @@ -469,12 +457,7 @@ where T: for<'p> PyObjectBoolProtocol<'p>, { fn nb_bool() -> Option { - py_unary_func!( - PyObjectBoolProtocol, - T::__bool__, - BoolCallbackConverter, - c_int - ) + py_unary_func!(PyObjectBoolProtocol, T::__bool__, c_int) } } @@ -503,26 +486,17 @@ where T: for<'p> PyObjectRichcmpProtocol<'p>, { let py = Python::assume_gil_acquired(); - let _pool = crate::GILPool::new(py); - let slf = py.from_borrowed_ptr::>(slf); - let arg = py.from_borrowed_ptr::(arg); + run_callback(py, || { + let _pool = GILPool::new(py); + let slf = py.from_borrowed_ptr::>(slf); + let arg = py.from_borrowed_ptr::(arg); - match slf.try_borrow() { - Ok(borrowed_slf) => { - let res = match extract_op(op) { - Ok(op) => match arg.extract() { - Ok(arg) => borrowed_slf.__richcmp__(arg, op).into(), - Err(e) => Err(e), - }, - Err(e) => Err(e), - }; - match res { - Ok(val) => val.into_py(py).into_ptr(), - Err(e) => e.restore_and_null(py), - } - } - Err(e) => PyErr::from(e).restore_and_null(py), - } + let borrowed_slf = slf.try_borrow()?; + let op = extract_op(op)?; + let arg = arg.extract()?; + let result = borrowed_slf.__richcmp__(arg, op).into(); + callback::convert(py, result) + }) } Some(wrap::) } diff --git a/src/class/buffer.rs b/src/class/buffer.rs index 54e496a1..2177974f 100644 --- a/src/class/buffer.rs +++ b/src/class/buffer.rs @@ -4,9 +4,9 @@ //! //! For more information check [buffer protocol](https://docs.python.org/3/c-api/buffer.html) //! c-api -use crate::callback::UnitCallbackConverter; use crate::err::PyResult; -use crate::{ffi, PyClass, PyRefMut}; +use crate::gil::GILPool; +use crate::{callback, ffi, run_callback, PyCell, PyClass, PyRefMut, Python}; use std::os::raw::c_int; /// Buffer protocol interface @@ -91,14 +91,13 @@ where where T: for<'p> PyBufferGetBufferProtocol<'p>, { - let py = crate::Python::assume_gil_acquired(); - let _pool = crate::GILPool::new(py); - let slf = py.from_borrowed_ptr::>(slf); - let result = slf - .try_borrow_mut() - .map_err(crate::PyErr::from) - .and_then(|slf_mut| T::bf_getbuffer(slf_mut, arg1, arg2).into()); - crate::callback::cb_convert(UnitCallbackConverter, py, result) + let py = Python::assume_gil_acquired(); + run_callback(py, || { + let _pool = GILPool::new(py); + let slf = py.from_borrowed_ptr::>(slf); + let result = T::bf_getbuffer(slf.try_borrow_mut()?, arg1, arg2).into(); + callback::convert(py, result) + }) } Some(wrap::) } @@ -127,14 +126,13 @@ where where T: for<'p> PyBufferReleaseBufferProtocol<'p>, { - let py = crate::Python::assume_gil_acquired(); - let _pool = crate::GILPool::new(py); - let slf = py.from_borrowed_ptr::>(slf); - let result = slf - .try_borrow_mut() - .map_err(crate::PyErr::from) - .and_then(|slf_mut| T::bf_releasebuffer(slf_mut, arg1).into()); - crate::callback::cb_convert(UnitCallbackConverter, py, result); + let py = Python::assume_gil_acquired(); + run_callback(py, || { + let _pool = GILPool::new(py); + let slf = py.from_borrowed_ptr::>(slf); + let result = T::bf_releasebuffer(slf.try_borrow_mut()?, arg1).into(); + crate::callback::convert(py, result) + }) } Some(wrap::) } diff --git a/src/class/descr.rs b/src/class/descr.rs index 61c2e51c..fb36b72a 100644 --- a/src/class/descr.rs +++ b/src/class/descr.rs @@ -5,7 +5,6 @@ //! [Python information]( //! https://docs.python.org/3/reference/datamodel.html#implementing-descriptors) -use crate::callback::{PyObjectCallbackConverter, UnitCallbackConverter}; use crate::class::methods::PyMethodDef; use crate::err::PyResult; use crate::types::{PyAny, PyType}; @@ -84,11 +83,7 @@ where T: for<'p> PyDescrGetProtocol<'p>, { fn tp_descr_get() -> Option { - py_ternary_func!( - PyDescrGetProtocol, - T::__get__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_ternary_func!(PyDescrGetProtocol, T::__get__) } } @@ -108,7 +103,7 @@ where T: for<'p> PyDescrSetProtocol<'p>, { fn tp_descr_set() -> Option { - py_ternary_func!(PyDescrSetProtocol, T::__set__, UnitCallbackConverter, c_int) + py_ternary_func!(PyDescrSetProtocol, T::__set__, c_int) } } diff --git a/src/class/gc.rs b/src/class/gc.rs index b8638808..e6fe3cf7 100644 --- a/src/class/gc.rs +++ b/src/class/gc.rs @@ -98,9 +98,14 @@ where arg, _py: py, }; - match slf.borrow().__traverse__(visit) { - Ok(()) => 0, - Err(PyTraverseError(code)) => code, + + if let Ok(borrow) = slf.try_borrow() { + match borrow.__traverse__(visit) { + Ok(()) => 0, + Err(PyTraverseError(code)) => code, + } + } else { + 0 } } diff --git a/src/class/iter.rs b/src/class/iter.rs index 8d7522e3..0d011d2e 100644 --- a/src/class/iter.rs +++ b/src/class/iter.rs @@ -2,10 +2,9 @@ //! Python Iterator Interface. //! Trait and support implementation for implementing iterators -use crate::callback::{CallbackConverter, PyObjectCallbackConverter}; +use crate::callback::IntoPyCallbackOutput; use crate::err::PyResult; use crate::{ffi, IntoPy, IntoPyPointer, PyClass, PyObject, PyRefMut, Python}; -use std::ptr; /// Python Iterator Interface. /// @@ -77,11 +76,7 @@ where { #[inline] fn tp_iter() -> Option { - py_unary_refmut_func!( - PyIterIterProtocol, - T::__iter__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_unary_refmut_func!(PyIterIterProtocol, T::__iter__) } } @@ -104,31 +99,20 @@ where { #[inline] fn tp_iternext() -> Option { - py_unary_refmut_func!( - PyIterNextProtocol, - T::__next__, - IterNextConverter::(std::marker::PhantomData) - ) + py_unary_refmut_func!(PyIterNextProtocol, T::__next__, IterNextConverter) } } -struct IterNextConverter(std::marker::PhantomData); +struct IterNextConverter(Option); -impl CallbackConverter for IterNextConverter +impl IntoPyCallbackOutput<*mut ffi::PyObject> for IterNextConverter where T: IntoPy, { - type Source = Option; - type Result = *mut ffi::PyObject; - const ERR_VALUE: Self::Result = ptr::null_mut(); - - fn convert(val: Self::Source, py: Python) -> Self::Result { - match val { - Some(val) => val.into_py(py).into_ptr(), - None => unsafe { - ffi::PyErr_SetNone(ffi::PyExc_StopIteration); - ptr::null_mut() - }, + fn convert(self, py: Python) -> PyResult<*mut ffi::PyObject> { + match self.0 { + Some(val) => Ok(val.into_py(py).into_ptr()), + None => Err(crate::exceptions::StopIteration::py_err(())), } } } diff --git a/src/class/macros.rs b/src/class/macros.rs index e304ca8c..8d26cd03 100644 --- a/src/class/macros.rs +++ b/src/class/macros.rs @@ -3,51 +3,44 @@ #[macro_export] #[doc(hidden)] macro_rules! py_unary_func { - ($trait:ident, $class:ident :: $f:ident, $conv: expr) => { - py_unary_func!($trait, $class::$f, $conv, *mut $crate::ffi::PyObject); - }; - // Use call_ref! by default - ($trait:ident, $class:ident :: $f:ident, $conv: expr, $ret_type:ty) => { - py_unary_func!( - $trait, - $class::$f, - $conv, - $ret_type, - call_ref_with_converter - ); - }; - ($trait: ident, - $class:ident :: $f:ident, - $conv: expr, - $ret_type: ty, - $call: ident - ) => {{ + ($trait: ident, $class:ident :: $f:ident, $call:ident, $ret_type: ty $(, $conv:expr)?) => {{ unsafe extern "C" fn wrap(slf: *mut $crate::ffi::PyObject) -> $ret_type where T: for<'p> $trait<'p>, { let py = $crate::Python::assume_gil_acquired(); - let _pool = $crate::GILPool::new(py); - let slf = py.from_borrowed_ptr::<$crate::PyCell>(slf); - $call!(slf, $conv, py, $f) + $crate::run_callback(py, || { + let _pool = $crate::GILPool::new(py); + let slf = py.from_borrowed_ptr::<$crate::PyCell>(slf); + $crate::callback::convert(py, $call!(slf, $f)$(.map($conv))?) + }) } Some(wrap::<$class>) }}; + // Use call_ref! by default + ($trait:ident, $class:ident :: $f:ident, $ret_type:ty $(, $conv:expr)?) => { + py_unary_func!($trait, $class::$f, call_ref, $ret_type $(, $conv)?); + }; + ($trait:ident, $class:ident :: $f:ident $(, $conv:expr)?) => { + py_unary_func!($trait, $class::$f, call_ref, *mut $crate::ffi::PyObject $(, $conv)?); + }; } #[macro_export] #[doc(hidden)] macro_rules! py_unary_refmut_func { - ($trait:ident, $class:ident :: $f:ident, $conv:expr) => {{ + ($trait:ident, $class:ident :: $f:ident $(, $conv:expr)?) => {{ unsafe extern "C" fn wrap(slf: *mut $crate::ffi::PyObject) -> *mut $crate::ffi::PyObject where T: for<'p> $trait<'p>, { let py = $crate::Python::assume_gil_acquired(); - let _pool = $crate::GILPool::new(py); - let slf = py.from_borrowed_ptr::<$crate::PyCell>(slf); - let res = $class::$f(slf.borrow_mut()).into(); - $crate::callback::cb_convert($conv, py, res) + $crate::run_callback(py, || { + let _pool = $crate::GILPool::new(py); + let slf = py.from_borrowed_ptr::<$crate::PyCell>(slf); + let res = $class::$f(slf.borrow_mut()).into(); + $crate::callback::convert(py, res $(.map($conv))?) + }) } Some(wrap::<$class>) }}; @@ -56,51 +49,48 @@ macro_rules! py_unary_refmut_func { #[macro_export] #[doc(hidden)] macro_rules! py_len_func { - ($trait:ident, $class:ident :: $f:ident, $conv:expr) => {{ - unsafe extern "C" fn wrap(slf: *mut $crate::ffi::PyObject) -> $crate::ffi::Py_ssize_t - where - T: for<'p> $trait<'p>, - { - let py = Python::assume_gil_acquired(); - let _pool = $crate::GILPool::new(py); - let slf = py.from_borrowed_ptr::<$crate::PyCell>(slf); - let result = call_ref!(slf, $f); - $crate::callback::cb_convert($conv, py, result) - } - Some(wrap::<$class>) - }}; + ($trait:ident, $class:ident :: $f:ident) => { + py_unary_func!( + $trait, + $class::$f, + $crate::ffi::Py_ssize_t, + $crate::callback::LenCallbackOutput + ) + }; } #[macro_export] #[doc(hidden)] macro_rules! py_binary_func { - ($trait:ident, $class:ident :: $f:ident, $conv:expr) => { - py_binary_func!($trait, $class::$f, $conv, *mut $crate::ffi::PyObject) - }; // Use call_ref! by default - ($trait:ident, $class:ident :: $f:ident, $conv:expr, $return:ty) => {{ - py_binary_func!($trait, $class::$f, $conv, $return, call_ref_with_converter) - }}; - ($trait:ident, $class:ident :: $f:ident, $conv:expr, $return:ty, $call:ident) => {{ + ($trait:ident, $class:ident :: $f:ident, $return:ty, $call:ident $(, $conv:expr)?) => {{ unsafe extern "C" fn wrap(slf: *mut ffi::PyObject, arg: *mut ffi::PyObject) -> $return where T: for<'p> $trait<'p>, { use $crate::ObjectProtocol; let py = $crate::Python::assume_gil_acquired(); - let _pool = $crate::GILPool::new(py); - let slf = py.from_borrowed_ptr::<$crate::PyCell>(slf); - let arg = py.from_borrowed_ptr::<$crate::PyAny>(arg); - $call!(slf, $conv, py, $f, arg) + $crate::run_callback(py, || { + let _pool = $crate::GILPool::new(py); + let slf = py.from_borrowed_ptr::<$crate::PyCell>(slf); + let arg = py.from_borrowed_ptr::<$crate::PyAny>(arg); + $crate::callback::convert(py, $call!(slf, $f, arg)$(.map($conv))?) + }) } Some(wrap::<$class>) }}; + ($trait:ident, $class:ident :: $f:ident, $return:ty $(, $conv:expr)?) => { + py_binary_func!($trait, $class::$f, $return, call_ref $(, $conv)?) + }; + ($trait:ident, $class:ident :: $f:ident $(, $conv:expr)?) => { + py_binary_func!($trait, $class::$f, *mut $crate::ffi::PyObject $(, $conv)?) + }; } #[macro_export] #[doc(hidden)] macro_rules! py_binary_num_func { - ($trait:ident, $class:ident :: $f:ident, $conv:expr) => {{ + ($trait:ident, $class:ident :: $f:ident) => {{ unsafe extern "C" fn wrap( lhs: *mut ffi::PyObject, rhs: *mut ffi::PyObject, @@ -110,18 +100,42 @@ macro_rules! py_binary_num_func { { use $crate::ObjectProtocol; let py = $crate::Python::assume_gil_acquired(); - let _pool = $crate::GILPool::new(py); - let lhs = py.from_borrowed_ptr::<$crate::PyAny>(lhs); - let rhs = py.from_borrowed_ptr::<$crate::PyAny>(rhs); + $crate::run_callback(py, || { + let _pool = $crate::GILPool::new(py); + let lhs = py.from_borrowed_ptr::<$crate::PyAny>(lhs); + let rhs = py.from_borrowed_ptr::<$crate::PyAny>(rhs); - let result = match lhs.extract() { - Ok(lhs) => match rhs.extract() { - Ok(rhs) => $class::$f(lhs, rhs).into(), - Err(e) => Err(e.into()), - }, - Err(e) => Err(e.into()), - }; - $crate::callback::cb_convert($conv, py, result) + let result = $class::$f(lhs.extract()?, rhs.extract()?).into(); + $crate::callback::convert(py, result) + }) + } + Some(wrap::<$class>) + }}; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! py_binary_reverse_num_func { + ($trait:ident, $class:ident :: $f:ident) => {{ + unsafe extern "C" fn wrap( + lhs: *mut ffi::PyObject, + rhs: *mut ffi::PyObject, + ) -> *mut $crate::ffi::PyObject + where + T: for<'p> $trait<'p>, + { + use $crate::ObjectProtocol; + let py = $crate::Python::assume_gil_acquired(); + $crate::run_callback(py, || { + let _pool = $crate::GILPool::new(py); + // Swap lhs <-> rhs + let slf = py.from_borrowed_ptr::<$crate::PyCell>(rhs); + let arg = py.from_borrowed_ptr::<$crate::PyAny>(lhs); + $crate::callback::convert( + py, + $class::$f(&*slf.try_borrow()?, arg.extract()?).into(), + ) + }) } Some(wrap::<$class>) }}; @@ -142,17 +156,14 @@ macro_rules! py_binary_self_func { use $crate::ObjectProtocol; let py = $crate::Python::assume_gil_acquired(); - let _pool = $crate::GILPool::new(py); - let slf_ = py.from_borrowed_ptr::<$crate::PyCell>(slf); - let arg = py.from_borrowed_ptr::<$crate::PyAny>(arg); - let result = call_mut!(slf_, $f, arg); - match result { - Ok(_) => { - ffi::Py_INCREF(slf); - slf - } - Err(e) => e.restore_and_null(py), - } + $crate::run_callback(py, || { + let _pool = $crate::GILPool::new(py); + let slf_ = py.from_borrowed_ptr::<$crate::PyCell>(slf); + let arg = py.from_borrowed_ptr::<$crate::PyAny>(arg); + call_mut!(slf_, $f, arg)?; + ffi::Py_INCREF(slf); + Ok(slf) + }) } Some(wrap::<$class>) }}; @@ -162,15 +173,10 @@ macro_rules! py_binary_self_func { #[doc(hidden)] macro_rules! py_ssizearg_func { // Use call_ref! by default - ($trait:ident, $class:ident :: $f:ident, $conv:expr) => { - py_ssizearg_func!( - $trait, - $class::$f, - $conv, - call_ref_with_converter - ) + ($trait:ident, $class:ident :: $f:ident) => { + py_ssizearg_func!($trait, $class::$f, call_ref) }; - ($trait:ident, $class:ident :: $f:ident, $conv:expr, $call:ident) => {{ + ($trait:ident, $class:ident :: $f:ident, $call:ident) => {{ unsafe extern "C" fn wrap( slf: *mut ffi::PyObject, arg: $crate::ffi::Py_ssize_t, @@ -179,9 +185,11 @@ macro_rules! py_ssizearg_func { T: for<'p> $trait<'p>, { let py = $crate::Python::assume_gil_acquired(); - let _pool = $crate::GILPool::new(py); - let slf = py.from_borrowed_ptr::<$crate::PyCell>(slf); - $call!(slf, $conv, py, $f ;arg.into()) + $crate::run_callback(py, || { + let _pool = $crate::GILPool::new(py); + let slf = py.from_borrowed_ptr::<$crate::PyCell>(slf); + $crate::callback::convert(py, $call!(slf, $f; arg.into())) + }) } Some(wrap::<$class>) }}; @@ -190,10 +198,7 @@ macro_rules! py_ssizearg_func { #[macro_export] #[doc(hidden)] macro_rules! py_ternary_func { - ($trait:ident, $class:ident :: $f:ident, $conv:expr) => { - py_ternary_func!($trait, $class::$f, $conv, *mut $crate::ffi::PyObject); - }; - ($trait:ident, $class:ident :: $f:ident, $conv:expr, $return_type:ty) => {{ + ($trait:ident, $class:ident :: $f:ident, $return_type:ty) => {{ unsafe extern "C" fn wrap( slf: *mut $crate::ffi::PyObject, arg1: *mut $crate::ffi::PyObject, @@ -205,22 +210,31 @@ macro_rules! py_ternary_func { use $crate::ObjectProtocol; let py = $crate::Python::assume_gil_acquired(); - let _pool = $crate::GILPool::new(py); - let slf = py.from_borrowed_ptr::<$crate::PyCell>(slf); - let arg1 = py.from_borrowed_ptr::<$crate::PyAny>(arg1); - let arg2 = py.from_borrowed_ptr::<$crate::PyAny>(arg2); + $crate::run_callback(py, || { + let _pool = $crate::GILPool::new(py); + let slf = py.from_borrowed_ptr::<$crate::PyCell>(slf); + let arg1 = py + .from_borrowed_ptr::<$crate::types::PyAny>(arg1) + .extract()?; + let arg2 = py + .from_borrowed_ptr::<$crate::types::PyAny>(arg2) + .extract()?; - call_ref_with_converter!(slf, $conv, py, $f, arg1, arg2) + $crate::callback::convert(py, slf.try_borrow()?.$f(arg1, arg2).into()) + }) } Some(wrap::) }}; + ($trait:ident, $class:ident :: $f:ident) => { + py_ternary_func!($trait, $class::$f, *mut $crate::ffi::PyObject); + }; } #[macro_export] #[doc(hidden)] macro_rules! py_ternary_num_func { - ($trait:ident, $class:ident :: $f:ident, $conv:expr) => {{ + ($trait:ident, $class:ident :: $f:ident) => {{ unsafe extern "C" fn wrap( arg1: *mut $crate::ffi::PyObject, arg2: *mut $crate::ffi::PyObject, @@ -232,22 +246,21 @@ macro_rules! py_ternary_num_func { use $crate::ObjectProtocol; let py = $crate::Python::assume_gil_acquired(); - let _pool = $crate::GILPool::new(py); - let arg1 = py.from_borrowed_ptr::<$crate::PyAny>(arg1); - let arg2 = py.from_borrowed_ptr::<$crate::PyAny>(arg2); - let arg3 = py.from_borrowed_ptr::<$crate::PyAny>(arg3); + $crate::run_callback(py, || { + let _pool = $crate::GILPool::new(py); + let arg1 = py + .from_borrowed_ptr::<$crate::types::PyAny>(arg1) + .extract()?; + let arg2 = py + .from_borrowed_ptr::<$crate::types::PyAny>(arg2) + .extract()?; + let arg3 = py + .from_borrowed_ptr::<$crate::types::PyAny>(arg3) + .extract()?; - let result = match arg1.extract() { - Ok(arg1) => match arg2.extract() { - Ok(arg2) => match arg3.extract() { - Ok(arg3) => $class::$f(arg1, arg2, arg3).into(), - Err(e) => Err(e.into()), - }, - Err(e) => Err(e.into()), - }, - Err(e) => Err(e.into()), - }; - $crate::callback::cb_convert($conv, py, result) + let result = $class::$f(arg1, arg2, arg3).into(); + $crate::callback::convert(py, result) + }) } Some(wrap::) @@ -256,12 +269,43 @@ macro_rules! py_ternary_num_func { #[macro_export] #[doc(hidden)] -macro_rules! py_ternary_self_func { +macro_rules! py_ternary_reverse_num_func { + ($trait:ident, $class:ident :: $f:ident) => {{ + unsafe extern "C" fn wrap( + arg1: *mut $crate::ffi::PyObject, + arg2: *mut $crate::ffi::PyObject, + arg3: *mut $crate::ffi::PyObject, + ) -> *mut $crate::ffi::PyObject + where + T: for<'p> $trait<'p>, + { + use $crate::ObjectProtocol; + let py = $crate::Python::assume_gil_acquired(); + $crate::run_callback(py, || { + let _pool = $crate::GILPool::new(py); + // Swap lhs <-> rhs + let slf = py.from_borrowed_ptr::<$crate::PyCell>(arg2); + let slf = slf.try_borrow()?; + let arg1 = py.from_borrowed_ptr::<$crate::PyAny>(arg1); + let arg2 = py.from_borrowed_ptr::<$crate::PyAny>(arg3); + let result = $class::$f(&*slf, arg1.extract()?, arg2.extract()?).into(); + $crate::callback::convert(py, result) + }) + } + Some(wrap::<$class>) + }}; +} + +// NOTE(kngwyu): Somehow __ipow__ causes SIGSEGV in Python < 3.8 when we extract arg2, +// so we ignore it. It's the same as what CPython does. +#[macro_export] +#[doc(hidden)] +macro_rules! py_dummy_ternary_self_func { ($trait:ident, $class:ident :: $f:ident) => {{ unsafe extern "C" fn wrap( slf: *mut $crate::ffi::PyObject, arg1: *mut $crate::ffi::PyObject, - arg2: *mut $crate::ffi::PyObject, + _arg2: *mut $crate::ffi::PyObject, ) -> *mut $crate::ffi::PyObject where T: for<'p> $trait<'p>, @@ -269,17 +313,16 @@ macro_rules! py_ternary_self_func { use $crate::ObjectProtocol; let py = $crate::Python::assume_gil_acquired(); - let _pool = $crate::GILPool::new(py); - let slf_cell = py.from_borrowed_ptr::<$crate::PyCell>(slf); - let arg1 = py.from_borrowed_ptr::<$crate::PyAny>(arg1); - let arg2 = py.from_borrowed_ptr::<$crate::PyAny>(arg2); - let result = call_mut!(slf_cell, $f, arg1, arg2); - match result { - Ok(_) => slf, - Err(e) => e.restore_and_null(py), - } + $crate::run_callback(py, || { + let _pool = $crate::GILPool::new(py); + let slf_cell = py.from_borrowed_ptr::<$crate::PyCell>(slf); + let arg1 = py.from_borrowed_ptr::<$crate::PyAny>(arg1); + call_mut!(slf_cell, $f, arg1)?; + ffi::Py_INCREF(slf); + Ok(slf) + }) } - Some(wrap::) + Some(wrap::<$class>) }}; } @@ -296,25 +339,23 @@ macro_rules! py_func_set { use $crate::ObjectProtocol; let py = $crate::Python::assume_gil_acquired(); - let _pool = $crate::GILPool::new(py); - let slf = py.from_borrowed_ptr::<$crate::PyCell<$generic>>(slf); + $crate::run_callback(py, || { + let _pool = $crate::GILPool::new(py); + let slf = py.from_borrowed_ptr::<$crate::PyCell<$generic>>(slf); - let result = if value.is_null() { - Err($crate::PyErr::new::( - format!( - "Subscript deletion not supported by {:?}", - stringify!($generic) - ), - )) - } else { - let name = py.from_borrowed_ptr::<$crate::PyAny>(name); - let value = py.from_borrowed_ptr::<$crate::PyAny>(value); - call_mut!(slf, $fn_set, name, value) - }; - match result { - Ok(_) => 0, - Err(e) => e.restore_and_minus1(py), - } + if value.is_null() { + Err($crate::PyErr::new::( + format!( + "Subscript deletion not supported by {:?}", + stringify!($generic) + ), + )) + } else { + let name = py.from_borrowed_ptr::<$crate::PyAny>(name); + let value = py.from_borrowed_ptr::<$crate::PyAny>(value); + crate::callback::convert(py, call_mut!(slf, $fn_set, name, value)) + } + }) } Some(wrap::<$generic>) @@ -334,22 +375,21 @@ macro_rules! py_func_del { use $crate::ObjectProtocol; let py = $crate::Python::assume_gil_acquired(); - let _pool = $crate::GILPool::new(py); + $crate::run_callback(py, || { + let _pool = $crate::GILPool::new(py); - let result = if value.is_null() { - let slf = py.from_borrowed_ptr::<$crate::PyCell>(slf); - let name = py.from_borrowed_ptr::<$crate::PyAny>(name); - - call_mut!(slf, $fn_del, name) - } else { - Err(PyErr::new::( - "Subscript assignment not supported", - )) - }; - match result { - Ok(_) => 0, - Err(e) => e.restore_and_minus1(py), - } + if value.is_null() { + let slf = py.from_borrowed_ptr::<$crate::PyCell>(slf); + let name = py + .from_borrowed_ptr::<$crate::types::PyAny>(name) + .extract()?; + $crate::callback::convert(py, slf.try_borrow_mut()?.$fn_del(name).into()) + } else { + Err(PyErr::new::( + "Subscript assignment not supported", + )) + } + }) } Some(wrap::<$generic>) @@ -369,71 +409,43 @@ macro_rules! py_func_set_del { use $crate::ObjectProtocol; let py = $crate::Python::assume_gil_acquired(); - let _pool = $crate::GILPool::new(py); - let slf = py.from_borrowed_ptr::<$crate::PyCell<$generic>>(slf); - let name = py.from_borrowed_ptr::<$crate::PyAny>(name); + $crate::run_callback(py, || { + let _pool = $crate::GILPool::new(py); + let slf = py.from_borrowed_ptr::<$crate::PyCell<$generic>>(slf); + let name = py.from_borrowed_ptr::<$crate::PyAny>(name); - let result = if value.is_null() { - call_mut!(slf, $fn_del, name) - } else { - let value = py.from_borrowed_ptr::<$crate::PyAny>(value); - call_mut!(slf, $fn_set, name, value) - }; - match result { - Ok(_) => 0, - Err(e) => e.restore_and_minus1(py), - } + let result = if value.is_null() { + call_mut!(slf, $fn_del, name) + } else { + let value = py.from_borrowed_ptr::<$crate::PyAny>(value); + call_mut!(slf, $fn_set, name, value) + }; + $crate::callback::convert(py, result) + }) } Some(wrap::<$generic>) }}; } macro_rules! _call_impl { - ($slf: ident, $fn: ident $(; $args: expr)*) => { $slf.$fn($($args,)*).into() }; - ($slf: ident, $fn: ident, $raw_arg: expr $(,$raw_args: expr)* $(; $args: expr)*) => { - match $raw_arg.extract() { - Ok(arg) => _call_impl!($slf, $fn $(,$raw_args)* $(;$args)* ;arg), - Err(e) => Err(e.into()), - } + ($slf: expr, $fn: ident $(; $args: expr)*) => { + $slf.$fn($($args,)*).into() + }; + ($slf: expr, $fn: ident, $raw_arg: expr $(,$raw_args: expr)* $(; $args: expr)*) => { + _call_impl!($slf, $fn $(,$raw_args)* $(;$args)* ;$raw_arg.extract()?) }; } /// Call `slf.try_borrow()?.$fn(...)` macro_rules! call_ref { ($slf: expr, $fn: ident $(,$raw_args: expr)* $(; $args: expr)*) => { - match $slf.try_borrow() { - Ok(slf) => _call_impl!(slf, $fn $(,$raw_args)* $(;$args)*), - Err(e) => Err(e.into()), - } - }; -} - -/// Call `slf.try_borrow()?.$fn(...)` and returns the result using the given CallbackConverter -macro_rules! call_ref_with_converter { - ($slf: expr, $conv: expr, $py: ident, $fn: ident $(,$raw_args: expr)* $(; $args: expr)*) => { - match $slf.try_borrow() { - Ok(slf) => $crate::callback::cb_convert($conv, $py, _call_impl!(slf, $fn $(,$raw_args)* $(;$args)*)), - Err(e) => $crate::callback::cb_err($conv, $py, e) - } + _call_impl!($slf.try_borrow()?, $fn $(,$raw_args)* $(;$args)*) }; } /// Call `slf.try_borrow_mut()?.$fn(...)` macro_rules! call_mut { ($slf: expr, $fn: ident $(,$raw_args: expr)* $(; $args: expr)*) => { - match $slf.try_borrow_mut() { - Ok(mut slf) => _call_impl!(slf, $fn $(,$raw_args)* $(;$args)*), - Err(e) => Err(e.into()), - } - }; -} - -/// Call `slf.try_borrow_mut()?.$fn(...)` and returns the result using the given CallbackConverter -macro_rules! call_mut_with_converter { - ($slf: expr, $conv: expr, $py: ident, $fn: ident $(,$raw_args: expr)* $(; $args: expr)*) => { - match $slf.try_borrow_mut() { - Ok(mut slf) => $crate::callback::cb_convert($conv, $py, _call_impl!(slf, $fn $(,$raw_args)* $(;$args)*)), - Err(e) => $crate::callback::cb_err($conv, $py, e) - } + _call_impl!($slf.try_borrow_mut()?, $fn $(,$raw_args)* $(;$args)*) }; } diff --git a/src/class/mapping.rs b/src/class/mapping.rs index 39373134..4d82a9dd 100644 --- a/src/class/mapping.rs +++ b/src/class/mapping.rs @@ -3,10 +3,9 @@ //! Python Mapping Interface //! Trait and support implementation for implementing mapping support -use crate::callback::{LenResultConverter, PyObjectCallbackConverter}; use crate::class::methods::PyMethodDef; use crate::err::{PyErr, PyResult}; -use crate::{exceptions, ffi, FromPyObject, IntoPy, PyClass, PyObject, Python}; +use crate::{exceptions, ffi, FromPyObject, IntoPy, PyClass, PyObject}; /// Mapping interface #[allow(unused_variables)] @@ -141,7 +140,7 @@ where { #[inline] fn mp_length() -> Option { - py_len_func!(PyMappingLenProtocol, T::__len__, LenResultConverter) + py_len_func!(PyMappingLenProtocol, T::__len__) } } @@ -164,11 +163,7 @@ where { #[inline] fn mp_subscript() -> Option { - py_binary_func!( - PyMappingGetItemProtocol, - T::__getitem__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_binary_func!(PyMappingGetItemProtocol, T::__getitem__) } } diff --git a/src/class/number.rs b/src/class/number.rs index 1be54f54..207a5b3a 100644 --- a/src/class/number.rs +++ b/src/class/number.rs @@ -3,7 +3,6 @@ //! Python Number Interface //! Trait and support implementation for implementing number protocol -use crate::callback::PyObjectCallbackConverter; use crate::class::basic::PyObjectProtocolImpl; use crate::class::methods::PyMethodDef; use crate::err::PyResult; @@ -60,7 +59,7 @@ pub trait PyNumberProtocol<'p>: PyClass { { unimplemented!() } - fn __pow__(lhs: Self::Left, rhs: Self::Right, modulo: Self::Modulo) -> Self::Result + fn __pow__(lhs: Self::Left, rhs: Self::Right, modulo: Option) -> Self::Result where Self: PyNumberPowProtocol<'p>, { @@ -145,7 +144,7 @@ pub trait PyNumberProtocol<'p>: PyClass { { unimplemented!() } - fn __rpow__(&'p self, other: Self::Other) -> Self::Result + fn __rpow__(&'p self, other: Self::Other, modulo: Option) -> Self::Result where Self: PyNumberRPowProtocol<'p>, { @@ -224,7 +223,7 @@ pub trait PyNumberProtocol<'p>: PyClass { { unimplemented!() } - fn __ipow__(&'p mut self, other: Self::Other, modulo: Self::Modulo) -> Self::Result + fn __ipow__(&'p mut self, other: Self::Other) -> Self::Result where Self: PyNumberIPowProtocol<'p>, { @@ -304,18 +303,18 @@ pub trait PyNumberProtocol<'p>: PyClass { { unimplemented!() } - fn __round__(&'p self) -> Self::Result - where - Self: PyNumberRoundProtocol<'p>, - { - unimplemented!() - } fn __index__(&'p self) -> Self::Result where Self: PyNumberIndexProtocol<'p>, { unimplemented!() } + fn __round__(&'p self, ndigits: Option) -> Self::Result + where + Self: PyNumberRoundProtocol<'p>, + { + unimplemented!() + } } pub trait PyNumberAddProtocol<'p>: PyNumberProtocol<'p> { @@ -544,7 +543,6 @@ pub trait PyNumberIDivmodProtocol<'p>: PyNumberProtocol<'p> { pub trait PyNumberIPowProtocol<'p>: PyNumberProtocol<'p> { type Other: FromPyObject<'p>; - type Modulo: FromPyObject<'p>; type Result: Into>; } @@ -610,6 +608,7 @@ pub trait PyNumberFloatProtocol<'p>: PyNumberProtocol<'p> { pub trait PyNumberRoundProtocol<'p>: PyNumberProtocol<'p> { type Success: IntoPy; + type NDigits: FromPyObject<'p>; type Result: Into>; } @@ -647,22 +646,22 @@ where { fn tp_as_number() -> Option { Some(ffi::PyNumberMethods { - nb_add: Self::nb_add(), - nb_subtract: Self::nb_subtract(), - nb_multiply: Self::nb_multiply(), + nb_add: Self::nb_add().or_else(Self::nb_add_fallback), + nb_subtract: Self::nb_subtract().or_else(Self::nb_sub_fallback), + nb_multiply: Self::nb_multiply().or_else(Self::nb_mul_fallback), nb_remainder: Self::nb_remainder(), - nb_divmod: Self::nb_divmod(), - nb_power: Self::nb_power(), + nb_divmod: Self::nb_divmod().or_else(Self::nb_divmod_fallback), + nb_power: Self::nb_power().or_else(Self::nb_pow_fallback), nb_negative: Self::nb_negative(), nb_positive: Self::nb_positive(), nb_absolute: Self::nb_absolute(), nb_bool: ::nb_bool_fn(), nb_invert: Self::nb_invert(), - nb_lshift: Self::nb_lshift(), - nb_rshift: Self::nb_rshift(), - nb_and: Self::nb_and(), - nb_xor: Self::nb_xor(), - nb_or: Self::nb_or(), + nb_lshift: Self::nb_lshift().or_else(Self::nb_lshift_fallback), + nb_rshift: Self::nb_rshift().or_else(Self::nb_rshift_fallback), + nb_and: Self::nb_and().or_else(Self::nb_and_fallback), + nb_xor: Self::nb_xor().or_else(Self::nb_xor_fallback), + nb_or: Self::nb_or().or_else(Self::nb_or_fallback), nb_int: Self::nb_int(), nb_reserved: ::std::ptr::null_mut(), nb_float: Self::nb_float(), @@ -676,12 +675,12 @@ where nb_inplace_and: Self::nb_inplace_and(), nb_inplace_xor: Self::nb_inplace_xor(), nb_inplace_or: Self::nb_inplace_or(), - nb_floor_divide: Self::nb_floor_divide(), - nb_true_divide: Self::nb_true_divide(), + nb_floor_divide: Self::nb_floor_divide().or_else(Self::nb_floordiv_fallback), + nb_true_divide: Self::nb_true_divide().or_else(Self::nb_truediv_fallback), nb_inplace_floor_divide: Self::nb_inplace_floor_divide(), nb_inplace_true_divide: Self::nb_inplace_true_divide(), nb_index: Self::nb_index(), - nb_matrix_multiply: Self::nb_matrix_multiply(), + nb_matrix_multiply: Self::nb_matrix_multiply().or_else(Self::nb_matmul_fallback), nb_inplace_matrix_multiply: Self::nb_inplace_matrix_multiply(), }) } @@ -761,11 +760,7 @@ where T: for<'p> PyNumberAddProtocol<'p>, { fn nb_add() -> Option { - py_binary_num_func!( - PyNumberAddProtocol, - T::__add__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_binary_num_func!(PyNumberAddProtocol, T::__add__) } } @@ -787,11 +782,7 @@ where T: for<'p> PyNumberSubProtocol<'p>, { fn nb_subtract() -> Option { - py_binary_num_func!( - PyNumberSubProtocol, - T::__sub__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_binary_num_func!(PyNumberSubProtocol, T::__sub__) } } @@ -813,11 +804,7 @@ where T: for<'p> PyNumberMulProtocol<'p>, { fn nb_multiply() -> Option { - py_binary_num_func!( - PyNumberMulProtocol, - T::__mul__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_binary_num_func!(PyNumberMulProtocol, T::__mul__) } } @@ -839,11 +826,7 @@ where T: for<'p> PyNumberMatmulProtocol<'p>, { fn nb_matrix_multiply() -> Option { - py_binary_num_func!( - PyNumberMatmulProtocol, - T::__matmul__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_binary_num_func!(PyNumberMatmulProtocol, T::__matmul__) } } @@ -865,11 +848,7 @@ where T: for<'p> PyNumberTruedivProtocol<'p>, { fn nb_true_divide() -> Option { - py_binary_num_func!( - PyNumberTruedivProtocol, - T::__truediv__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_binary_num_func!(PyNumberTruedivProtocol, T::__truediv__) } } @@ -891,11 +870,7 @@ where T: for<'p> PyNumberFloordivProtocol<'p>, { fn nb_floor_divide() -> Option { - py_binary_num_func!( - PyNumberFloordivProtocol, - T::__floordiv__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_binary_num_func!(PyNumberFloordivProtocol, T::__floordiv__) } } @@ -917,11 +892,7 @@ where T: for<'p> PyNumberModProtocol<'p>, { fn nb_remainder() -> Option { - py_binary_num_func!( - PyNumberModProtocol, - T::__mod__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_binary_num_func!(PyNumberModProtocol, T::__mod__) } } @@ -943,11 +914,7 @@ where T: for<'p> PyNumberDivmodProtocol<'p>, { fn nb_divmod() -> Option { - py_binary_num_func!( - PyNumberDivmodProtocol, - T::__divmod__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_binary_num_func!(PyNumberDivmodProtocol, T::__divmod__) } } @@ -969,11 +936,7 @@ where T: for<'p> PyNumberPowProtocol<'p>, { fn nb_power() -> Option { - py_ternary_num_func!( - PyNumberPowProtocol, - T::__pow__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_ternary_num_func!(PyNumberPowProtocol, T::__pow__) } } @@ -995,11 +958,7 @@ where T: for<'p> PyNumberLShiftProtocol<'p>, { fn nb_lshift() -> Option { - py_binary_num_func!( - PyNumberLShiftProtocol, - T::__lshift__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_binary_num_func!(PyNumberLShiftProtocol, T::__lshift__) } } @@ -1021,11 +980,7 @@ where T: for<'p> PyNumberRShiftProtocol<'p>, { fn nb_rshift() -> Option { - py_binary_num_func!( - PyNumberRShiftProtocol, - T::__rshift__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_binary_num_func!(PyNumberRShiftProtocol, T::__rshift__) } } @@ -1047,11 +1002,7 @@ where T: for<'p> PyNumberAndProtocol<'p>, { fn nb_and() -> Option { - py_binary_num_func!( - PyNumberAndProtocol, - T::__and__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_binary_num_func!(PyNumberAndProtocol, T::__and__) } } @@ -1073,11 +1024,7 @@ where T: for<'p> PyNumberXorProtocol<'p>, { fn nb_xor() -> Option { - py_binary_num_func!( - PyNumberXorProtocol, - T::__xor__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_binary_num_func!(PyNumberXorProtocol, T::__xor__) } } @@ -1099,11 +1046,7 @@ where T: for<'p> PyNumberOrProtocol<'p>, { fn nb_or() -> Option { - py_binary_num_func!( - PyNumberOrProtocol, - T::__or__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_binary_num_func!(PyNumberOrProtocol, T::__or__) } } @@ -1279,7 +1222,7 @@ where T: for<'p> PyNumberIPowProtocol<'p>, { fn nb_inplace_power() -> Option { - py_ternary_self_func!(PyNumberIPowProtocol, T::__ipow__) + py_dummy_ternary_self_func!(PyNumberIPowProtocol, T::__ipow__) } } @@ -1407,14 +1350,64 @@ where } } -#[doc(hidden)] -pub trait PyNumberRSubProtocolImpl { - fn __rsub__() -> Option { +// Fallback trait for nb_add +trait PyNumberAddFallback { + fn nb_add_fallback() -> Option; +} + +impl<'p, T> PyNumberAddFallback for T +where + T: PyNumberProtocol<'p>, +{ + default fn nb_add_fallback() -> Option { None } } -impl<'p, T> PyNumberRSubProtocolImpl for T where T: PyNumberProtocol<'p> {} +impl PyNumberAddFallback for T +where + T: for<'p> PyNumberRAddProtocol<'p>, +{ + fn nb_add_fallback() -> Option { + py_binary_reverse_num_func!(PyNumberRAddProtocol, T::__radd__) + } +} + +#[doc(hidden)] +pub trait PyNumberRSubProtocolImpl { + fn __rsub__() -> Option; +} + +impl<'p, T> PyNumberRSubProtocolImpl for T +where + T: PyNumberProtocol<'p>, +{ + default fn __rsub__() -> Option { + None + } +} + +trait PyNumberSubFallback { + fn nb_sub_fallback() -> Option; +} + +impl<'p, T> PyNumberSubFallback for T +where + T: PyNumberProtocol<'p>, +{ + default fn nb_sub_fallback() -> Option { + None + } +} + +impl PyNumberSubFallback for T +where + T: for<'p> PyNumberRSubProtocol<'p>, +{ + fn nb_sub_fallback() -> Option { + py_binary_reverse_num_func!(PyNumberRSubProtocol, T::__rsub__) + } +} #[doc(hidden)] pub trait PyNumberRMulProtocolImpl { @@ -1430,6 +1423,28 @@ where } } +trait PyNumberMulFallback { + fn nb_mul_fallback() -> Option; +} + +impl<'p, T> PyNumberMulFallback for T +where + T: PyNumberProtocol<'p>, +{ + default fn nb_mul_fallback() -> Option { + None + } +} + +impl PyNumberMulFallback for T +where + T: for<'p> PyNumberRMulProtocol<'p>, +{ + fn nb_mul_fallback() -> Option { + py_binary_reverse_num_func!(PyNumberRMulProtocol, T::__rmul__) + } +} + #[doc(hidden)] pub trait PyNumberRMatmulProtocolImpl { fn __rmatmul__() -> Option; @@ -1444,6 +1459,28 @@ where } } +trait PyNumberMatmulFallback { + fn nb_matmul_fallback() -> Option; +} + +impl<'p, T> PyNumberMatmulFallback for T +where + T: PyNumberProtocol<'p>, +{ + default fn nb_matmul_fallback() -> Option { + None + } +} + +impl PyNumberMatmulFallback for T +where + T: for<'p> PyNumberRMatmulProtocol<'p>, +{ + fn nb_matmul_fallback() -> Option { + py_binary_reverse_num_func!(PyNumberRMatmulProtocol, T::__rmatmul__) + } +} + #[doc(hidden)] pub trait PyNumberRTruedivProtocolImpl { fn __rtruediv__() -> Option; @@ -1458,6 +1495,28 @@ where } } +trait PyNumberTruedivFallback { + fn nb_truediv_fallback() -> Option; +} + +impl<'p, T> PyNumberTruedivFallback for T +where + T: PyNumberProtocol<'p>, +{ + default fn nb_truediv_fallback() -> Option { + None + } +} + +impl PyNumberTruedivFallback for T +where + T: for<'p> PyNumberRTruedivProtocol<'p>, +{ + fn nb_truediv_fallback() -> Option { + py_binary_reverse_num_func!(PyNumberRTruedivProtocol, T::__rtruediv__) + } +} + #[doc(hidden)] pub trait PyNumberRFloordivProtocolImpl { fn __rfloordiv__() -> Option; @@ -1472,6 +1531,28 @@ where } } +trait PyNumberFloordivFallback { + fn nb_floordiv_fallback() -> Option; +} + +impl<'p, T> PyNumberFloordivFallback for T +where + T: PyNumberProtocol<'p>, +{ + default fn nb_floordiv_fallback() -> Option { + None + } +} + +impl PyNumberFloordivFallback for T +where + T: for<'p> PyNumberRFloordivProtocol<'p>, +{ + fn nb_floordiv_fallback() -> Option { + py_binary_reverse_num_func!(PyNumberRFloordivProtocol, T::__rfloordiv__) + } +} + #[doc(hidden)] pub trait PyNumberRModProtocolImpl { fn __rmod__() -> Option; @@ -1486,6 +1567,28 @@ where } } +trait PyNumberModFallback { + fn nb_mod_fallback() -> Option; +} + +impl<'p, T> PyNumberModFallback for T +where + T: PyNumberProtocol<'p>, +{ + default fn nb_mod_fallback() -> Option { + None + } +} + +impl PyNumberModFallback for T +where + T: for<'p> PyNumberRModProtocol<'p>, +{ + fn nb_mod_fallback() -> Option { + py_binary_reverse_num_func!(PyNumberRModProtocol, T::__rmod__) + } +} + #[doc(hidden)] pub trait PyNumberRDivmodProtocolImpl { fn __rdivmod__() -> Option; @@ -1500,6 +1603,28 @@ where } } +trait PyNumberDivmodFallback { + fn nb_divmod_fallback() -> Option; +} + +impl<'p, T> PyNumberDivmodFallback for T +where + T: PyNumberProtocol<'p>, +{ + default fn nb_divmod_fallback() -> Option { + None + } +} + +impl PyNumberDivmodFallback for T +where + T: for<'p> PyNumberRDivmodProtocol<'p>, +{ + fn nb_divmod_fallback() -> Option { + py_binary_reverse_num_func!(PyNumberRDivmodProtocol, T::__rdivmod__) + } +} + #[doc(hidden)] pub trait PyNumberRPowProtocolImpl { fn __rpow__() -> Option; @@ -1514,6 +1639,28 @@ where } } +trait PyNumberPowFallback { + fn nb_pow_fallback() -> Option; +} + +impl<'p, T> PyNumberPowFallback for T +where + T: PyNumberProtocol<'p>, +{ + default fn nb_pow_fallback() -> Option { + None + } +} + +impl PyNumberPowFallback for T +where + T: for<'p> PyNumberRPowProtocol<'p>, +{ + fn nb_pow_fallback() -> Option { + py_ternary_reverse_num_func!(PyNumberRPowProtocol, T::__rpow__) + } +} + #[doc(hidden)] pub trait PyNumberRLShiftProtocolImpl { fn __rlshift__() -> Option; @@ -1528,6 +1675,28 @@ where } } +trait PyNumberLShiftFallback { + fn nb_lshift_fallback() -> Option; +} + +impl<'p, T> PyNumberLShiftFallback for T +where + T: PyNumberProtocol<'p>, +{ + default fn nb_lshift_fallback() -> Option { + None + } +} + +impl PyNumberLShiftFallback for T +where + T: for<'p> PyNumberRLShiftProtocol<'p>, +{ + fn nb_lshift_fallback() -> Option { + py_binary_reverse_num_func!(PyNumberRLShiftProtocol, T::__rlshift__) + } +} + #[doc(hidden)] pub trait PyNumberRRShiftProtocolImpl { fn __rrshift__() -> Option; @@ -1542,6 +1711,28 @@ where } } +trait PyNumberRRshiftFallback { + fn nb_rshift_fallback() -> Option; +} + +impl<'p, T> PyNumberRRshiftFallback for T +where + T: PyNumberProtocol<'p>, +{ + default fn nb_rshift_fallback() -> Option { + None + } +} + +impl PyNumberRRshiftFallback for T +where + T: for<'p> PyNumberRRShiftProtocol<'p>, +{ + fn nb_rshift_fallback() -> Option { + py_binary_reverse_num_func!(PyNumberRRShiftProtocol, T::__rrshift__) + } +} + #[doc(hidden)] pub trait PyNumberRAndProtocolImpl { fn __rand__() -> Option; @@ -1556,6 +1747,28 @@ where } } +trait PyNumberAndFallback { + fn nb_and_fallback() -> Option; +} + +impl<'p, T> PyNumberAndFallback for T +where + T: PyNumberProtocol<'p>, +{ + default fn nb_and_fallback() -> Option { + None + } +} + +impl PyNumberAndFallback for T +where + T: for<'p> PyNumberRAndProtocol<'p>, +{ + fn nb_and_fallback() -> Option { + py_binary_reverse_num_func!(PyNumberRAndProtocol, T::__rand__) + } +} + #[doc(hidden)] pub trait PyNumberRXorProtocolImpl { fn __rxor__() -> Option; @@ -1570,6 +1783,28 @@ where } } +trait PyNumberXorFallback { + fn nb_xor_fallback() -> Option; +} + +impl<'p, T> PyNumberXorFallback for T +where + T: PyNumberProtocol<'p>, +{ + default fn nb_xor_fallback() -> Option { + None + } +} + +impl PyNumberXorFallback for T +where + T: for<'p> PyNumberRXorProtocol<'p>, +{ + fn nb_xor_fallback() -> Option { + py_binary_reverse_num_func!(PyNumberRXorProtocol, T::__rxor__) + } +} + #[doc(hidden)] pub trait PyNumberROrProtocolImpl { fn __ror__() -> Option; @@ -1584,6 +1819,28 @@ where } } +trait PyNumberOrFallback { + fn nb_or_fallback() -> Option; +} + +impl<'p, T> PyNumberOrFallback for T +where + T: PyNumberProtocol<'p>, +{ + default fn nb_or_fallback() -> Option { + None + } +} + +impl PyNumberOrFallback for T +where + T: for<'p> PyNumberROrProtocol<'p>, +{ + fn nb_or_fallback() -> Option { + py_binary_reverse_num_func!(PyNumberROrProtocol, T::__ror__) + } +} + trait PyNumberNegProtocolImpl { fn nb_negative() -> Option; } @@ -1603,11 +1860,7 @@ where { #[inline] fn nb_negative() -> Option { - py_unary_func!( - PyNumberNegProtocol, - T::__neg__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_unary_func!(PyNumberNegProtocol, T::__neg__) } } @@ -1629,11 +1882,7 @@ where T: for<'p> PyNumberPosProtocol<'p>, { fn nb_positive() -> Option { - py_unary_func!( - PyNumberPosProtocol, - T::__pos__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_unary_func!(PyNumberPosProtocol, T::__pos__) } } @@ -1655,11 +1904,7 @@ where T: for<'p> PyNumberAbsProtocol<'p>, { fn nb_absolute() -> Option { - py_unary_func!( - PyNumberAbsProtocol, - T::__abs__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_unary_func!(PyNumberAbsProtocol, T::__abs__) } } @@ -1681,11 +1926,7 @@ where T: for<'p> PyNumberInvertProtocol<'p>, { fn nb_invert() -> Option { - py_unary_func!( - PyNumberInvertProtocol, - T::__invert__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_unary_func!(PyNumberInvertProtocol, T::__invert__) } } @@ -1707,11 +1948,7 @@ where T: for<'p> PyNumberIntProtocol<'p>, { fn nb_int() -> Option { - py_unary_func!( - PyNumberIntProtocol, - T::__int__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_unary_func!(PyNumberIntProtocol, T::__int__) } } @@ -1733,11 +1970,7 @@ where T: for<'p> PyNumberFloatProtocol<'p>, { fn nb_float() -> Option { - py_unary_func!( - PyNumberFloatProtocol, - T::__float__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_unary_func!(PyNumberFloatProtocol, T::__float__) } } @@ -1759,15 +1992,11 @@ where T: for<'p> PyNumberIndexProtocol<'p>, { fn nb_index() -> Option { - py_unary_func!( - PyNumberIndexProtocol, - T::__index__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_unary_func!(PyNumberIndexProtocol, T::__index__) } } -trait PyNumberComplexProtocolImpl { +pub trait PyNumberComplexProtocolImpl { fn __complex__() -> Option; } @@ -1780,7 +2009,7 @@ where } } -trait PyNumberRoundProtocolImpl { +pub trait PyNumberRoundProtocolImpl { fn __round__() -> Option; } diff --git a/src/class/pyasync.rs b/src/class/pyasync.rs index 3a423ffa..a43dc57c 100644 --- a/src/class/pyasync.rs +++ b/src/class/pyasync.rs @@ -8,7 +8,6 @@ //! [PEP-0492](https://www.python.org/dev/peps/pep-0492/) //! -use crate::callback::PyObjectCallbackConverter; use crate::class::methods::PyMethodDef; use crate::err::PyResult; use crate::{ffi, PyClass, PyObject}; @@ -150,11 +149,7 @@ where { #[inline] fn am_await() -> Option { - py_unary_func!( - PyAsyncAwaitProtocol, - T::__await__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_unary_func!(PyAsyncAwaitProtocol, T::__await__) } } @@ -177,11 +172,7 @@ where { #[inline] fn am_aiter() -> Option { - py_unary_func!( - PyAsyncAiterProtocol, - T::__aiter__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_unary_func!(PyAsyncAiterProtocol, T::__aiter__) } } @@ -200,30 +191,22 @@ where mod anext { use super::{PyAsyncAnextProtocol, PyAsyncAnextProtocolImpl}; - use crate::callback::CallbackConverter; + use crate::callback::IntoPyCallbackOutput; + use crate::err::PyResult; use crate::IntoPyPointer; use crate::Python; use crate::{ffi, IntoPy, PyObject}; - use std::marker::PhantomData; - use std::ptr; - struct IterANextResultConverter(PhantomData); + struct IterANextOutput(Option); - impl CallbackConverter for IterANextResultConverter + impl IntoPyCallbackOutput<*mut ffi::PyObject> for IterANextOutput where T: IntoPy, { - type Source = Option; - type Result = *mut ffi::PyObject; - const ERR_VALUE: Self::Result = ptr::null_mut(); - - fn convert(val: Self::Source, py: Python) -> Self::Result { - match val { - Some(val) => val.into_py(py).into_ptr(), - None => unsafe { - ffi::PyErr_SetNone(ffi::PyExc_StopAsyncIteration); - ptr::null_mut() - }, + fn convert(self, py: Python) -> PyResult<*mut ffi::PyObject> { + match self.0 { + Some(val) => Ok(val.into_py(py).into_ptr()), + None => Err(crate::exceptions::StopAsyncIteration::py_err(())), } } } @@ -237,9 +220,9 @@ mod anext { py_unary_func!( PyAsyncAnextProtocol, T::__anext__, - IterANextResultConverter::(std::marker::PhantomData), + call_mut, *mut crate::ffi::PyObject, - call_mut_with_converter + IterANextOutput ) } } diff --git a/src/class/sequence.rs b/src/class/sequence.rs index 498844b7..eeb23600 100644 --- a/src/class/sequence.rs +++ b/src/class/sequence.rs @@ -3,10 +3,11 @@ //! Python Sequence Interface //! Trait and support implementation for implementing sequence -use crate::callback::{BoolCallbackConverter, LenResultConverter, PyObjectCallbackConverter}; +use crate::conversion::{FromPyObject, IntoPy}; use crate::err::{PyErr, PyResult}; +use crate::gil::GILPool; use crate::objectprotocol::ObjectProtocol; -use crate::{exceptions, ffi, FromPyObject, IntoPy, PyAny, PyClass, PyObject, Python}; +use crate::{callback, exceptions, ffi, run_callback, PyAny, PyCell, PyClass, PyObject, Python}; use std::os::raw::c_int; /// Sequence interface @@ -176,7 +177,7 @@ where T: for<'p> PySequenceLenProtocol<'p>, { fn sq_length() -> Option { - py_len_func!(PySequenceLenProtocol, T::__len__, LenResultConverter) + py_len_func!(PySequenceLenProtocol, T::__len__) } } @@ -198,11 +199,7 @@ where T: for<'p> PySequenceGetItemProtocol<'p>, { fn sq_item() -> Option { - py_ssizearg_func!( - PySequenceGetItemProtocol, - T::__getitem__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_ssizearg_func!(PySequenceGetItemProtocol, T::__getitem__) } } @@ -260,31 +257,23 @@ mod sq_ass_item_impl { T: for<'p> PySequenceSetItemProtocol<'p>, { let py = Python::assume_gil_acquired(); - let _pool = crate::GILPool::new(py); - let slf = py.from_borrowed_ptr::>(slf); + run_callback(py, || { + let _pool = GILPool::new(py); + let slf = py.from_borrowed_ptr::>(slf); - if value.is_null() { - return PyErr::new::(format!( - "Item deletion is not supported by {:?}", - stringify!(T) - )) - .restore_and_minus1(py); - } - - let result = match slf.try_borrow_mut() { - Ok(mut slf) => { - let value = py.from_borrowed_ptr::(value); - match value.extract() { - Ok(value) => slf.__setitem__(key.into(), value).into(), - Err(e) => e.into(), - } + if value.is_null() { + return Err(PyErr::new::(format!( + "Item deletion is not supported by {:?}", + stringify!(T) + ))); } - Err(e) => Err(PyErr::from(e)), - }; - match result { - Ok(_) => 0, - Err(e) => e.restore_and_minus1(py), - } + + let mut slf = slf.try_borrow_mut()?; + let value = py.from_borrowed_ptr::(value); + let value = value.extract()?; + let result = slf.__setitem__(key.into(), value).into(); + callback::convert(py, result) + }) } Some(wrap::) } @@ -317,22 +306,21 @@ mod sq_ass_item_impl { T: for<'p> PySequenceDelItemProtocol<'p>, { let py = Python::assume_gil_acquired(); - let _pool = crate::GILPool::new(py); - let slf = py.from_borrowed_ptr::>(slf); + run_callback(py, || { + let _pool = GILPool::new(py); + let slf = py.from_borrowed_ptr::>(slf); - let result = if value.is_null() { - slf.borrow_mut().__delitem__(key.into()).into() - } else { - Err(PyErr::new::(format!( - "Item assignment not supported by {:?}", - stringify!(T) - ))) - }; + let result = if value.is_null() { + slf.borrow_mut().__delitem__(key.into()).into() + } else { + Err(PyErr::new::(format!( + "Item assignment not supported by {:?}", + stringify!(T) + ))) + }; - match result { - Ok(_) => 0, - Err(e) => e.restore_and_minus1(py), - } + callback::convert(py, result) + }) } Some(wrap::) } @@ -365,25 +353,20 @@ mod sq_ass_item_impl { T: for<'p> PySequenceSetItemProtocol<'p> + for<'p> PySequenceDelItemProtocol<'p>, { let py = Python::assume_gil_acquired(); - let _pool = crate::GILPool::new(py); - let slf = py.from_borrowed_ptr::>(slf); + run_callback(py, || { + let _pool = GILPool::new(py); + let slf = py.from_borrowed_ptr::>(slf); - let result = if value.is_null() { - call_mut!(slf, __delitem__; key.into()) - } else { - let value = py.from_borrowed_ptr::(value); - match slf.try_borrow_mut() { - Ok(mut slf_) => match value.extract() { - Ok(value) => slf_.__setitem__(key.into(), value).into(), - Err(e) => Err(e), - }, - Err(e) => Err(e.into()), - } - }; - match result { - Ok(_) => 0, - Err(e) => e.restore_and_minus1(py), - } + let result = if value.is_null() { + call_mut!(slf, __delitem__; key.into()) + } else { + let value = py.from_borrowed_ptr::(value); + let mut slf_ = slf.try_borrow_mut()?; + let value = value.extract()?; + slf_.__setitem__(key.into(), value).into() + }; + callback::convert(py, result) + }) } Some(wrap::) } @@ -408,12 +391,7 @@ where T: for<'p> PySequenceContainsProtocol<'p>, { fn sq_contains() -> Option { - py_binary_func!( - PySequenceContainsProtocol, - T::__contains__, - BoolCallbackConverter, - c_int - ) + py_binary_func!(PySequenceContainsProtocol, T::__contains__, c_int) } } @@ -435,11 +413,7 @@ where T: for<'p> PySequenceConcatProtocol<'p>, { fn sq_concat() -> Option { - py_binary_func!( - PySequenceConcatProtocol, - T::__concat__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_binary_func!(PySequenceConcatProtocol, T::__concat__) } } @@ -461,11 +435,7 @@ where T: for<'p> PySequenceRepeatProtocol<'p>, { fn sq_repeat() -> Option { - py_ssizearg_func!( - PySequenceRepeatProtocol, - T::__repeat__, - PyObjectCallbackConverter::(std::marker::PhantomData) - ) + py_ssizearg_func!(PySequenceRepeatProtocol, T::__repeat__) } } @@ -490,9 +460,8 @@ where py_binary_func!( PySequenceInplaceConcatProtocol, T::__inplace_concat__, - PyObjectCallbackConverter::(std::marker::PhantomData), - *mut crate::ffi::PyObject, - call_mut_with_converter + *mut ffi::PyObject, + call_mut ) } } @@ -518,8 +487,7 @@ where py_ssizearg_func!( PySequenceInplaceRepeatProtocol, T::__inplace_repeat__, - PyObjectCallbackConverter::(std::marker::PhantomData), - call_mut_with_converter + call_mut ) } } diff --git a/src/err.rs b/src/err.rs index cc0dbcd7..2cdfcac3 100644 --- a/src/err.rs +++ b/src/err.rs @@ -1,15 +1,12 @@ // Copyright (c) 2017-present PyO3 Project and Contributors -use crate::instance::Py; -use crate::object::PyObject; use crate::type_object::PyTypeObject; -use crate::types::{PyAny, PyType}; -use crate::AsPyPointer; -use crate::IntoPyPointer; -use crate::Python; -use crate::{exceptions, IntoPy}; -use crate::{ffi, FromPy}; -use crate::{ToBorrowedObject, ToPyObject}; +use crate::types::PyType; +use crate::{exceptions, ffi}; +use crate::{ + AsPyPointer, FromPy, IntoPy, IntoPyPointer, Py, PyAny, PyObject, Python, ToBorrowedObject, + ToPyObject, +}; use libc::c_int; use std::ffi::CString; use std::io; diff --git a/src/ffi/bytesobject.rs b/src/ffi/bytesobject.rs index b150e3b1..17362e6c 100644 --- a/src/ffi/bytesobject.rs +++ b/src/ffi/bytesobject.rs @@ -37,9 +37,9 @@ extern "C" { pub fn PyBytes_AsString(arg1: *mut PyObject) -> *mut c_char; pub fn PyBytes_Repr(arg1: *mut PyObject, arg2: c_int) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyBytes_Concat")] - pub fn PyBytes_Concat(arg1: *mut *mut PyObject, arg2: *mut PyObject) -> (); + pub fn PyBytes_Concat(arg1: *mut *mut PyObject, arg2: *mut PyObject); #[cfg_attr(PyPy, link_name = "PyPyBytes_ConcatAndDel")] - pub fn PyBytes_ConcatAndDel(arg1: *mut *mut PyObject, arg2: *mut PyObject) -> (); + pub fn PyBytes_ConcatAndDel(arg1: *mut *mut PyObject, arg2: *mut PyObject); pub fn PyBytes_DecodeEscape( arg1: *const c_char, arg2: Py_ssize_t, diff --git a/src/ffi/ceval.rs b/src/ffi/ceval.rs index f5265c75..df815ee3 100644 --- a/src/ffi/ceval.rs +++ b/src/ffi/ceval.rs @@ -45,7 +45,7 @@ extern "C" { #[cfg_attr(PyPy, link_name = "PyPy_MakePendingCalls")] pub fn Py_MakePendingCalls() -> c_int; #[cfg_attr(PyPy, link_name = "PyPy_SetRecursionLimit")] - pub fn Py_SetRecursionLimit(arg1: c_int) -> (); + pub fn Py_SetRecursionLimit(arg1: c_int); #[cfg_attr(PyPy, link_name = "PyPy_GetRecursionLimit")] pub fn Py_GetRecursionLimit() -> c_int; fn _Py_CheckRecursiveCall(_where: *mut c_char) -> c_int; @@ -74,7 +74,7 @@ extern "C" { #[cfg_attr(PyPy, link_name = "PyPyEval_SaveThread")] pub fn PyEval_SaveThread() -> *mut PyThreadState; #[cfg_attr(PyPy, link_name = "PyPyEval_RestoreThread")] - pub fn PyEval_RestoreThread(arg1: *mut PyThreadState) -> (); + pub fn PyEval_RestoreThread(arg1: *mut PyThreadState); } #[cfg(py_sys_config = "WITH_THREAD")] @@ -83,13 +83,13 @@ extern "C" { #[cfg_attr(PyPy, link_name = "PyPyEval_ThreadsInitialized")] pub fn PyEval_ThreadsInitialized() -> c_int; #[cfg_attr(PyPy, link_name = "PyPyEval_InitThreads")] - pub fn PyEval_InitThreads() -> (); - pub fn PyEval_AcquireLock() -> (); - pub fn PyEval_ReleaseLock() -> (); + pub fn PyEval_InitThreads(); + pub fn PyEval_AcquireLock(); + pub fn PyEval_ReleaseLock(); #[cfg_attr(PyPy, link_name = "PyPyEval_AcquireThread")] - pub fn PyEval_AcquireThread(tstate: *mut PyThreadState) -> (); + pub fn PyEval_AcquireThread(tstate: *mut PyThreadState); #[cfg_attr(PyPy, link_name = "PyPyEval_ReleaseThread")] - pub fn PyEval_ReleaseThread(tstate: *mut PyThreadState) -> (); + pub fn PyEval_ReleaseThread(tstate: *mut PyThreadState); #[cfg(not(Py_3_8))] - pub fn PyEval_ReInitThreads() -> (); + pub fn PyEval_ReInitThreads(); } diff --git a/src/ffi/dictobject.rs b/src/ffi/dictobject.rs index 046f8896..995e61f4 100644 --- a/src/ffi/dictobject.rs +++ b/src/ffi/dictobject.rs @@ -69,6 +69,8 @@ pub unsafe fn PyDictViewSet_Check(op: *mut PyObject) -> 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; @@ -84,7 +86,7 @@ extern "C" { #[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")] - pub fn PyDict_Clear(mp: *mut PyObject) -> (); + pub fn PyDict_Clear(mp: *mut PyObject); #[cfg_attr(PyPy, link_name = "PyPyDict_Next")] pub fn PyDict_Next( mp: *mut PyObject, diff --git a/src/ffi/frameobject.rs b/src/ffi/frameobject.rs index ff564977..3e459a0b 100644 --- a/src/ffi/frameobject.rs +++ b/src/ffi/frameobject.rs @@ -65,17 +65,12 @@ extern "C" { locals: *mut PyObject, ) -> *mut PyFrameObject; - pub fn PyFrame_BlockSetup( - f: *mut PyFrameObject, - _type: c_int, - handler: c_int, - level: c_int, - ) -> (); + 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; - pub fn PyFrame_LocalsToFast(f: *mut PyFrameObject, clear: c_int) -> (); + pub fn PyFrame_LocalsToFast(f: *mut PyFrameObject, clear: c_int); pub fn PyFrame_FastToLocalsWithError(f: *mut PyFrameObject) -> c_int; - pub fn PyFrame_FastToLocals(f: *mut PyFrameObject) -> (); + pub fn PyFrame_FastToLocals(f: *mut PyFrameObject); pub fn PyFrame_ClearFreeList() -> c_int; pub fn PyFrame_GetLineNumber(f: *mut PyFrameObject) -> c_int; diff --git a/src/ffi/import.rs b/src/ffi/import.rs index b72c6526..a96bb911 100644 --- a/src/ffi/import.rs +++ b/src/ffi/import.rs @@ -68,7 +68,7 @@ extern "C" { pub fn PyImport_Import(name: *mut PyObject) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyImport_ReloadModule")] pub fn PyImport_ReloadModule(m: *mut PyObject) -> *mut PyObject; - pub fn PyImport_Cleanup() -> (); + pub fn PyImport_Cleanup(); pub fn PyImport_ImportFrozenModuleObject(name: *mut PyObject) -> c_int; pub fn PyImport_ImportFrozenModule(name: *const c_char) -> c_int; diff --git a/src/ffi/intrcheck.rs b/src/ffi/intrcheck.rs index 4e1e3088..d4710c3a 100644 --- a/src/ffi/intrcheck.rs +++ b/src/ffi/intrcheck.rs @@ -4,7 +4,7 @@ use std::os::raw::c_int; extern "C" { #[cfg_attr(PyPy, link_name = "PyPyOS_InterruptOccurred")] pub fn PyOS_InterruptOccurred() -> c_int; - pub fn PyOS_InitInterrupts() -> (); + pub fn PyOS_InitInterrupts(); #[cfg_attr(PyPy, link_name = "PyPyOS_AfterFork")] - pub fn PyOS_AfterFork() -> (); + pub fn PyOS_AfterFork(); } diff --git a/src/ffi/object.rs b/src/ffi/object.rs index 6ceb6d3b..67fd1133 100644 --- a/src/ffi/object.rs +++ b/src/ffi/object.rs @@ -165,7 +165,7 @@ mod bufferinfo { arg3: c_int, ) -> c_int; pub type releasebufferproc = - unsafe extern "C" fn(arg1: *mut crate::ffi::PyObject, arg2: *mut Py_buffer) -> (); + unsafe extern "C" fn(arg1: *mut crate::ffi::PyObject, arg2: *mut Py_buffer); /// Maximum number of dimensions pub const PyBUF_MAX_NDIM: c_int = 64; @@ -829,9 +829,9 @@ extern "C" { #[cfg_attr(PyPy, link_name = "PyPyCallable_Check")] pub fn PyCallable_Check(arg1: *mut PyObject) -> c_int; #[cfg_attr(PyPy, link_name = "PyPyObject_ClearWeakRefs")] - pub fn PyObject_ClearWeakRefs(arg1: *mut PyObject) -> (); + pub fn PyObject_ClearWeakRefs(arg1: *mut PyObject); #[cfg(not(Py_LIMITED_API))] - pub fn PyObject_CallFinalizer(arg1: *mut PyObject) -> (); + pub fn PyObject_CallFinalizer(arg1: *mut PyObject); #[cfg(not(Py_LIMITED_API))] #[cfg_attr(PyPy, link_name = "PyPyObject_CallFinalizerFromDealloc")] pub fn PyObject_CallFinalizerFromDealloc(arg1: *mut PyObject) -> c_int; @@ -839,7 +839,7 @@ extern "C" { #[cfg_attr(PyPy, link_name = "PyPyObject_Dir")] pub fn PyObject_Dir(arg1: *mut PyObject) -> *mut PyObject; pub fn Py_ReprEnter(arg1: *mut PyObject) -> c_int; - pub fn Py_ReprLeave(arg1: *mut PyObject) -> (); + pub fn Py_ReprLeave(arg1: *mut PyObject); } // Flag bits for printing: @@ -908,7 +908,7 @@ pub unsafe fn PyType_FastSubclass(t: *mut PyTypeObject, f: c_ulong) -> c_int { #[cfg_attr(windows, link(name = "pythonXY"))] extern "C" { #[cfg_attr(PyPy, link_name = "_PyPy_Dealloc")] - pub fn _Py_Dealloc(arg1: *mut PyObject) -> (); + pub fn _Py_Dealloc(arg1: *mut PyObject); } // Reference counting macros. diff --git a/src/ffi/objectabstract.rs b/src/ffi/objectabstract.rs index a1fb403f..e180d3c3 100644 --- a/src/ffi/objectabstract.rs +++ b/src/ffi/objectabstract.rs @@ -132,7 +132,7 @@ extern "C" { strides: *mut Py_ssize_t, itemsize: c_int, fort: c_char, - ) -> (); + ); #[cfg_attr(PyPy, link_name = "PyPyBuffer_FillInfo")] pub fn PyBuffer_FillInfo( view: *mut Py_buffer, @@ -143,7 +143,7 @@ extern "C" { flags: c_int, ) -> c_int; #[cfg_attr(PyPy, link_name = "PyPyBuffer_Release")] - pub fn PyBuffer_Release(view: *mut Py_buffer) -> (); + pub fn PyBuffer_Release(view: *mut Py_buffer); } #[cfg_attr(windows, link(name = "pythonXY"))] diff --git a/src/ffi/objimpl.rs b/src/ffi/objimpl.rs index 60f192a5..c6f4cf8b 100644 --- a/src/ffi/objimpl.rs +++ b/src/ffi/objimpl.rs @@ -11,7 +11,7 @@ extern "C" { #[cfg_attr(PyPy, link_name = "PyPyObject_Realloc")] pub fn PyObject_Realloc(ptr: *mut c_void, new_size: size_t) -> *mut c_void; #[cfg_attr(PyPy, link_name = "PyPyObject_Free")] - pub fn PyObject_Free(ptr: *mut c_void) -> (); + pub fn PyObject_Free(ptr: *mut c_void); #[cfg(not(Py_LIMITED_API))] pub fn _Py_GetAllocatedBlocks() -> Py_ssize_t; @@ -37,7 +37,7 @@ extern "C" { pub struct PyObjectArenaAllocator { pub ctx: *mut c_void, pub alloc: Option *mut c_void>, - pub free: Option ()>, + pub free: Option, } #[cfg(not(Py_LIMITED_API))] @@ -50,8 +50,8 @@ impl Default for PyObjectArenaAllocator { #[cfg(not(Py_LIMITED_API))] #[cfg_attr(windows, link(name = "pythonXY"))] extern "C" { - pub fn PyObject_GetArenaAllocator(allocator: *mut PyObjectArenaAllocator) -> (); - pub fn PyObject_SetArenaAllocator(allocator: *mut PyObjectArenaAllocator) -> (); + pub fn PyObject_GetArenaAllocator(allocator: *mut PyObjectArenaAllocator); + pub fn PyObject_SetArenaAllocator(allocator: *mut PyObjectArenaAllocator); } /// Test if a type has a GC head @@ -84,10 +84,10 @@ extern "C" { pub fn _PyObject_GC_New(arg1: *mut PyTypeObject) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "_PyPyObject_GC_NewVar")] pub fn _PyObject_GC_NewVar(arg1: *mut PyTypeObject, arg2: Py_ssize_t) -> *mut PyVarObject; - pub fn PyObject_GC_Track(arg1: *mut c_void) -> (); - pub fn PyObject_GC_UnTrack(arg1: *mut c_void) -> (); + pub fn PyObject_GC_Track(arg1: *mut c_void); + pub fn PyObject_GC_UnTrack(arg1: *mut c_void); #[cfg_attr(PyPy, link_name = "PyPyObject_GC_Del")] - pub fn PyObject_GC_Del(arg1: *mut c_void) -> (); + pub fn PyObject_GC_Del(arg1: *mut c_void); } /// Test if a type supports weak references diff --git a/src/ffi/pyerrors.rs b/src/ffi/pyerrors.rs index 1e81a2e4..2467902f 100644 --- a/src/ffi/pyerrors.rs +++ b/src/ffi/pyerrors.rs @@ -9,31 +9,31 @@ use std::os::raw::{c_char, c_int}; #[cfg_attr(windows, link(name = "pythonXY"))] extern "C" { #[cfg_attr(PyPy, link_name = "PyPyErr_SetNone")] - pub fn PyErr_SetNone(arg1: *mut PyObject) -> (); + pub fn PyErr_SetNone(arg1: *mut PyObject); #[cfg_attr(PyPy, link_name = "PyPyErr_SetObject")] - pub fn PyErr_SetObject(arg1: *mut PyObject, arg2: *mut PyObject) -> (); + pub fn PyErr_SetObject(arg1: *mut PyObject, arg2: *mut PyObject); #[cfg_attr(PyPy, link_name = "PyPyErr_SetString")] - pub fn PyErr_SetString(exception: *mut PyObject, string: *const c_char) -> (); + pub fn PyErr_SetString(exception: *mut PyObject, string: *const c_char); #[cfg_attr(PyPy, link_name = "PyPyErr_Occurred")] pub fn PyErr_Occurred() -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyErr_Clear")] - pub fn PyErr_Clear() -> (); + pub fn PyErr_Clear(); #[cfg_attr(PyPy, link_name = "PyPyErr_Fetch")] pub fn PyErr_Fetch( arg1: *mut *mut PyObject, arg2: *mut *mut PyObject, arg3: *mut *mut PyObject, - ) -> (); + ); #[cfg_attr(PyPy, link_name = "PyPyErr_Restore")] - pub fn PyErr_Restore(arg1: *mut PyObject, arg2: *mut PyObject, arg3: *mut PyObject) -> (); + pub fn PyErr_Restore(arg1: *mut PyObject, arg2: *mut PyObject, arg3: *mut PyObject); #[cfg_attr(PyPy, link_name = "PyPyErr_GetExcInfo")] pub fn PyErr_GetExcInfo( arg1: *mut *mut PyObject, arg2: *mut *mut PyObject, arg3: *mut *mut PyObject, - ) -> (); + ); #[cfg_attr(PyPy, link_name = "PyPyErr_SetExcInfo")] - pub fn PyErr_SetExcInfo(arg1: *mut PyObject, arg2: *mut PyObject, arg3: *mut PyObject) -> (); + pub fn PyErr_SetExcInfo(arg1: *mut PyObject, arg2: *mut PyObject, arg3: *mut PyObject); #[cfg_attr(PyPy, link_name = "PyPy_FatalError")] pub fn Py_FatalError(message: *const c_char) -> !; #[cfg_attr(PyPy, link_name = "PyPyErr_GivenExceptionMatches")] @@ -45,7 +45,7 @@ extern "C" { arg1: *mut *mut PyObject, arg2: *mut *mut PyObject, arg3: *mut *mut PyObject, - ) -> (); + ); #[cfg_attr(PyPy, link_name = "PyPyException_SetTraceback")] pub fn PyException_SetTraceback(arg1: *mut PyObject, arg2: *mut PyObject) -> c_int; #[cfg_attr(PyPy, link_name = "PyPyException_GetTraceback")] @@ -53,11 +53,11 @@ extern "C" { #[cfg_attr(PyPy, link_name = "PyPyException_GetCause")] pub fn PyException_GetCause(arg1: *mut PyObject) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyException_SetCause")] - pub fn PyException_SetCause(arg1: *mut PyObject, arg2: *mut PyObject) -> (); + pub fn PyException_SetCause(arg1: *mut PyObject, arg2: *mut PyObject); #[cfg_attr(PyPy, link_name = "PyPyException_GetContext")] pub fn PyException_GetContext(arg1: *mut PyObject) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyException_SetContext")] - pub fn PyException_SetContext(arg1: *mut PyObject, arg2: *mut PyObject) -> (); + pub fn PyException_SetContext(arg1: *mut PyObject, arg2: *mut PyObject); } #[inline] @@ -277,8 +277,8 @@ extern "C" { arg3: *mut PyObject, ) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyErr_BadInternalCall")] - pub fn PyErr_BadInternalCall() -> (); - pub fn _PyErr_BadInternalCall(filename: *const c_char, lineno: c_int) -> (); + pub fn PyErr_BadInternalCall(); + pub fn _PyErr_BadInternalCall(filename: *const c_char, lineno: c_int); #[cfg_attr(PyPy, link_name = "PyPyErr_NewException")] pub fn PyErr_NewException( name: *const c_char, @@ -293,13 +293,13 @@ extern "C" { dict: *mut PyObject, ) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyErr_WriteUnraisable")] - pub fn PyErr_WriteUnraisable(arg1: *mut PyObject) -> (); + pub fn PyErr_WriteUnraisable(arg1: *mut PyObject); #[cfg_attr(PyPy, link_name = "PyPyErr_CheckSignals")] pub fn PyErr_CheckSignals() -> c_int; #[cfg_attr(PyPy, link_name = "PyPyErr_SetInterrupt")] - pub fn PyErr_SetInterrupt() -> (); - pub fn PyErr_SyntaxLocation(filename: *const c_char, lineno: c_int) -> (); - pub fn PyErr_SyntaxLocationEx(filename: *const c_char, lineno: c_int, col_offset: c_int) -> (); + pub fn PyErr_SetInterrupt(); + pub fn PyErr_SyntaxLocation(filename: *const c_char, lineno: c_int); + pub fn PyErr_SyntaxLocationEx(filename: *const c_char, lineno: c_int, col_offset: c_int); pub fn PyErr_ProgramText(filename: *const c_char, lineno: c_int) -> *mut PyObject; #[cfg(not(PyPy))] pub fn PyUnicodeDecodeError_Create( diff --git a/src/ffi/pymem.rs b/src/ffi/pymem.rs index 5bb517f2..58e3e897 100644 --- a/src/ffi/pymem.rs +++ b/src/ffi/pymem.rs @@ -11,7 +11,7 @@ extern "C" { #[cfg_attr(PyPy, link_name = "PyPyMem_RawRealloc")] pub fn PyMem_RawRealloc(ptr: *mut c_void, new_size: size_t) -> *mut c_void; #[cfg_attr(PyPy, link_name = "PyPyMem_RawFree")] - pub fn PyMem_RawFree(ptr: *mut c_void) -> (); + pub fn PyMem_RawFree(ptr: *mut c_void); } #[cfg_attr(windows, link(name = "pythonXY"))] @@ -23,7 +23,7 @@ extern "C" { #[cfg_attr(PyPy, link_name = "PyPyMem_Realloc")] pub fn PyMem_Realloc(ptr: *mut c_void, new_size: size_t) -> *mut c_void; #[cfg_attr(PyPy, link_name = "PyPyMem_Free")] - pub fn PyMem_Free(ptr: *mut c_void) -> (); + pub fn PyMem_Free(ptr: *mut c_void); } #[cfg(not(Py_LIMITED_API))] @@ -45,15 +45,13 @@ pub struct PyMemAllocatorEx { Option *mut c_void>, pub realloc: Option *mut c_void>, - pub free: Option ()>, + pub free: Option, } #[cfg(not(Py_LIMITED_API))] #[cfg_attr(windows, link(name = "pythonXY"))] extern "C" { - pub fn PyMem_GetAllocator(domain: PyMemAllocatorDomain, allocator: *mut PyMemAllocatorEx) - -> (); - pub fn PyMem_SetAllocator(domain: PyMemAllocatorDomain, allocator: *mut PyMemAllocatorEx) - -> (); - pub fn PyMem_SetupDebugHooks() -> (); + pub fn PyMem_GetAllocator(domain: PyMemAllocatorDomain, allocator: *mut PyMemAllocatorEx); + pub fn PyMem_SetAllocator(domain: PyMemAllocatorDomain, allocator: *mut PyMemAllocatorEx); + pub fn PyMem_SetupDebugHooks(); } diff --git a/src/ffi/pystate.rs b/src/ffi/pystate.rs index 92c43422..2fbd2ea3 100644 --- a/src/ffi/pystate.rs +++ b/src/ffi/pystate.rs @@ -25,8 +25,8 @@ pub struct PyThreadState { #[cfg_attr(windows, link(name = "pythonXY"))] extern "C" { pub fn PyInterpreterState_New() -> *mut PyInterpreterState; - pub fn PyInterpreterState_Clear(arg1: *mut PyInterpreterState) -> (); - pub fn PyInterpreterState_Delete(arg1: *mut PyInterpreterState) -> (); + pub fn PyInterpreterState_Clear(arg1: *mut PyInterpreterState); + pub fn PyInterpreterState_Delete(arg1: *mut PyInterpreterState); //fn _PyState_AddModule(arg1: *mut PyObject, // arg2: *mut PyModuleDef) -> c_int; pub fn PyState_FindModule(arg1: *mut PyModuleDef) -> *mut PyObject; @@ -34,14 +34,14 @@ extern "C" { pub fn PyThreadState_New(arg1: *mut PyInterpreterState) -> *mut PyThreadState; //fn _PyThreadState_Prealloc(arg1: *mut PyInterpreterState) // -> *mut PyThreadState; - //fn _PyThreadState_Init(arg1: *mut PyThreadState) -> (); + //fn _PyThreadState_Init(arg1: *mut PyThreadState); #[cfg_attr(PyPy, link_name = "PyPyThreadState_Clear")] - pub fn PyThreadState_Clear(arg1: *mut PyThreadState) -> (); + pub fn PyThreadState_Clear(arg1: *mut PyThreadState); #[cfg_attr(PyPy, link_name = "PyPyThreadState_Delete")] - pub fn PyThreadState_Delete(arg1: *mut PyThreadState) -> (); + pub fn PyThreadState_Delete(arg1: *mut PyThreadState); #[cfg(py_sys_config = "WITH_THREAD")] #[cfg_attr(PyPy, link_name = "PyPyThreadState_DeleteCurrent")] - pub fn PyThreadState_DeleteCurrent() -> (); + pub fn PyThreadState_DeleteCurrent(); #[cfg_attr(PyPy, link_name = "PyPyThreadState_Get")] pub fn PyThreadState_Get() -> *mut PyThreadState; #[cfg_attr(PyPy, link_name = "PyPyThreadState_Swap")] @@ -63,7 +63,7 @@ extern "C" { #[cfg_attr(PyPy, link_name = "PyPyGILState_Ensure")] pub fn PyGILState_Ensure() -> PyGILState_STATE; #[cfg_attr(PyPy, link_name = "PyPyGILState_Release")] - pub fn PyGILState_Release(arg1: PyGILState_STATE) -> (); + pub fn PyGILState_Release(arg1: PyGILState_STATE); pub fn PyGILState_GetThisThreadState() -> *mut PyThreadState; } diff --git a/src/ffi/pythonrun.rs b/src/ffi/pythonrun.rs index 03041b53..2252ac10 100644 --- a/src/ffi/pythonrun.rs +++ b/src/ffi/pythonrun.rs @@ -11,18 +11,18 @@ use std::ptr; #[cfg_attr(windows, link(name = "pythonXY"))] extern "C" { // TODO: these moved to pylifecycle.h - pub fn Py_SetProgramName(arg1: *mut wchar_t) -> (); + pub fn Py_SetProgramName(arg1: *mut wchar_t); #[cfg_attr(PyPy, link_name = "PyPy_GetProgramName")] pub fn Py_GetProgramName() -> *mut wchar_t; - pub fn Py_SetPythonHome(arg1: *mut wchar_t) -> (); + pub fn Py_SetPythonHome(arg1: *mut wchar_t); pub fn Py_GetPythonHome() -> *mut wchar_t; - pub fn Py_Initialize() -> (); - pub fn Py_InitializeEx(arg1: c_int) -> (); - pub fn Py_Finalize() -> (); + pub fn Py_Initialize(); + pub fn Py_InitializeEx(arg1: c_int); + pub fn Py_Finalize(); #[cfg_attr(PyPy, link_name = "PyPy_IsInitialized")] pub fn Py_IsInitialized() -> c_int; pub fn Py_NewInterpreter() -> *mut PyThreadState; - pub fn Py_EndInterpreter(arg1: *mut PyThreadState) -> (); + pub fn Py_EndInterpreter(arg1: *mut PyThreadState); } #[repr(C)] @@ -220,22 +220,22 @@ extern "C" { ) -> *mut symtable; #[cfg_attr(PyPy, link_name = "PyPyErr_Print")] - pub fn PyErr_Print() -> (); + pub fn PyErr_Print(); #[cfg_attr(PyPy, link_name = "PyPyErr_PrintEx")] - pub fn PyErr_PrintEx(arg1: c_int) -> (); + pub fn PyErr_PrintEx(arg1: c_int); #[cfg_attr(PyPy, link_name = "PyPyErr_Display")] - pub fn PyErr_Display(arg1: *mut PyObject, arg2: *mut PyObject, arg3: *mut PyObject) -> (); + pub fn PyErr_Display(arg1: *mut PyObject, arg2: *mut PyObject, arg3: *mut PyObject); // TODO: these moved to pylifecycle.h #[cfg_attr(PyPy, link_name = "PyPy_AtExit")] - pub fn Py_AtExit(func: Option ()>) -> c_int; - pub fn Py_Exit(arg1: c_int) -> (); + pub fn Py_AtExit(func: Option) -> c_int; + pub fn Py_Exit(arg1: c_int); pub fn Py_Main(argc: c_int, argv: *mut *mut wchar_t) -> c_int; pub fn Py_GetProgramFullPath() -> *mut wchar_t; pub fn Py_GetPrefix() -> *mut wchar_t; pub fn Py_GetExecPrefix() -> *mut wchar_t; pub fn Py_GetPath() -> *mut wchar_t; - pub fn Py_SetPath(arg1: *const wchar_t) -> (); + pub fn Py_SetPath(arg1: *const wchar_t); #[cfg_attr(PyPy, link_name = "PyPy_GetVersion")] pub fn Py_GetVersion() -> *const c_char; pub fn Py_GetPlatform() -> *const c_char; diff --git a/src/ffi/structseq.rs b/src/ffi/structseq.rs index 96857a4c..1829fd51 100644 --- a/src/ffi/structseq.rs +++ b/src/ffi/structseq.rs @@ -22,10 +22,6 @@ pub struct PyStructSequence_Desc { extern "C" { pub fn PyStructSequence_NewType(desc: *mut PyStructSequence_Desc) -> *mut PyTypeObject; pub fn PyStructSequence_New(_type: *mut PyTypeObject) -> *mut PyObject; - pub fn PyStructSequence_SetItem( - arg1: *mut PyObject, - arg2: Py_ssize_t, - arg3: *mut PyObject, - ) -> (); + pub fn PyStructSequence_SetItem(arg1: *mut PyObject, arg2: Py_ssize_t, arg3: *mut PyObject); pub fn PyStructSequence_GetItem(arg1: *mut PyObject, arg2: Py_ssize_t) -> *mut PyObject; } diff --git a/src/ffi/sysmodule.rs b/src/ffi/sysmodule.rs index 3af451c2..a96cfec6 100644 --- a/src/ffi/sysmodule.rs +++ b/src/ffi/sysmodule.rs @@ -10,19 +10,19 @@ extern "C" { pub fn PySys_GetObject(arg1: *const c_char) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPySys_SetObject")] pub fn PySys_SetObject(arg1: *const c_char, arg2: *mut PyObject) -> c_int; - pub fn PySys_SetArgv(arg1: c_int, arg2: *mut *mut wchar_t) -> (); - pub fn PySys_SetArgvEx(arg1: c_int, arg2: *mut *mut wchar_t, arg3: c_int) -> (); - pub fn PySys_SetPath(arg1: *const wchar_t) -> (); + pub fn PySys_SetArgv(arg1: c_int, arg2: *mut *mut wchar_t); + pub fn PySys_SetArgvEx(arg1: c_int, arg2: *mut *mut wchar_t, arg3: c_int); + pub fn PySys_SetPath(arg1: *const wchar_t); #[cfg_attr(PyPy, link_name = "PyPySys_WriteStdout")] - pub fn PySys_WriteStdout(format: *const c_char, ...) -> (); + pub fn PySys_WriteStdout(format: *const c_char, ...); #[cfg_attr(PyPy, link_name = "PyPySys_WriteStderr")] - pub fn PySys_WriteStderr(format: *const c_char, ...) -> (); - pub fn PySys_FormatStdout(format: *const c_char, ...) -> (); - pub fn PySys_FormatStderr(format: *const c_char, ...) -> (); - pub fn PySys_ResetWarnOptions() -> (); - pub fn PySys_AddWarnOption(arg1: *const wchar_t) -> (); - pub fn PySys_AddWarnOptionUnicode(arg1: *mut PyObject) -> (); + pub fn PySys_WriteStderr(format: *const c_char, ...); + pub fn PySys_FormatStdout(format: *const c_char, ...); + pub fn PySys_FormatStderr(format: *const c_char, ...); + pub fn PySys_ResetWarnOptions(); + pub fn PySys_AddWarnOption(arg1: *const wchar_t); + pub fn PySys_AddWarnOptionUnicode(arg1: *mut PyObject); pub fn PySys_HasWarnOptions() -> c_int; - pub fn PySys_AddXOption(arg1: *const wchar_t) -> (); + pub fn PySys_AddXOption(arg1: *const wchar_t); pub fn PySys_GetXOptions() -> *mut PyObject; } diff --git a/src/ffi/unicodeobject.rs b/src/ffi/unicodeobject.rs index 2b8e5dec..8f178d11 100644 --- a/src/ffi/unicodeobject.rs +++ b/src/ffi/unicodeobject.rs @@ -116,8 +116,8 @@ extern "C" { // vargs: va_list) -> *mut PyObject; pub fn PyUnicode_FromFormat(format: *const c_char, ...) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyUnicode_InternInPlace")] - pub fn PyUnicode_InternInPlace(arg1: *mut *mut PyObject) -> (); - pub fn PyUnicode_InternImmortal(arg1: *mut *mut PyObject) -> (); + pub fn PyUnicode_InternInPlace(arg1: *mut *mut PyObject); + pub fn PyUnicode_InternImmortal(arg1: *mut *mut PyObject); #[cfg_attr(PyPy, link_name = "PyPyUnicode_InternFromString")] pub fn PyUnicode_InternFromString(u: *const c_char) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyUnicode_FromWideChar")] @@ -389,8 +389,8 @@ extern "C" { pub fn PyUnicode_EncodeFSDefault(unicode: *mut PyObject) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyUnicode_Concat")] pub fn PyUnicode_Concat(left: *mut PyObject, right: *mut PyObject) -> *mut PyObject; - pub fn PyUnicode_Append(pleft: *mut *mut PyObject, right: *mut PyObject) -> (); - pub fn PyUnicode_AppendAndDel(pleft: *mut *mut PyObject, right: *mut PyObject) -> (); + pub fn PyUnicode_Append(pleft: *mut *mut PyObject, right: *mut PyObject); + pub fn PyUnicode_AppendAndDel(pleft: *mut *mut PyObject, right: *mut PyObject); #[cfg_attr(PyPy, link_name = "PyPyUnicode_Split")] pub fn PyUnicode_Split( s: *mut PyObject, diff --git a/src/gil.rs b/src/gil.rs index a2ef2154..642261f2 100644 --- a/src/gil.rs +++ b/src/gil.rs @@ -108,7 +108,6 @@ impl Drop for GILGuard { unsafe { let pool: &'static mut ReleasePool = &mut *POOL; pool.drain(self.python(), self.owned, self.borrowed); - ffi::PyGILState_Release(self.gstate); } } diff --git a/src/internal_tricks.rs b/src/internal_tricks.rs index 0dae9fb8..a5388165 100644 --- a/src/internal_tricks.rs +++ b/src/internal_tricks.rs @@ -12,7 +12,7 @@ macro_rules! private_decl { /// This trait is private to implement; this method exists to make it /// impossible to implement outside the crate. fn __private__(&self) -> crate::internal_tricks::PrivateMarker; - } + }; } macro_rules! private_impl { @@ -21,7 +21,7 @@ macro_rules! private_impl { fn __private__(&self) -> crate::internal_tricks::PrivateMarker { crate::internal_tricks::PrivateMarker } - } + }; } macro_rules! pyo3_exception { diff --git a/src/lib.rs b/src/lib.rs index 033e9c93..3b501a22 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -133,6 +133,7 @@ //! } //! ``` +pub use crate::callback::run_callback; pub use crate::class::*; pub use crate::conversion::{ AsPyPointer, FromPy, FromPyObject, FromPyPointer, IntoPy, IntoPyPointer, PyTryFrom, PyTryInto, diff --git a/src/python.rs b/src/python.rs index 0d9b479c..6c4f4d89 100644 --- a/src/python.rs +++ b/src/python.rs @@ -9,8 +9,7 @@ use crate::instance::AsPyRef; use crate::object::PyObject; use crate::type_object::{PyDowncastImpl, PyTypeInfo, PyTypeObject}; use crate::types::{PyAny, PyDict, PyModule, PyType}; -use crate::AsPyPointer; -use crate::{FromPyPointer, IntoPyPointer, PyTryFrom}; +use crate::{AsPyPointer, FromPyPointer, IntoPyPointer, PyTryFrom}; use std::ffi::CString; use std::marker::PhantomData; use std::os::raw::c_int; diff --git a/src/types/set.rs b/src/types/set.rs index 39a1afed..6b7aa248 100644 --- a/src/types/set.rs +++ b/src/types/set.rs @@ -4,8 +4,8 @@ use crate::err::{self, PyErr, PyResult}; use crate::internal_tricks::Unsendable; use crate::{ - ffi, AsPyPointer, FromPyObject, PyAny, PyNativeType, PyObject, PyTryFrom, Python, - ToBorrowedObject, ToPyObject, + ffi, AsPyPointer, FromPyObject, PyAny, PyNativeType, PyObject, Python, ToBorrowedObject, + ToPyObject, }; use std::cmp; use std::collections::{BTreeSet, HashSet}; @@ -189,13 +189,9 @@ where K: FromPyObject<'source> + cmp::Eq + hash::Hash, S: hash::BuildHasher + Default, { - fn extract(ob: &'source PyAny) -> Result { - let set = ::try_from(ob)?; - let mut ret = HashSet::default(); - for k in set.iter() { - ret.insert(K::extract(k)?); - } - Ok(ret) + fn extract(ob: &'source PyAny) -> PyResult { + let set: &PySet = ob.downcast()?; + set.iter().map(K::extract).collect() } } @@ -203,13 +199,9 @@ impl<'source, K> FromPyObject<'source> for BTreeSet where K: FromPyObject<'source> + cmp::Ord, { - fn extract(ob: &'source PyAny) -> Result { - let set = ::try_from(ob)?; - let mut ret = BTreeSet::default(); - for k in set.iter() { - ret.insert(K::extract(k)?); - } - Ok(ret) + fn extract(ob: &'source PyAny) -> PyResult { + let set: &PySet = ob.downcast()?; + set.iter().map(K::extract).collect() } } @@ -279,9 +271,9 @@ impl<'a> std::iter::IntoIterator for &'a PyFrozenSet { #[cfg(test)] mod test { use super::{PyFrozenSet, PySet}; - use crate::instance::AsPyRef; - use crate::{ObjectProtocol, PyTryFrom, Python, ToPyObject}; - use std::collections::HashSet; + use crate::{AsPyRef, ObjectProtocol, PyTryFrom, Python, ToPyObject}; + use std::collections::{BTreeSet, HashSet}; + use std::iter::FromIterator; #[test] fn test_set_new() { @@ -433,4 +425,30 @@ mod test { assert_eq!(1i32, el.extract::().unwrap()); } } + + #[test] + fn test_extract_hashset() { + let gil = Python::acquire_gil(); + let py = gil.python(); + + let set = PySet::new(py, &[1, 2, 3, 4, 5]).unwrap(); + let hash_set: HashSet = set.extract().unwrap(); + assert_eq!( + hash_set, + HashSet::from_iter([1, 2, 3, 4, 5].iter().copied()) + ); + } + + #[test] + fn test_extract_btreeset() { + let gil = Python::acquire_gil(); + let py = gil.python(); + + let set = PySet::new(py, &[1, 2, 3, 4, 5]).unwrap(); + let hash_set: BTreeSet = set.extract().unwrap(); + assert_eq!( + hash_set, + BTreeSet::from_iter([1, 2, 3, 4, 5].iter().copied()) + ); + } } diff --git a/tests/test_arithmetics.rs b/tests/test_arithmetics.rs index 914585cd..8b1260dc 100644 --- a/tests/test_arithmetics.rs +++ b/tests/test_arithmetics.rs @@ -8,24 +8,39 @@ use pyo3::py_run; mod common; #[pyclass] -struct UnaryArithmetic {} +struct UnaryArithmetic { + inner: f64, +} + +impl UnaryArithmetic { + fn new(value: f64) -> Self { + UnaryArithmetic { inner: value } + } +} + +#[pyproto] +impl PyObjectProtocol for UnaryArithmetic { + fn __repr__(&self) -> PyResult { + Ok(format!("UA({})", self.inner)) + } +} #[pyproto] impl PyNumberProtocol for UnaryArithmetic { - fn __neg__(&self) -> PyResult<&'static str> { - Ok("neg") + fn __neg__(&self) -> PyResult { + Ok(Self::new(-self.inner)) } - fn __pos__(&self) -> PyResult<&'static str> { - Ok("pos") + fn __pos__(&self) -> PyResult { + Ok(Self::new(self.inner)) } - fn __abs__(&self) -> PyResult<&'static str> { - Ok("abs") + fn __abs__(&self) -> PyResult { + Ok(Self::new(self.inner.abs())) } - fn __invert__(&self) -> PyResult<&'static str> { - Ok("invert") + fn __round__(&self, _ndigits: Option) -> PyResult { + Ok(Self::new(self.inner.round())) } } @@ -34,11 +49,12 @@ fn unary_arithmetic() { let gil = Python::acquire_gil(); let py = gil.python(); - let c = Py::new(py, UnaryArithmetic {}).unwrap(); - py_run!(py, c, "assert -c == 'neg'"); - py_run!(py, c, "assert +c == 'pos'"); - py_run!(py, c, "assert abs(c) == 'abs'"); - py_run!(py, c, "assert ~c == 'invert'"); + let c = PyCell::new(py, UnaryArithmetic::new(2.7)).unwrap(); + py_run!(py, c, "assert repr(-c) == 'UA(-2.7)'"); + py_run!(py, c, "assert repr(+c) == 'UA(2.7)'"); + py_run!(py, c, "assert repr(abs(c)) == 'UA(2.7)'"); + py_run!(py, c, "assert repr(round(c)) == 'UA(3)'"); + py_run!(py, c, "assert repr(round(c, 1)) == 'UA(3)'"); } #[pyclass] @@ -104,15 +120,19 @@ impl PyNumberProtocol for InPlaceOperations { self.value |= other; Ok(()) } + + fn __ipow__(&mut self, other: u32) -> PyResult<()> { + self.value = self.value.pow(other); + Ok(()) + } } #[test] fn inplace_operations() { let gil = Python::acquire_gil(); let py = gil.python(); - let init = |value, code| { - let c = Py::new(py, InPlaceOperations { value }).unwrap(); + let c = PyCell::new(py, InPlaceOperations { value }).unwrap(); py_run!(py, c, code); }; @@ -124,6 +144,11 @@ fn inplace_operations() { init(12, "d = c; c &= 10; assert repr(c) == repr(d) == 'IPO(8)'"); init(12, "d = c; c |= 3; assert repr(c) == repr(d) == 'IPO(15)'"); init(12, "d = c; c ^= 5; assert repr(c) == repr(d) == 'IPO(9)'"); + init(3, "d = c; c **= 4; assert repr(c) == repr(d) == 'IPO(81)'"); + init( + 3, + "d = c; c.__ipow__(4); assert repr(c) == repr(d) == 'IPO(81)'", + ); } #[pyproto] @@ -159,6 +184,10 @@ impl PyNumberProtocol for BinaryArithmetic { fn __or__(lhs: &PyAny, rhs: &PyAny) -> PyResult { Ok(format!("{:?} | {:?}", lhs, rhs)) } + + fn __pow__(lhs: &PyAny, rhs: &PyAny, mod_: Option) -> PyResult { + Ok(format!("{:?} ** {:?} (mod: {:?})", lhs, rhs, mod_)) + } } #[test] @@ -166,8 +195,9 @@ fn binary_arithmetic() { let gil = Python::acquire_gil(); let py = gil.python(); - let c = Py::new(py, BinaryArithmetic {}).unwrap(); + let c = PyCell::new(py, BinaryArithmetic {}).unwrap(); py_run!(py, c, "assert c + c == 'BA + BA'"); + py_run!(py, c, "assert c.__add__(c) == 'BA + BA'"); py_run!(py, c, "assert c + 1 == 'BA + 1'"); py_run!(py, c, "assert 1 + c == '1 + BA'"); py_run!(py, c, "assert c - 1 == 'BA - 1'"); @@ -185,6 +215,10 @@ fn binary_arithmetic() { py_run!(py, c, "assert 1 ^ c == '1 ^ BA'"); py_run!(py, c, "assert c | 1 == 'BA | 1'"); py_run!(py, c, "assert 1 | c == '1 | BA'"); + py_run!(py, c, "assert c ** 1 == 'BA ** 1 (mod: None)'"); + py_run!(py, c, "assert 1 ** c == '1 ** BA (mod: None)'"); + + py_run!(py, c, "assert pow(c, 1, 100) == 'BA ** 1 (mod: Some(100))'"); } #[pyclass] @@ -195,6 +229,38 @@ impl PyNumberProtocol for RhsArithmetic { fn __radd__(&self, other: &PyAny) -> PyResult { Ok(format!("{:?} + RA", other)) } + + fn __rsub__(&self, other: &PyAny) -> PyResult { + Ok(format!("{:?} - RA", other)) + } + + fn __rmul__(&self, other: &PyAny) -> PyResult { + Ok(format!("{:?} * RA", other)) + } + + fn __rlshift__(&self, other: &PyAny) -> PyResult { + Ok(format!("{:?} << RA", other)) + } + + fn __rrshift__(&self, other: &PyAny) -> PyResult { + Ok(format!("{:?} >> RA", other)) + } + + fn __rand__(&self, other: &PyAny) -> PyResult { + Ok(format!("{:?} & RA", other)) + } + + fn __rxor__(&self, other: &PyAny) -> PyResult { + Ok(format!("{:?} ^ RA", other)) + } + + fn __ror__(&self, other: &PyAny) -> PyResult { + Ok(format!("{:?} | RA", other)) + } + + fn __rpow__(&self, other: &PyAny, _mod: Option<&'p PyAny>) -> PyResult { + Ok(format!("{:?} ** RA", other)) + } } #[test] @@ -202,11 +268,78 @@ fn rhs_arithmetic() { let gil = Python::acquire_gil(); let py = gil.python(); - let c = Py::new(py, RhsArithmetic {}).unwrap(); + let c = PyCell::new(py, RhsArithmetic {}).unwrap(); py_run!(py, c, "assert c.__radd__(1) == '1 + RA'"); - // TODO: commented out for now until reflected arithemtics gets fixed. - // see discussion here: https://github.com/PyO3/pyo3/pull/550 - // py_run!(py, c, "assert 1 + c == '1 + RA'"); + py_run!(py, c, "assert 1 + c == '1 + RA'"); + py_run!(py, c, "assert c.__rsub__(1) == '1 - RA'"); + py_run!(py, c, "assert 1 - c == '1 - RA'"); + py_run!(py, c, "assert c.__rmul__(1) == '1 * RA'"); + py_run!(py, c, "assert 1 * c == '1 * RA'"); + py_run!(py, c, "assert c.__rlshift__(1) == '1 << RA'"); + py_run!(py, c, "assert 1 << c == '1 << RA'"); + py_run!(py, c, "assert c.__rrshift__(1) == '1 >> RA'"); + py_run!(py, c, "assert 1 >> c == '1 >> RA'"); + py_run!(py, c, "assert c.__rand__(1) == '1 & RA'"); + py_run!(py, c, "assert 1 & c == '1 & RA'"); + py_run!(py, c, "assert c.__rxor__(1) == '1 ^ RA'"); + py_run!(py, c, "assert 1 ^ c == '1 ^ RA'"); + py_run!(py, c, "assert c.__ror__(1) == '1 | RA'"); + py_run!(py, c, "assert 1 | c == '1 | RA'"); + py_run!(py, c, "assert c.__rpow__(1) == '1 ** RA'"); + py_run!(py, c, "assert 1 ** c == '1 ** RA'"); +} + +#[pyclass] +struct LhsAndRhsArithmetic {} + +#[pyproto] +impl PyNumberProtocol for LhsAndRhsArithmetic { + fn __radd__(&self, other: &PyAny) -> PyResult { + Ok(format!("{:?} + RA", other)) + } + + fn __rsub__(&self, other: &PyAny) -> PyResult { + Ok(format!("{:?} - RA", other)) + } + + fn __rpow__(&self, other: &PyAny, _mod: Option<&'p PyAny>) -> PyResult { + Ok(format!("{:?} ** RA", other)) + } + + fn __add__(lhs: &PyAny, rhs: &PyAny) -> PyResult { + Ok(format!("{:?} + {:?}", lhs, rhs)) + } + + fn __sub__(lhs: &PyAny, rhs: &PyAny) -> PyResult { + Ok(format!("{:?} - {:?}", lhs, rhs)) + } + + fn __pow__(lhs: &PyAny, rhs: &PyAny, _mod: Option) -> PyResult { + Ok(format!("{:?} ** {:?}", lhs, rhs)) + } +} + +#[pyproto] +impl PyObjectProtocol for LhsAndRhsArithmetic { + fn __repr__(&self) -> PyResult<&'static str> { + Ok("BA") + } +} + +#[test] +fn lhs_override_rhs() { + let gil = Python::acquire_gil(); + let py = gil.python(); + + let c = PyCell::new(py, LhsAndRhsArithmetic {}).unwrap(); + // Not overrided + py_run!(py, c, "assert c.__radd__(1) == '1 + RA'"); + py_run!(py, c, "assert c.__rsub__(1) == '1 - RA'"); + py_run!(py, c, "assert c.__rpow__(1) == '1 ** RA'"); + // Overrided + py_run!(py, c, "assert 1 + c == '1 + BA'"); + py_run!(py, c, "assert 1 - c == '1 - BA'"); + py_run!(py, c, "assert 1 ** c == '1 ** BA'"); } #[pyclass] @@ -254,7 +387,7 @@ fn rich_comparisons() { let gil = Python::acquire_gil(); let py = gil.python(); - let c = Py::new(py, RichComparisons {}).unwrap(); + let c = PyCell::new(py, RichComparisons {}).unwrap(); py_run!(py, c, "assert (c < c) == 'RC < RC'"); py_run!(py, c, "assert (c < 1) == 'RC < 1'"); py_run!(py, c, "assert (1 < c) == 'RC > 1'"); @@ -280,7 +413,7 @@ fn rich_comparisons_python_3_type_error() { let gil = Python::acquire_gil(); let py = gil.python(); - let c2 = Py::new(py, RichComparisons2 {}).unwrap(); + let c2 = PyCell::new(py, RichComparisons2 {}).unwrap(); py_expect_exception!(py, c2, "c2 < c2", TypeError); py_expect_exception!(py, c2, "c2 < 1", TypeError); py_expect_exception!(py, c2, "1 < c2", TypeError); diff --git a/tests/test_gc.rs b/tests/test_gc.rs index 829bb881..88e440fd 100644 --- a/tests/test_gc.rs +++ b/tests/test_gc.rs @@ -2,6 +2,7 @@ use pyo3::class::PyGCProtocol; use pyo3::class::PyTraverseError; use pyo3::class::PyVisit; use pyo3::prelude::*; +use pyo3::type_object::PyTypeObject; use pyo3::{py_run, AsPyPointer, PyCell, PyTryInto}; use std::cell::RefCell; use std::sync::atomic::{AtomicBool, Ordering}; @@ -245,3 +246,63 @@ fn inheritance_with_new_methods_with_drop() { assert!(drop_called1.load(Ordering::Relaxed)); assert!(drop_called2.load(Ordering::Relaxed)); } + +#[pyclass(gc)] +struct TraversableClass { + traversed: AtomicBool, +} + +impl TraversableClass { + fn new() -> Self { + Self { + traversed: AtomicBool::new(false), + } + } +} + +#[pyproto] +impl PyGCProtocol for TraversableClass { + fn __clear__(&mut self) {} + fn __traverse__(&self, _visit: PyVisit) -> Result<(), PyTraverseError> { + self.traversed.store(true, Ordering::Relaxed); + Ok(()) + } +} + +#[test] +fn gc_during_borrow() { + let gil = Python::acquire_gil(); + let py = gil.python(); + + unsafe { + // declare a dummy visitor function + extern "C" fn novisit( + _object: *mut pyo3::ffi::PyObject, + _arg: *mut core::ffi::c_void, + ) -> std::os::raw::c_int { + 0 + } + + // get the traverse function + let ty = TraversableClass::type_object().as_ref(py).as_type_ptr(); + let traverse = (*ty).tp_traverse.unwrap(); + + // create an object and check that traversing it works normally + // when it's not borrowed + let cell = PyCell::new(py, TraversableClass::new()).unwrap(); + let obj = cell.to_object(py); + assert!(!cell.borrow().traversed.load(Ordering::Relaxed)); + traverse(obj.as_ptr(), novisit, std::ptr::null_mut()); + assert!(cell.borrow().traversed.load(Ordering::Relaxed)); + + // create an object and check that it is not traversed if the GC + // is invoked while it is already borrowed mutably + let cell2 = PyCell::new(py, TraversableClass::new()).unwrap(); + let obj2 = cell2.to_object(py); + let guard = cell2.borrow_mut(); + assert!(!guard.traversed.load(Ordering::Relaxed)); + traverse(obj2.as_ptr(), novisit, std::ptr::null_mut()); + assert!(!guard.traversed.load(Ordering::Relaxed)); + drop(guard); + } +}