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 `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 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. - 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 ### Removed
- `PyMethodsProtocol` is now renamed to `PyMethodsImpl` and hidden. [#889](https://github.com/PyO3/pyo3/pull/889) - `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) - `num-traits` is no longer a dependency. [#895](https://github.com/PyO3/pyo3/pull/895)
- `ObjectProtocol`. [#911](https://github.com/PyO3/pyo3/pull/911) - `ObjectProtocol`. [#911](https://github.com/PyO3/pyo3/pull/911)
- All `*ProtocolImpl` traits. [#917](https://github.com/PyO3/pyo3/pull/917)
### Fixed ### Fixed
- `__radd__` and other `__r*__` methods now correctly work with operators. [#839](https://github.com/PyO3/pyo3/pull/839) - `__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`], The above example generates implementations for [`PyTypeInfo`], [`PyTypeObject`],
and [`PyClass`] for `MyClass`. and [`PyClass`] for `MyClass`.
Specifically, the following implementation is generated: If you curious what `#[pyclass]` generates, see [How methods are implemented](#how-methods-are-implemented) section.
```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'")
```
## Adding the class to a module ## 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 `#[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. 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 [`GILGuard`]: https://docs.rs/pyo3/latest/pyo3/struct.GILGuard.html
[`PyGCProtocol`]: https://docs.rs/pyo3/latest/pyo3/class/gc/trait.PyGCProtocol.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) Ok(descs)
} }
/// The orphan rule disallows using a generic inventory struct, so we create the whole boilerplate /// To allow multiple #[pymethods]/#[pyproto] block, we define inventory types.
/// once per class fn impl_methods_inventory(cls: &syn::Ident) -> TokenStream {
fn impl_inventory(cls: &syn::Ident) -> TokenStream { // Try to build a unique type for better error messages
// Try to build a unique type that gives a hint about it's function when
// it comes up in error messages
let name = format!("Pyo3MethodsInventoryFor{}", cls); let name = format!("Pyo3MethodsInventoryFor{}", cls);
let inventory_cls = syn::Ident::new(&name, Span::call_site()); 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 { pub struct #inventory_cls {
methods: &'static [pyo3::class::PyMethodDefType], methods: &'static [pyo3::class::PyMethodDefType],
} }
impl pyo3::class::methods::PyMethodsInventory for #inventory_cls { impl pyo3::class::methods::PyMethodsInventory for #inventory_cls {
fn new(methods: &'static [pyo3::class::PyMethodDefType]) -> Self { fn new(methods: &'static [pyo3::class::PyMethodDefType]) -> Self {
Self { Self { methods }
methods
}
} }
fn get(&self) -> &'static [pyo3::class::PyMethodDefType] {
fn get_methods(&self) -> &'static [pyo3::class::PyMethodDefType] {
self.methods self.methods
} }
} }
@ -345,7 +339,7 @@ fn impl_class(
quote! {} quote! {}
}; };
let inventory_impl = impl_inventory(&cls); let impl_inventory = impl_methods_inventory(&cls);
let base = &attr.base; let base = &attr.base;
let flags = &attr.flags; let flags = &attr.flags;
@ -418,7 +412,7 @@ fn impl_class(
#into_pyobject #into_pyobject
#inventory_impl #impl_inventory
#extra #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 // attach lifetime
let mut seg = path.segments.pop().unwrap().into_value(); let mut seg = path.segments.pop().unwrap().into_value();
@ -57,53 +57,54 @@ fn impl_proto_impl(
ty: &syn::Type, ty: &syn::Type,
impls: &mut Vec<syn::ImplItem>, impls: &mut Vec<syn::ImplItem>,
proto: &defs::Proto, proto: &defs::Proto,
) -> TokenStream { ) -> syn::Result<TokenStream> {
let mut tokens = TokenStream::new(); let mut trait_impls = TokenStream::new();
let mut py_methods = Vec::new(); let mut py_methods = Vec::new();
for iimpl in impls.iter_mut() { for iimpl in impls.iter_mut() {
if let syn::ImplItem::Method(ref mut met) = iimpl { if let syn::ImplItem::Method(ref mut met) = iimpl {
if let Some(m) = proto.get_proto(&met.sig.ident) { 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) { if let Some(m) = proto.get_method(&met.sig.ident) {
let name = &met.sig.ident; let name = &met.sig.ident;
let proto: syn::Path = syn::parse_str(m.proto).unwrap(); let fn_spec = FnSpec::parse(&met.sig, &mut met.attrs, false)?;
let method = 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 { let coexist = if m.can_coexist {
// We need METH_COEXIST here to prevent __add__ from overriding __radd__
quote!(pyo3::ffi::METH_COEXIST) quote!(pyo3::ffi::METH_COEXIST)
} else { } else {
quote!(0) quote!(0)
}; };
// TODO(kngwyu): doc
py_methods.push(quote! { py_methods.push(quote! {
impl #proto for #ty pyo3::class::PyMethodDefType::Method({
{ #method
#[inline] pyo3::class::PyMethodDef {
fn #name() -> Option<pyo3::class::methods::PyMethodDef> { ml_name: stringify!(#name),
#meth ml_meth: pyo3::class::PyMethodType::PyCFunctionWithKeywords(__wrap),
ml_flags: pyo3::ffi::METH_VARARGS | pyo3::ffi::METH_KEYWORDS | #coexist,
Some(pyo3::class::PyMethodDef { ml_doc: ""
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: ""
})
} }
} })
}); });
} }
} }
} }
quote! { if py_methods.is_empty() {
#tokens return Ok(quote! { #trait_impls });
#(#py_methods)*
} }
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) //! [typeobj docs](https://docs.python.org/3/c-api/typeobj.html)
use crate::callback::HashCallbackOutput; use crate::callback::HashCallbackOutput;
use crate::class::methods::PyMethodDef;
use crate::{ use crate::{
exceptions, ffi, FromPyObject, IntoPy, PyAny, PyCell, PyClass, PyErr, PyObject, PyResult, exceptions, ffi, FromPyObject, IntoPy, PyAny, PyCell, PyClass, PyErr, PyObject, PyResult,
}; };
@ -145,15 +144,11 @@ pub trait PyObjectRichcmpProtocol<'p>: PyObjectProtocol<'p> {
#[doc(hidden)] #[doc(hidden)]
pub trait PyObjectProtocolImpl { pub trait PyObjectProtocolImpl {
fn methods() -> Vec<PyMethodDef>;
fn tp_as_object(_type_object: &mut ffi::PyTypeObject); fn tp_as_object(_type_object: &mut ffi::PyTypeObject);
fn nb_bool_fn() -> Option<ffi::inquiry>; fn nb_bool_fn() -> Option<ffi::inquiry>;
} }
impl<T> PyObjectProtocolImpl for T { impl<T> PyObjectProtocolImpl for T {
default fn methods() -> Vec<PyMethodDef> {
Vec::new()
}
default fn tp_as_object(_type_object: &mut ffi::PyTypeObject) {} default fn tp_as_object(_type_object: &mut ffi::PyTypeObject) {}
default fn nb_bool_fn() -> Option<ffi::inquiry> { default fn nb_bool_fn() -> Option<ffi::inquiry> {
None None
@ -164,20 +159,6 @@ impl<'p, T> PyObjectProtocolImpl for T
where where
T: PyObjectProtocol<'p>, 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) { fn tp_as_object(type_object: &mut ffi::PyTypeObject) {
type_object.tp_str = Self::tp_str(); type_object.tp_str = Self::tp_str();
type_object.tp_repr = Self::tp_repr(); 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 { trait HashProtocolImpl {
fn tp_hash() -> Option<ffi::hashfunc>; fn tp_hash() -> Option<ffi::hashfunc>;
} }

View file

@ -4,7 +4,6 @@
//! Trait and support implementation for context manager api //! Trait and support implementation for context manager api
//! //!
use crate::class::methods::PyMethodDef;
use crate::err::PyResult; use crate::err::PyResult;
use crate::{PyClass, PyObject}; use crate::{PyClass, PyObject};
@ -43,61 +42,3 @@ pub trait PyContextExitProtocol<'p>: PyContextProtocol<'p> {
type Success: crate::IntoPy<PyObject>; type Success: crate::IntoPy<PyObject>;
type Result: Into<PyResult<Self::Success>>; 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)] #[doc(hidden)]
pub trait PyDescrProtocolImpl { pub trait PyDescrProtocolImpl {
fn methods() -> Vec<PyMethodDef>;
fn tp_as_descr(_type_object: &mut ffi::PyTypeObject); fn tp_as_descr(_type_object: &mut ffi::PyTypeObject);
} }
impl<T> PyDescrProtocolImpl for T { impl<T> PyDescrProtocolImpl for T {
default fn methods() -> Vec<PyMethodDef> {
Vec::new()
}
default fn tp_as_descr(_type_object: &mut ffi::PyTypeObject) {} default fn tp_as_descr(_type_object: &mut ffi::PyTypeObject) {}
} }
@ -138,9 +134,6 @@ impl<'p, T> PyDescrProtocolImpl for T
where where
T: PyDescrProtocol<'p>, T: PyDescrProtocol<'p>,
{ {
fn methods() -> Vec<PyMethodDef> {
Vec::new()
}
fn tp_as_descr(type_object: &mut ffi::PyTypeObject) { fn tp_as_descr(type_object: &mut ffi::PyTypeObject) {
type_object.tp_descr_get = Self::tp_descr_get(); type_object.tp_descr_get = Self::tp_descr_get();
type_object.tp_descr_set = Self::tp_descr_set(); type_object.tp_descr_set = Self::tp_descr_set();

View file

@ -3,7 +3,6 @@
//! Python Mapping Interface //! Python Mapping Interface
//! Trait and support implementation for implementing mapping support //! Trait and support implementation for implementing mapping support
use crate::class::methods::PyMethodDef;
use crate::err::{PyErr, PyResult}; use crate::err::{PyErr, PyResult};
use crate::{exceptions, ffi, FromPyObject, IntoPy, PyClass, PyObject}; use crate::{exceptions, ffi, FromPyObject, IntoPy, PyClass, PyObject};
@ -78,16 +77,12 @@ pub trait PyMappingReversedProtocol<'p>: PyMappingProtocol<'p> {
#[doc(hidden)] #[doc(hidden)]
pub trait PyMappingProtocolImpl { pub trait PyMappingProtocolImpl {
fn tp_as_mapping() -> Option<ffi::PyMappingMethods>; fn tp_as_mapping() -> Option<ffi::PyMappingMethods>;
fn methods() -> Vec<PyMethodDef>;
} }
impl<T> PyMappingProtocolImpl for T { impl<T> PyMappingProtocolImpl for T {
default fn tp_as_mapping() -> Option<ffi::PyMappingMethods> { default fn tp_as_mapping() -> Option<ffi::PyMappingMethods> {
None None
} }
default fn methods() -> Vec<PyMethodDef> {
Vec::new()
}
} }
impl<'p, T> PyMappingProtocolImpl for T impl<'p, T> PyMappingProtocolImpl for T
@ -108,17 +103,6 @@ where
mp_ass_subscript: f, 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 { trait PyMappingLenProtocolImpl {
@ -242,17 +226,3 @@ where
<T as DelSetItemDispatch>::det_set_dispatch() <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. /// Implementation detail. Only to be used through the proc macros.
/// Allows arbitrary pymethod blocks to submit their methods, which are eventually /// Allows arbitrary `#[pymethod]/#[pyproto]` blocks to submit their methods,
/// collected by pyclass. /// which are eventually collected by `#[pyclass]`.
#[doc(hidden)] #[doc(hidden)]
#[cfg(feature = "macros")] #[cfg(feature = "macros")]
pub trait PyMethodsInventory: inventory::Collect { pub trait PyMethodsInventory: inventory::Collect {
/// Create a new instance /// Create a new instance
fn new(methods: &'static [PyMethodDefType]) -> Self; fn new(methods: &'static [PyMethodDefType]) -> Self;
/// Returns the methods for a single impl block /// Returns the methods for a single `#[pymethods] impl` block
fn get_methods(&self) -> &'static [PyMethodDefType]; fn get(&self) -> &'static [PyMethodDefType];
} }
/// Implementation detail. Only to be used through the proc macros. /// Implementation detail. Only to be used through the proc macros.
@ -159,7 +159,7 @@ pub trait PyMethodsImpl {
fn py_methods() -> Vec<&'static PyMethodDefType> { fn py_methods() -> Vec<&'static PyMethodDefType> {
inventory::iter::<Self::Methods> inventory::iter::<Self::Methods>
.into_iter() .into_iter()
.flat_map(PyMethodsInventory::get_methods) .flat_map(PyMethodsInventory::get)
.collect() .collect()
} }
} }

View file

@ -4,7 +4,6 @@
//! Trait and support implementation for implementing number protocol //! Trait and support implementation for implementing number protocol
use crate::class::basic::PyObjectProtocolImpl; use crate::class::basic::PyObjectProtocolImpl;
use crate::class::methods::PyMethodDef;
use crate::err::PyResult; use crate::err::PyResult;
use crate::{ffi, FromPyObject, IntoPy, PyClass, PyObject}; use crate::{ffi, FromPyObject, IntoPy, PyClass, PyObject};
@ -619,14 +618,10 @@ pub trait PyNumberIndexProtocol<'p>: PyNumberProtocol<'p> {
#[doc(hidden)] #[doc(hidden)]
pub trait PyNumberProtocolImpl: PyObjectProtocolImpl { pub trait PyNumberProtocolImpl: PyObjectProtocolImpl {
fn methods() -> Vec<PyMethodDef>;
fn tp_as_number() -> Option<ffi::PyNumberMethods>; fn tp_as_number() -> Option<ffi::PyNumberMethods>;
} }
impl<'p, T> PyNumberProtocolImpl for T { impl<'p, T> PyNumberProtocolImpl for T {
default fn methods() -> Vec<PyMethodDef> {
Vec::new()
}
default fn tp_as_number() -> Option<ffi::PyNumberMethods> { default fn tp_as_number() -> Option<ffi::PyNumberMethods> {
if let Some(nb_bool) = <Self as PyObjectProtocolImpl>::nb_bool_fn() { if let Some(nb_bool) = <Self as PyObjectProtocolImpl>::nb_bool_fn() {
let meth = ffi::PyNumberMethods { let meth = ffi::PyNumberMethods {
@ -684,62 +679,6 @@ where
nb_inplace_matrix_multiply: Self::nb_inplace_matrix_multiply(), 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 { 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 // Fallback trait for nb_add
trait PyNumberAddFallback { trait PyNumberAddFallback {
fn nb_add_fallback() -> Option<ffi::binaryfunc>; 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 { trait PyNumberSubFallback {
fn nb_sub_fallback() -> Option<ffi::binaryfunc>; 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 { trait PyNumberMulFallback {
fn nb_mul_fallback() -> Option<ffi::binaryfunc>; 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 { trait PyNumberMatmulFallback {
fn nb_matmul_fallback() -> Option<ffi::binaryfunc>; 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 { trait PyNumberTruedivFallback {
fn nb_truediv_fallback() -> Option<ffi::binaryfunc>; 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 { trait PyNumberFloordivFallback {
fn nb_floordiv_fallback() -> Option<ffi::binaryfunc>; 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 { trait PyNumberModFallback {
fn nb_mod_fallback() -> Option<ffi::binaryfunc>; 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 { trait PyNumberDivmodFallback {
fn nb_divmod_fallback() -> Option<ffi::binaryfunc>; 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 { trait PyNumberPowFallback {
fn nb_pow_fallback() -> Option<ffi::ternaryfunc>; 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 { trait PyNumberLShiftFallback {
fn nb_lshift_fallback() -> Option<ffi::binaryfunc>; 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 { trait PyNumberRRshiftFallback {
fn nb_rshift_fallback() -> Option<ffi::binaryfunc>; 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 { trait PyNumberAndFallback {
fn nb_and_fallback() -> Option<ffi::binaryfunc>; 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 { trait PyNumberXorFallback {
fn nb_xor_fallback() -> Option<ffi::binaryfunc>; 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 { trait PyNumberOrFallback {
fn nb_or_fallback() -> Option<ffi::binaryfunc>; fn nb_or_fallback() -> Option<ffi::binaryfunc>;
} }
@ -1995,29 +1738,3 @@ where
py_unary_func!(PyNumberIndexProtocol, T::__index__) 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/) //! [PEP-0492](https://www.python.org/dev/peps/pep-0492/)
//! //!
use crate::class::methods::PyMethodDef;
use crate::err::PyResult; use crate::err::PyResult;
use crate::{ffi, PyClass, PyObject}; use crate::{ffi, PyClass, PyObject};
@ -89,17 +88,12 @@ pub trait PyAsyncAexitProtocol<'p>: PyAsyncProtocol<'p> {
#[doc(hidden)] #[doc(hidden)]
pub trait PyAsyncProtocolImpl { pub trait PyAsyncProtocolImpl {
fn tp_as_async() -> Option<ffi::PyAsyncMethods>; fn tp_as_async() -> Option<ffi::PyAsyncMethods>;
fn methods() -> Vec<PyMethodDef>;
} }
impl<T> PyAsyncProtocolImpl for T { impl<T> PyAsyncProtocolImpl for T {
default fn tp_as_async() -> Option<ffi::PyAsyncMethods> { default fn tp_as_async() -> Option<ffi::PyAsyncMethods> {
None None
} }
default fn methods() -> Vec<PyMethodDef> {
Vec::new()
}
} }
impl<'p, T> PyAsyncProtocolImpl for T impl<'p, T> PyAsyncProtocolImpl for T
@ -114,20 +108,6 @@ where
am_anext: Self::am_anext(), 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 { 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 // normal methods
if !methods.is_empty() { if !methods.is_empty() {
methods.push(ffi::PyMethodDef_INIT); 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 // class attributes
@ -197,7 +197,7 @@ where
} }
if !props.is_empty() { if !props.is_empty() {
props.push(ffi::PyGetSetDef_INIT); 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 // 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) (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> { fn py_class_properties<T: PyMethodsImpl>() -> Vec<ffi::PyGetSetDef> {
let mut defs = std::collections::HashMap::new(); let mut defs = std::collections::HashMap::new();

View file

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

View file

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

View file

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