Encapsule slot_setter's behavior to an iterator
This commit is contained in:
parent
71a7a76227
commit
3e958bf607
|
@ -44,6 +44,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|||
- Improve lifetime elision in `#[pyproto]`. [#1093](https://github.com/PyO3/pyo3/pull/1093)
|
||||
- Fix python configuration detection when cross-compiling. [#1095](https://github.com/PyO3/pyo3/pull/1095)
|
||||
- Link against libpython on android with `extension-module` set. [#1095](https://github.com/PyO3/pyo3/pull/1095)
|
||||
- Fix support for both `__add__` and `__radd__` in the `+` operator when both are defined in `PyNumberProtocol`
|
||||
(and similar for all other reversible operators). [#1107](https://github.com/PyO3/pyo3/pull/1107)
|
||||
|
||||
## [0.11.1] - 2020-06-30
|
||||
### Added
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||
use crate::proto_method::MethodProto;
|
||||
use std::collections::HashSet;
|
||||
|
||||
/// Predicates for `#[pyproto]`.
|
||||
pub struct Proto {
|
||||
|
@ -14,7 +15,7 @@ pub struct Proto {
|
|||
/// All methods registered as normal methods like `#[pymethods]`.
|
||||
pub py_methods: &'static [PyMethod],
|
||||
/// All methods registered to the slot table.
|
||||
pub slot_setters: &'static [SlotSetter],
|
||||
slot_setters: &'static [SlotSetter],
|
||||
}
|
||||
|
||||
impl Proto {
|
||||
|
@ -30,6 +31,28 @@ impl Proto {
|
|||
{
|
||||
self.py_methods.iter().find(|m| query == m.name)
|
||||
}
|
||||
// Since the order matters, we expose only the iterator instead of the slice.
|
||||
pub(crate) fn setters(
|
||||
&self,
|
||||
mut implemented_protocols: HashSet<String>,
|
||||
) -> impl Iterator<Item = &'static str> {
|
||||
self.slot_setters.iter().filter_map(move |setter| {
|
||||
// If any required method is not implemented, we skip this setter.
|
||||
if setter
|
||||
.proto_names
|
||||
.iter()
|
||||
.any(|name| !implemented_protocols.contains(*name))
|
||||
{
|
||||
return None;
|
||||
}
|
||||
// To use 'paired' setter in priority, we remove used protocols.
|
||||
// For example, if set_add_radd is already used, we shouldn't use set_add and set_radd.
|
||||
for name in setter.proto_names {
|
||||
implemented_protocols.remove(*name);
|
||||
}
|
||||
Some(setter.set_function)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a method registered as a normal method like `#[pymethods]`.
|
||||
|
@ -59,7 +82,7 @@ impl PyMethod {
|
|||
}
|
||||
|
||||
/// Represents a setter used to register a method to the method table.
|
||||
pub struct SlotSetter {
|
||||
struct SlotSetter {
|
||||
/// Protocols necessary for invoking this setter.
|
||||
/// E.g., we need `__setattr__` and `__delattr__` for invoking `set_setdelitem`.
|
||||
pub proto_names: &'static [&'static str],
|
||||
|
|
|
@ -134,24 +134,11 @@ fn slot_initialization(
|
|||
ty: &syn::Type,
|
||||
proto: &defs::Proto,
|
||||
) -> syn::Result<TokenStream> {
|
||||
// To skip used protocols.
|
||||
// E.g., if __set__ and __del__ exist, we use set_set_del and skip set_set.
|
||||
let mut used_protocols = HashSet::new();
|
||||
// Collect initializers
|
||||
let mut initializers: Vec<TokenStream> = vec![];
|
||||
for m in proto.slot_setters {
|
||||
// Skip if any required protocol are not implemented or already used.
|
||||
if m.proto_names
|
||||
.iter()
|
||||
.any(|name| !method_names.contains(*name) || used_protocols.contains(name))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for name in m.proto_names {
|
||||
used_protocols.insert(name);
|
||||
}
|
||||
for setter in proto.setters(method_names) {
|
||||
// Add slot methods to PyProtoRegistry
|
||||
let set = syn::Ident::new(m.set_function, Span::call_site());
|
||||
let set = syn::Ident::new(setter, Span::call_site());
|
||||
initializers.push(quote! { table.#set::<#ty>(); });
|
||||
}
|
||||
if initializers.is_empty() {
|
||||
|
|
|
@ -125,7 +125,7 @@ macro_rules! py_binary_fallback_num_func {
|
|||
match (lhs.extract(), rhs.extract()) {
|
||||
(Ok(l), Ok(r)) => $class::$lop(l, r).convert(py),
|
||||
_ => {
|
||||
// Next, try the right hand method (e.g., __add__)
|
||||
// Next, try the right hand method (e.g., __radd__)
|
||||
let slf: &$crate::PyCell<T> = extract_or_return_not_implemented!(rhs);
|
||||
let arg = extract_or_return_not_implemented!(lhs);
|
||||
$class::$rop(&*slf.try_borrow()?, arg).convert(py)
|
||||
|
|
Loading…
Reference in New Issue