Use PyMethodsImpl instead of *ProtocolImpl::methods

This commit is contained in:
kngwyu 2020-05-09 16:36:02 +09:00
parent da22eecb5f
commit 69dba08b01
15 changed files with 118 additions and 632 deletions

View file

@ -24,11 +24,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- The `GILGuard` returned from `Python::acquire_gil` will now only assume responsiblity for freeing owned references on drop if no other `GILPool` or `GILGuard` exists. This ensures that multiple calls to the safe api `Python::acquire_gil` cannot lead to dangling references. [#893](https://github.com/PyO3/pyo3/pull/893)
- The trait `ObjectProtocol` has been removed, and all the methods from the trait have been moved to `PyAny`. [#911](https://github.com/PyO3/pyo3/pull/911)
- The exception to this is `ObjectProtocol::None`, which has simply been removed. Use `Python::None` instead.
- No `#![feature(specialization)]` in user code. [#917](https://github.com/PyO3/pyo3/pull/917)
### Removed
- `PyMethodsProtocol` is now renamed to `PyMethodsImpl` and hidden. [#889](https://github.com/PyO3/pyo3/pull/889)
- `num-traits` is no longer a dependency. [#895](https://github.com/PyO3/pyo3/pull/895)
- `ObjectProtocol`. [#911](https://github.com/PyO3/pyo3/pull/911)
- All `*ProtocolImpl` traits. [#917](https://github.com/PyO3/pyo3/pull/917)
### Fixed
- `__radd__` and other `__r*__` methods now correctly work with operators. [#839](https://github.com/PyO3/pyo3/pull/839)

View file

@ -17,76 +17,7 @@ struct MyClass {
The above example generates implementations for [`PyTypeInfo`], [`PyTypeObject`],
and [`PyClass`] for `MyClass`.
Specifically, the following implementation is generated:
```rust
use pyo3::prelude::*;
/// Class for demonstration
struct MyClass {
num: i32,
debug: bool,
}
impl pyo3::pyclass::PyClassAlloc for MyClass {}
unsafe impl pyo3::PyTypeInfo for MyClass {
type Type = MyClass;
type BaseType = PyAny;
type BaseLayout = pyo3::pycell::PyCellBase<PyAny>;
type Layout = PyCell<Self>;
type Initializer = PyClassInitializer<Self>;
type AsRefTarget = PyCell<Self>;
const NAME: &'static str = "MyClass";
const MODULE: Option<&'static str> = None;
const DESCRIPTION: &'static str = "Class for demonstration";
const FLAGS: usize = 0;
#[inline]
fn type_object() -> &'static pyo3::ffi::PyTypeObject {
use pyo3::type_object::LazyStaticType;
static TYPE_OBJECT: LazyStaticType = LazyStaticType::new();
TYPE_OBJECT.get_or_init::<Self>()
}
}
impl pyo3::pyclass::PyClass for MyClass {
type Dict = pyo3::pyclass_slots::PyClassDummySlot;
type WeakRef = pyo3::pyclass_slots::PyClassDummySlot;
type BaseNativeType = PyAny;
}
impl pyo3::IntoPy<PyObject> for MyClass {
fn into_py(self, py: pyo3::Python) -> pyo3::PyObject {
pyo3::IntoPy::into_py(pyo3::Py::new(py, self).unwrap(), py)
}
}
pub struct Pyo3MethodsInventoryForMyClass {
methods: &'static [pyo3::class::PyMethodDefType],
}
impl pyo3::class::methods::PyMethodsInventory for Pyo3MethodsInventoryForMyClass {
fn new(methods: &'static [pyo3::class::PyMethodDefType]) -> Self {
Self { methods }
}
fn get_methods(&self) -> &'static [pyo3::class::PyMethodDefType] {
self.methods
}
}
impl pyo3::class::methods::PyMethodsImpl for MyClass {
type Methods = Pyo3MethodsInventoryForMyClass;
}
pyo3::inventory::collect!(Pyo3MethodsInventoryForMyClass);
# let gil = Python::acquire_gil();
# let py = gil.python();
# let cls = py.get_type::<MyClass>();
# pyo3::py_run!(py, cls, "assert cls.__name__ == 'MyClass'")
```
If you curious what `#[pyclass]` generates, see [How methods are implemented](#how-methods-are-implemented) section.
## Adding the class to a module
@ -944,7 +875,77 @@ pyclass dependent on whether there is an impl block, we'd need to implement the
`#[pyclass]` and override the implementation in `#[pymethods]`, which is to the best of my knowledge
only possible with the specialization feature, which can't be used on stable.
To escape this we use [inventory](https://github.com/dtolnay/inventory), which allows us to collect `impl`s from arbitrary source code by exploiting some binary trick. See [inventory: how it works](https://github.com/dtolnay/inventory#how-it-works) and `pyo3_derive_backend::py_class::impl_inventory` for more details.
To escape this we use [inventory](https://github.com/dtolnay/inventory),
which allows us to collect `impl`s from arbitrary source code by exploiting some binary trick.
See [inventory: how it works](https://github.com/dtolnay/inventory#how-it-works) and `pyo3_derive_backend::py_class` for more details.
Specifically, the following implementation is generated:
```rust
use pyo3::prelude::*;
/// Class for demonstration
struct MyClass {
num: i32,
debug: bool,
}
impl pyo3::pyclass::PyClassAlloc for MyClass {}
unsafe impl pyo3::PyTypeInfo for MyClass {
type Type = MyClass;
type BaseType = PyAny;
type BaseLayout = pyo3::pycell::PyCellBase<PyAny>;
type Layout = PyCell<Self>;
type Initializer = PyClassInitializer<Self>;
type AsRefTarget = PyCell<Self>;
const NAME: &'static str = "MyClass";
const MODULE: Option<&'static str> = None;
const DESCRIPTION: &'static str = "Class for demonstration";
const FLAGS: usize = 0;
#[inline]
fn type_object() -> &'static pyo3::ffi::PyTypeObject {
use pyo3::type_object::LazyStaticType;
static TYPE_OBJECT: LazyStaticType = LazyStaticType::new();
TYPE_OBJECT.get_or_init::<Self>()
}
}
impl pyo3::pyclass::PyClass for MyClass {
type Dict = pyo3::pyclass_slots::PyClassDummySlot;
type WeakRef = pyo3::pyclass_slots::PyClassDummySlot;
type BaseNativeType = PyAny;
}
impl pyo3::IntoPy<PyObject> for MyClass {
fn into_py(self, py: pyo3::Python) -> pyo3::PyObject {
pyo3::IntoPy::into_py(pyo3::Py::new(py, self).unwrap(), py)
}
}
pub struct Pyo3MethodsInventoryForMyClass {
methods: &'static [pyo3::class::PyMethodDefType],
}
impl pyo3::class::methods::PyMethodsInventory for Pyo3MethodsInventoryForMyClass {
fn new(methods: &'static [pyo3::class::PyMethodDefType]) -> Self {
Self { methods }
}
fn get(&self) -> &'static [pyo3::class::PyMethodDefType] {
self.methods
}
}
impl pyo3::class::methods::PyMethodsImpl for MyClass {
type Methods = Pyo3MethodsInventoryForMyClass;
}
pyo3::inventory::collect!(Pyo3MethodsInventoryForMyClass);
# let gil = Python::acquire_gil();
# let py = gil.python();
# let cls = py.get_type::<MyClass>();
# pyo3::py_run!(py, cls, "assert cls.__name__ == 'MyClass'")
```
[`GILGuard`]: https://docs.rs/pyo3/latest/pyo3/struct.GILGuard.html
[`PyGCProtocol`]: https://docs.rs/pyo3/latest/pyo3/class/gc/trait.PyGCProtocol.html

View file

@ -208,11 +208,9 @@ fn parse_descriptors(item: &mut syn::Field) -> syn::Result<Vec<FnType>> {
Ok(descs)
}
/// The orphan rule disallows using a generic inventory struct, so we create the whole boilerplate
/// once per class
fn impl_inventory(cls: &syn::Ident) -> TokenStream {
// Try to build a unique type that gives a hint about it's function when
// it comes up in error messages
/// To allow multiple #[pymethods]/#[pyproto] block, we define inventory types.
fn impl_methods_inventory(cls: &syn::Ident) -> TokenStream {
// Try to build a unique type for better error messages
let name = format!("Pyo3MethodsInventoryFor{}", cls);
let inventory_cls = syn::Ident::new(&name, Span::call_site());
@ -221,15 +219,11 @@ fn impl_inventory(cls: &syn::Ident) -> TokenStream {
pub struct #inventory_cls {
methods: &'static [pyo3::class::PyMethodDefType],
}
impl pyo3::class::methods::PyMethodsInventory for #inventory_cls {
fn new(methods: &'static [pyo3::class::PyMethodDefType]) -> Self {
Self {
methods
}
Self { methods }
}
fn get_methods(&self) -> &'static [pyo3::class::PyMethodDefType] {
fn get(&self) -> &'static [pyo3::class::PyMethodDefType] {
self.methods
}
}
@ -345,7 +339,7 @@ fn impl_class(
quote! {}
};
let inventory_impl = impl_inventory(&cls);
let impl_inventory = impl_methods_inventory(&cls);
let base = &attr.base;
let flags = &attr.flags;
@ -418,7 +412,7 @@ fn impl_class(
#into_pyobject
#inventory_impl
#impl_inventory
#extra

View file

@ -36,7 +36,7 @@ pub fn build_py_proto(ast: &mut syn::ItemImpl) -> syn::Result<TokenStream> {
));
};
let tokens = impl_proto_impl(&ast.self_ty, &mut ast.items, proto);
let tokens = impl_proto_impl(&ast.self_ty, &mut ast.items, proto)?;
// attach lifetime
let mut seg = path.segments.pop().unwrap().into_value();
@ -57,53 +57,54 @@ fn impl_proto_impl(
ty: &syn::Type,
impls: &mut Vec<syn::ImplItem>,
proto: &defs::Proto,
) -> TokenStream {
let mut tokens = TokenStream::new();
) -> syn::Result<TokenStream> {
let mut trait_impls = TokenStream::new();
let mut py_methods = Vec::new();
for iimpl in impls.iter_mut() {
if let syn::ImplItem::Method(ref mut met) = iimpl {
if let Some(m) = proto.get_proto(&met.sig.ident) {
impl_method_proto(ty, &mut met.sig, m).to_tokens(&mut tokens);
impl_method_proto(ty, &mut met.sig, m).to_tokens(&mut trait_impls);
}
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 = FnSpec::parse(&met.sig, &mut met.attrs, false)?;
let method = pymethod::impl_proto_wrap(ty, &fn_spec);
let coexist = if m.can_coexist {
// We need METH_COEXIST here to prevent __add__ from overriding __radd__
quote!(pyo3::ffi::METH_COEXIST)
} else {
quote!(0)
};
// TODO(kngwyu): doc
py_methods.push(quote! {
impl #proto for #ty
{
#[inline]
fn #name() -> Option<pyo3::class::methods::PyMethodDef> {
#meth
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: ""
})
pyo3::class::PyMethodDefType::Method({
#method
pyo3::class::PyMethodDef {
ml_name: stringify!(#name),
ml_meth: pyo3::class::PyMethodType::PyCFunctionWithKeywords(__wrap),
ml_flags: pyo3::ffi::METH_VARARGS | pyo3::ffi::METH_KEYWORDS | #coexist,
ml_doc: ""
}
}
})
});
}
}
}
quote! {
#tokens
#(#py_methods)*
if py_methods.is_empty() {
return Ok(quote! { #trait_impls });
}
let inventory_submission = quote! {
pyo3::inventory::submit! {
#![crate = pyo3] {
type ProtoInventory = <#ty as pyo3::class::methods::PyMethodsImpl>::Methods;
<ProtoInventory as pyo3::class::methods::PyMethodsInventory>::new(&[#(#py_methods),*])
}
}
};
Ok(quote! {
#trait_impls
#inventory_submission
})
}

View file

@ -9,7 +9,6 @@
//! [typeobj docs](https://docs.python.org/3/c-api/typeobj.html)
use crate::callback::HashCallbackOutput;
use crate::class::methods::PyMethodDef;
use crate::{
exceptions, ffi, FromPyObject, IntoPy, PyAny, PyCell, PyClass, PyErr, PyObject, PyResult,
};
@ -145,15 +144,11 @@ pub trait PyObjectRichcmpProtocol<'p>: PyObjectProtocol<'p> {
#[doc(hidden)]
pub trait PyObjectProtocolImpl {
fn methods() -> Vec<PyMethodDef>;
fn tp_as_object(_type_object: &mut ffi::PyTypeObject);
fn nb_bool_fn() -> Option<ffi::inquiry>;
}
impl<T> PyObjectProtocolImpl for T {
default fn methods() -> Vec<PyMethodDef> {
Vec::new()
}
default fn tp_as_object(_type_object: &mut ffi::PyTypeObject) {}
default fn nb_bool_fn() -> Option<ffi::inquiry> {
None
@ -164,20 +159,6 @@ impl<'p, T> PyObjectProtocolImpl for T
where
T: PyObjectProtocol<'p>,
{
fn methods() -> Vec<PyMethodDef> {
let mut methods = Vec::new();
if let Some(def) = <Self as FormatProtocolImpl>::__format__() {
methods.push(def)
}
if let Some(def) = <Self as BytesProtocolImpl>::__bytes__() {
methods.push(def)
}
if let Some(def) = <Self as UnicodeProtocolImpl>::__unicode__() {
methods.push(def)
}
methods
}
fn tp_as_object(type_object: &mut ffi::PyTypeObject) {
type_object.tp_str = Self::tp_str();
type_object.tp_repr = Self::tp_repr();
@ -373,45 +354,6 @@ where
}
}
#[doc(hidden)]
pub trait FormatProtocolImpl {
fn __format__() -> Option<PyMethodDef>;
}
impl<'p, T> FormatProtocolImpl for T
where
T: PyObjectProtocol<'p>,
{
default fn __format__() -> Option<PyMethodDef> {
None
}
}
#[doc(hidden)]
pub trait BytesProtocolImpl {
fn __bytes__() -> Option<PyMethodDef>;
}
impl<'p, T> BytesProtocolImpl for T
where
T: PyObjectProtocol<'p>,
{
default fn __bytes__() -> Option<PyMethodDef> {
None
}
}
#[doc(hidden)]
pub trait UnicodeProtocolImpl {
fn __unicode__() -> Option<PyMethodDef>;
}
impl<'p, T> UnicodeProtocolImpl for T
where
T: PyObjectProtocol<'p>,
{
default fn __unicode__() -> Option<PyMethodDef> {
None
}
}
trait HashProtocolImpl {
fn tp_hash() -> Option<ffi::hashfunc>;
}

View file

@ -4,7 +4,6 @@
//! Trait and support implementation for context manager api
//!
use crate::class::methods::PyMethodDef;
use crate::err::PyResult;
use crate::{PyClass, PyObject};
@ -43,61 +42,3 @@ pub trait PyContextExitProtocol<'p>: PyContextProtocol<'p> {
type Success: crate::IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>;
}
#[doc(hidden)]
pub trait PyContextProtocolImpl {
fn methods() -> Vec<PyMethodDef>;
}
impl<T> PyContextProtocolImpl for T {
default fn methods() -> Vec<PyMethodDef> {
Vec::new()
}
}
impl<'p, T> PyContextProtocolImpl for T
where
T: PyContextProtocol<'p>,
{
#[inline]
fn methods() -> Vec<PyMethodDef> {
let mut methods = Vec::new();
if let Some(def) = <Self as PyContextEnterProtocolImpl>::__enter__() {
methods.push(def)
}
if let Some(def) = <Self as PyContextExitProtocolImpl>::__exit__() {
methods.push(def)
}
methods
}
}
#[doc(hidden)]
pub trait PyContextEnterProtocolImpl {
fn __enter__() -> Option<PyMethodDef>;
}
impl<'p, T> PyContextEnterProtocolImpl for T
where
T: PyContextProtocol<'p>,
{
default fn __enter__() -> Option<PyMethodDef> {
None
}
}
#[doc(hidden)]
pub trait PyContextExitProtocolImpl {
fn __exit__() -> Option<PyMethodDef>;
}
impl<'p, T> PyContextExitProtocolImpl for T
where
T: PyContextProtocol<'p>,
{
default fn __exit__() -> Option<PyMethodDef> {
None
}
}

View file

@ -123,14 +123,10 @@ impl<'p, T> PyDescrSetNameProtocolImpl for T where T: PyDescrProtocol<'p> {}
#[doc(hidden)]
pub trait PyDescrProtocolImpl {
fn methods() -> Vec<PyMethodDef>;
fn tp_as_descr(_type_object: &mut ffi::PyTypeObject);
}
impl<T> PyDescrProtocolImpl for T {
default fn methods() -> Vec<PyMethodDef> {
Vec::new()
}
default fn tp_as_descr(_type_object: &mut ffi::PyTypeObject) {}
}
@ -138,9 +134,6 @@ impl<'p, T> PyDescrProtocolImpl for T
where
T: PyDescrProtocol<'p>,
{
fn methods() -> Vec<PyMethodDef> {
Vec::new()
}
fn tp_as_descr(type_object: &mut ffi::PyTypeObject) {
type_object.tp_descr_get = Self::tp_descr_get();
type_object.tp_descr_set = Self::tp_descr_set();

View file

@ -3,7 +3,6 @@
//! Python Mapping Interface
//! Trait and support implementation for implementing mapping support
use crate::class::methods::PyMethodDef;
use crate::err::{PyErr, PyResult};
use crate::{exceptions, ffi, FromPyObject, IntoPy, PyClass, PyObject};
@ -78,16 +77,12 @@ pub trait PyMappingReversedProtocol<'p>: PyMappingProtocol<'p> {
#[doc(hidden)]
pub trait PyMappingProtocolImpl {
fn tp_as_mapping() -> Option<ffi::PyMappingMethods>;
fn methods() -> Vec<PyMethodDef>;
}
impl<T> PyMappingProtocolImpl for T {
default fn tp_as_mapping() -> Option<ffi::PyMappingMethods> {
None
}
default fn methods() -> Vec<PyMethodDef> {
Vec::new()
}
}
impl<'p, T> PyMappingProtocolImpl for T
@ -108,17 +103,6 @@ where
mp_ass_subscript: f,
})
}
#[inline]
fn methods() -> Vec<PyMethodDef> {
let mut methods = Vec::new();
if let Some(def) = <Self as PyMappingReversedProtocolImpl>::__reversed__() {
methods.push(def)
}
methods
}
}
trait PyMappingLenProtocolImpl {
@ -242,17 +226,3 @@ where
<T as DelSetItemDispatch>::det_set_dispatch()
}
}
#[doc(hidden)]
pub trait PyMappingReversedProtocolImpl {
fn __reversed__() -> Option<PyMethodDef>;
}
impl<'p, T> PyMappingReversedProtocolImpl for T
where
T: PyMappingProtocol<'p>,
{
default fn __reversed__() -> Option<PyMethodDef> {
None
}
}

View file

@ -135,16 +135,16 @@ impl PySetterDef {
}
/// Implementation detail. Only to be used through the proc macros.
/// Allows arbitrary pymethod blocks to submit their methods, which are eventually
/// collected by pyclass.
/// Allows arbitrary `#[pymethod]/#[pyproto]` blocks to submit their methods,
/// which are eventually collected by `#[pyclass]`.
#[doc(hidden)]
#[cfg(feature = "macros")]
pub trait PyMethodsInventory: inventory::Collect {
/// Create a new instance
fn new(methods: &'static [PyMethodDefType]) -> Self;
/// Returns the methods for a single impl block
fn get_methods(&self) -> &'static [PyMethodDefType];
/// Returns the methods for a single `#[pymethods] impl` block
fn get(&self) -> &'static [PyMethodDefType];
}
/// Implementation detail. Only to be used through the proc macros.
@ -159,7 +159,7 @@ pub trait PyMethodsImpl {
fn py_methods() -> Vec<&'static PyMethodDefType> {
inventory::iter::<Self::Methods>
.into_iter()
.flat_map(PyMethodsInventory::get_methods)
.flat_map(PyMethodsInventory::get)
.collect()
}
}

View file

@ -4,7 +4,6 @@
//! Trait and support implementation for implementing number protocol
use crate::class::basic::PyObjectProtocolImpl;
use crate::class::methods::PyMethodDef;
use crate::err::PyResult;
use crate::{ffi, FromPyObject, IntoPy, PyClass, PyObject};
@ -619,14 +618,10 @@ pub trait PyNumberIndexProtocol<'p>: PyNumberProtocol<'p> {
#[doc(hidden)]
pub trait PyNumberProtocolImpl: PyObjectProtocolImpl {
fn methods() -> Vec<PyMethodDef>;
fn tp_as_number() -> Option<ffi::PyNumberMethods>;
}
impl<'p, T> PyNumberProtocolImpl for T {
default fn methods() -> Vec<PyMethodDef> {
Vec::new()
}
default fn tp_as_number() -> Option<ffi::PyNumberMethods> {
if let Some(nb_bool) = <Self as PyObjectProtocolImpl>::nb_bool_fn() {
let meth = ffi::PyNumberMethods {
@ -684,62 +679,6 @@ where
nb_inplace_matrix_multiply: Self::nb_inplace_matrix_multiply(),
})
}
#[inline]
fn methods() -> Vec<PyMethodDef> {
let mut methods = Vec::new();
if let Some(def) = <Self as PyNumberRAddProtocolImpl>::__radd__() {
methods.push(def)
}
if let Some(def) = <Self as PyNumberRSubProtocolImpl>::__rsub__() {
methods.push(def)
}
if let Some(def) = <Self as PyNumberRMulProtocolImpl>::__rmul__() {
methods.push(def)
}
if let Some(def) = <Self as PyNumberRMatmulProtocolImpl>::__rmatmul__() {
methods.push(def)
}
if let Some(def) = <Self as PyNumberRTruedivProtocolImpl>::__rtruediv__() {
methods.push(def)
}
if let Some(def) = <Self as PyNumberRFloordivProtocolImpl>::__rfloordiv__() {
methods.push(def)
}
if let Some(def) = <Self as PyNumberRModProtocolImpl>::__rmod__() {
methods.push(def)
}
if let Some(def) = <Self as PyNumberRDivmodProtocolImpl>::__rdivmod__() {
methods.push(def)
}
if let Some(def) = <Self as PyNumberRPowProtocolImpl>::__rpow__() {
methods.push(def)
}
if let Some(def) = <Self as PyNumberRLShiftProtocolImpl>::__rlshift__() {
methods.push(def)
}
if let Some(def) = <Self as PyNumberRRShiftProtocolImpl>::__rrshift__() {
methods.push(def)
}
if let Some(def) = <Self as PyNumberRAndProtocolImpl>::__rand__() {
methods.push(def)
}
if let Some(def) = <Self as PyNumberRXorProtocolImpl>::__rxor__() {
methods.push(def)
}
if let Some(def) = <Self as PyNumberROrProtocolImpl>::__ror__() {
methods.push(def)
}
if let Some(def) = <Self as PyNumberComplexProtocolImpl>::__complex__() {
methods.push(def)
}
if let Some(def) = <Self as PyNumberRoundProtocolImpl>::__round__() {
methods.push(def)
}
methods
}
}
trait PyNumberAddProtocolImpl {
@ -1336,20 +1275,6 @@ where
}
}
#[doc(hidden)]
pub trait PyNumberRAddProtocolImpl {
fn __radd__() -> Option<PyMethodDef>;
}
impl<'p, T> PyNumberRAddProtocolImpl for T
where
T: PyNumberProtocol<'p>,
{
default fn __radd__() -> Option<PyMethodDef> {
None
}
}
// Fallback trait for nb_add
trait PyNumberAddFallback {
fn nb_add_fallback() -> Option<ffi::binaryfunc>;
@ -1373,20 +1298,6 @@ where
}
}
#[doc(hidden)]
pub trait PyNumberRSubProtocolImpl {
fn __rsub__() -> Option<PyMethodDef>;
}
impl<'p, T> PyNumberRSubProtocolImpl for T
where
T: PyNumberProtocol<'p>,
{
default fn __rsub__() -> Option<PyMethodDef> {
None
}
}
trait PyNumberSubFallback {
fn nb_sub_fallback() -> Option<ffi::binaryfunc>;
}
@ -1409,20 +1320,6 @@ where
}
}
#[doc(hidden)]
pub trait PyNumberRMulProtocolImpl {
fn __rmul__() -> Option<PyMethodDef>;
}
impl<'p, T> PyNumberRMulProtocolImpl for T
where
T: PyNumberProtocol<'p>,
{
default fn __rmul__() -> Option<PyMethodDef> {
None
}
}
trait PyNumberMulFallback {
fn nb_mul_fallback() -> Option<ffi::binaryfunc>;
}
@ -1445,20 +1342,6 @@ where
}
}
#[doc(hidden)]
pub trait PyNumberRMatmulProtocolImpl {
fn __rmatmul__() -> Option<PyMethodDef>;
}
impl<'p, T> PyNumberRMatmulProtocolImpl for T
where
T: PyNumberProtocol<'p>,
{
default fn __rmatmul__() -> Option<PyMethodDef> {
None
}
}
trait PyNumberMatmulFallback {
fn nb_matmul_fallback() -> Option<ffi::binaryfunc>;
}
@ -1481,20 +1364,6 @@ where
}
}
#[doc(hidden)]
pub trait PyNumberRTruedivProtocolImpl {
fn __rtruediv__() -> Option<PyMethodDef>;
}
impl<'p, T> PyNumberRTruedivProtocolImpl for T
where
T: PyNumberProtocol<'p>,
{
default fn __rtruediv__() -> Option<PyMethodDef> {
None
}
}
trait PyNumberTruedivFallback {
fn nb_truediv_fallback() -> Option<ffi::binaryfunc>;
}
@ -1517,20 +1386,6 @@ where
}
}
#[doc(hidden)]
pub trait PyNumberRFloordivProtocolImpl {
fn __rfloordiv__() -> Option<PyMethodDef>;
}
impl<'p, T> PyNumberRFloordivProtocolImpl for T
where
T: PyNumberProtocol<'p>,
{
default fn __rfloordiv__() -> Option<PyMethodDef> {
None
}
}
trait PyNumberFloordivFallback {
fn nb_floordiv_fallback() -> Option<ffi::binaryfunc>;
}
@ -1553,20 +1408,6 @@ where
}
}
#[doc(hidden)]
pub trait PyNumberRModProtocolImpl {
fn __rmod__() -> Option<PyMethodDef>;
}
impl<'p, T> PyNumberRModProtocolImpl for T
where
T: PyNumberProtocol<'p>,
{
default fn __rmod__() -> Option<PyMethodDef> {
None
}
}
trait PyNumberModFallback {
fn nb_mod_fallback() -> Option<ffi::binaryfunc>;
}
@ -1589,20 +1430,6 @@ where
}
}
#[doc(hidden)]
pub trait PyNumberRDivmodProtocolImpl {
fn __rdivmod__() -> Option<PyMethodDef>;
}
impl<'p, T> PyNumberRDivmodProtocolImpl for T
where
T: PyNumberProtocol<'p>,
{
default fn __rdivmod__() -> Option<PyMethodDef> {
None
}
}
trait PyNumberDivmodFallback {
fn nb_divmod_fallback() -> Option<ffi::binaryfunc>;
}
@ -1625,20 +1452,6 @@ where
}
}
#[doc(hidden)]
pub trait PyNumberRPowProtocolImpl {
fn __rpow__() -> Option<PyMethodDef>;
}
impl<'p, T> PyNumberRPowProtocolImpl for T
where
T: PyNumberProtocol<'p>,
{
default fn __rpow__() -> Option<PyMethodDef> {
None
}
}
trait PyNumberPowFallback {
fn nb_pow_fallback() -> Option<ffi::ternaryfunc>;
}
@ -1661,20 +1474,6 @@ where
}
}
#[doc(hidden)]
pub trait PyNumberRLShiftProtocolImpl {
fn __rlshift__() -> Option<PyMethodDef>;
}
impl<'p, T> PyNumberRLShiftProtocolImpl for T
where
T: PyNumberProtocol<'p>,
{
default fn __rlshift__() -> Option<PyMethodDef> {
None
}
}
trait PyNumberLShiftFallback {
fn nb_lshift_fallback() -> Option<ffi::binaryfunc>;
}
@ -1697,20 +1496,6 @@ where
}
}
#[doc(hidden)]
pub trait PyNumberRRShiftProtocolImpl {
fn __rrshift__() -> Option<PyMethodDef>;
}
impl<'p, T> PyNumberRRShiftProtocolImpl for T
where
T: PyNumberProtocol<'p>,
{
default fn __rrshift__() -> Option<PyMethodDef> {
None
}
}
trait PyNumberRRshiftFallback {
fn nb_rshift_fallback() -> Option<ffi::binaryfunc>;
}
@ -1733,20 +1518,6 @@ where
}
}
#[doc(hidden)]
pub trait PyNumberRAndProtocolImpl {
fn __rand__() -> Option<PyMethodDef>;
}
impl<'p, T> PyNumberRAndProtocolImpl for T
where
T: PyNumberProtocol<'p>,
{
default fn __rand__() -> Option<PyMethodDef> {
None
}
}
trait PyNumberAndFallback {
fn nb_and_fallback() -> Option<ffi::binaryfunc>;
}
@ -1769,20 +1540,6 @@ where
}
}
#[doc(hidden)]
pub trait PyNumberRXorProtocolImpl {
fn __rxor__() -> Option<PyMethodDef>;
}
impl<'p, T> PyNumberRXorProtocolImpl for T
where
T: PyNumberProtocol<'p>,
{
default fn __rxor__() -> Option<PyMethodDef> {
None
}
}
trait PyNumberXorFallback {
fn nb_xor_fallback() -> Option<ffi::binaryfunc>;
}
@ -1805,20 +1562,6 @@ where
}
}
#[doc(hidden)]
pub trait PyNumberROrProtocolImpl {
fn __ror__() -> Option<PyMethodDef>;
}
impl<'p, T> PyNumberROrProtocolImpl for T
where
T: PyNumberProtocol<'p>,
{
default fn __ror__() -> Option<PyMethodDef> {
None
}
}
trait PyNumberOrFallback {
fn nb_or_fallback() -> Option<ffi::binaryfunc>;
}
@ -1995,29 +1738,3 @@ where
py_unary_func!(PyNumberIndexProtocol, T::__index__)
}
}
pub trait PyNumberComplexProtocolImpl {
fn __complex__() -> Option<PyMethodDef>;
}
impl<'p, T> PyNumberComplexProtocolImpl for T
where
T: PyNumberProtocol<'p>,
{
default fn __complex__() -> Option<PyMethodDef> {
None
}
}
pub trait PyNumberRoundProtocolImpl {
fn __round__() -> Option<PyMethodDef>;
}
impl<'p, T> PyNumberRoundProtocolImpl for T
where
T: PyNumberProtocol<'p>,
{
default fn __round__() -> Option<PyMethodDef> {
None
}
}

View file

@ -8,7 +8,6 @@
//! [PEP-0492](https://www.python.org/dev/peps/pep-0492/)
//!
use crate::class::methods::PyMethodDef;
use crate::err::PyResult;
use crate::{ffi, PyClass, PyObject};
@ -89,17 +88,12 @@ pub trait PyAsyncAexitProtocol<'p>: PyAsyncProtocol<'p> {
#[doc(hidden)]
pub trait PyAsyncProtocolImpl {
fn tp_as_async() -> Option<ffi::PyAsyncMethods>;
fn methods() -> Vec<PyMethodDef>;
}
impl<T> PyAsyncProtocolImpl for T {
default fn tp_as_async() -> Option<ffi::PyAsyncMethods> {
None
}
default fn methods() -> Vec<PyMethodDef> {
Vec::new()
}
}
impl<'p, T> PyAsyncProtocolImpl for T
@ -114,20 +108,6 @@ where
am_anext: Self::am_anext(),
})
}
#[inline]
fn methods() -> Vec<PyMethodDef> {
let mut methods = Vec::new();
if let Some(def) = <Self as PyAsyncAenterProtocolImpl>::__aenter__() {
methods.push(def)
}
if let Some(def) = <Self as PyAsyncAexitProtocolImpl>::__aexit__() {
methods.push(def)
}
methods
}
}
trait PyAsyncAwaitProtocolImpl {
@ -227,29 +207,3 @@ mod anext {
}
}
}
trait PyAsyncAenterProtocolImpl {
fn __aenter__() -> Option<PyMethodDef>;
}
impl<'p, T> PyAsyncAenterProtocolImpl for T
where
T: PyAsyncProtocol<'p>,
{
default fn __aenter__() -> Option<PyMethodDef> {
None
}
}
trait PyAsyncAexitProtocolImpl {
fn __aexit__() -> Option<PyMethodDef>;
}
impl<'p, T> PyAsyncAexitProtocolImpl for T
where
T: PyAsyncProtocol<'p>,
{
default fn __aexit__() -> Option<PyMethodDef> {
None
}
}

View file

@ -172,7 +172,7 @@ where
// normal methods
if !methods.is_empty() {
methods.push(ffi::PyMethodDef_INIT);
type_object.tp_methods = Box::into_raw(methods.into_boxed_slice()) as *mut _;
type_object.tp_methods = Box::into_raw(methods.into_boxed_slice()) as _;
}
// class attributes
@ -197,7 +197,7 @@ where
}
if !props.is_empty() {
props.push(ffi::PyGetSetDef_INIT);
type_object.tp_getset = Box::into_raw(props.into_boxed_slice()) as *mut _;
type_object.tp_getset = Box::into_raw(props.into_boxed_slice()) as _;
}
// set type flags
@ -264,33 +264,9 @@ fn py_class_method_defs<T: PyMethodsImpl>() -> (
}
}
for def in <T as class::basic::PyObjectProtocolImpl>::methods() {
defs.push(def.as_method_def());
}
for def in <T as class::context::PyContextProtocolImpl>::methods() {
defs.push(def.as_method_def());
}
for def in <T as class::mapping::PyMappingProtocolImpl>::methods() {
defs.push(def.as_method_def());
}
for def in <T as class::number::PyNumberProtocolImpl>::methods() {
defs.push(def.as_method_def());
}
for def in <T as class::descr::PyDescrProtocolImpl>::methods() {
defs.push(def.as_method_def());
}
py_class_async_methods::<T>(&mut defs);
(new, call, defs, attrs)
}
fn py_class_async_methods<T>(defs: &mut Vec<ffi::PyMethodDef>) {
for def in <T as class::pyasync::PyAsyncProtocolImpl>::methods() {
defs.push(def.as_method_def());
}
}
fn py_class_properties<T: PyMethodsImpl>() -> Vec<ffi::PyGetSetDef> {
let mut defs = std::collections::HashMap::new();

View file

@ -1,5 +1,3 @@
#![feature(specialization)]
use pyo3::class::basic::CompareOp;
use pyo3::class::*;
use pyo3::prelude::*;

View file

@ -1,5 +1,3 @@
#![feature(specialization)]
use pyo3::class::{
PyContextProtocol, PyIterProtocol, PyMappingProtocol, PyObjectProtocol, PySequenceProtocol,
};

View file

@ -1,4 +1,3 @@
#![feature(specialization)]
use std::collections::HashMap;
use pyo3::exceptions::KeyError;