Merge pull request #961 from kngwyu/slot-provider
Object protocols without specialization
This commit is contained in:
commit
390ff5f17f
|
@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|||
- Change return type of `PyTuple::as_slice` to `&[&PyAny]`. [#971](https://github.com/PyO3/pyo3/pull/971)
|
||||
- Update `num-complex` optional dependendency from `0.2` to `0.3`. [#977](https://github.com/PyO3/pyo3/pull/977)
|
||||
- Update `num-bigint` optional dependendency from `0.2` to `0.3`. [#978](https://github.com/PyO3/pyo3/pull/978)
|
||||
- `#[pyproto]` is re-implemented without specialization. [#961](https://github.com/PyO3/pyo3/pull/961)
|
||||
|
||||
### Removed
|
||||
- Remove `ManagedPyRef` (unused, and needs specialization) [#930](https://github.com/PyO3/pyo3/pull/930)
|
||||
|
|
|
@ -19,6 +19,7 @@ travis-ci = { repository = "PyO3/pyo3", branch = "master" }
|
|||
appveyor = { repository = "fafhrd91/pyo3" }
|
||||
|
||||
[dependencies]
|
||||
ctor = { version = "0.1", optional = true }
|
||||
indoc = { version = "0.3.4", optional = true }
|
||||
inventory = { version = "0.1.4", optional = true }
|
||||
libc = "0.2.62"
|
||||
|
@ -38,7 +39,7 @@ version_check = "0.9.1"
|
|||
|
||||
[features]
|
||||
default = ["macros"]
|
||||
macros = ["indoc", "inventory", "paste", "pyo3cls", "unindent"]
|
||||
macros = ["ctor", "indoc", "inventory", "paste", "pyo3cls", "unindent"]
|
||||
|
||||
# this is no longer needed internally, but setuptools-rust assumes this feature
|
||||
python3 = []
|
||||
|
|
|
@ -956,6 +956,14 @@ impl pyo3::class::methods::HasMethodsInventory for MyClass {
|
|||
type Methods = Pyo3MethodsInventoryForMyClass;
|
||||
}
|
||||
pyo3::inventory::collect!(Pyo3MethodsInventoryForMyClass);
|
||||
|
||||
impl pyo3::class::proto_methods::HasProtoRegistry for MyClass {
|
||||
fn registry() -> &'static pyo3::class::proto_methods::PyProtoRegistry {
|
||||
static REGISTRY: pyo3::class::proto_methods::PyProtoRegistry
|
||||
= pyo3::class::proto_methods::PyProtoRegistry::new();
|
||||
®ISTRY
|
||||
}
|
||||
}
|
||||
# let gil = Python::acquire_gil();
|
||||
# let py = gil.python();
|
||||
# let cls = py.get_type::<MyClass>();
|
||||
|
|
|
@ -1,10 +1,20 @@
|
|||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||
use crate::func::MethodProto;
|
||||
|
||||
/// Predicates for `#[pyproto]`.
|
||||
pub struct Proto {
|
||||
/// The name of this protocol. E.g., Iter.
|
||||
pub name: &'static str,
|
||||
/// The name of slot table. E.g., PyIterMethods.
|
||||
pub slot_table: &'static str,
|
||||
/// The name of the setter used to set the table to `PyProtoRegistry`.
|
||||
pub set_slot_table: &'static str,
|
||||
/// All methods.
|
||||
pub methods: &'static [MethodProto],
|
||||
/// 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],
|
||||
}
|
||||
|
||||
impl Proto {
|
||||
|
@ -22,6 +32,7 @@ impl Proto {
|
|||
}
|
||||
}
|
||||
|
||||
/// Represents a method registered as a normal method like `#[pymethods]`.
|
||||
// TODO(kngwyu): Currently only __radd__-like methods use METH_COEXIST to prevent
|
||||
// __add__-like methods from overriding them.
|
||||
pub struct PyMethod {
|
||||
|
@ -47,8 +58,33 @@ impl PyMethod {
|
|||
}
|
||||
}
|
||||
|
||||
/// Represents a setter used to register a method to the method table.
|
||||
pub 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],
|
||||
/// The name of the setter called to the method table.
|
||||
pub set_function: &'static str,
|
||||
/// Represents a set of setters disabled by this setter.
|
||||
/// E.g., `set_setdelitem` have to disable `set_setitem` and `set_delitem`.
|
||||
pub skipped_setters: &'static [&'static str],
|
||||
}
|
||||
|
||||
impl SlotSetter {
|
||||
const EMPTY_SETTERS: &'static [&'static str] = &[];
|
||||
const fn new(names: &'static [&'static str], set_function: &'static str) -> Self {
|
||||
SlotSetter {
|
||||
proto_names: names,
|
||||
set_function,
|
||||
skipped_setters: Self::EMPTY_SETTERS,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const OBJECT: Proto = Proto {
|
||||
name: "Object",
|
||||
slot_table: "pyo3::class::basic::PyObjectMethods",
|
||||
set_slot_table: "set_basic_methods",
|
||||
methods: &[
|
||||
MethodProto::Binary {
|
||||
name: "__getattr__",
|
||||
|
@ -95,40 +131,60 @@ pub const OBJECT: Proto = Proto {
|
|||
pyres: true,
|
||||
proto: "pyo3::class::basic::PyObjectBytesProtocol",
|
||||
},
|
||||
MethodProto::Unary {
|
||||
name: "__bool__",
|
||||
pyres: false,
|
||||
proto: "pyo3::class::basic::PyObjectBoolProtocol",
|
||||
},
|
||||
MethodProto::Binary {
|
||||
name: "__richcmp__",
|
||||
arg: "Other",
|
||||
pyres: true,
|
||||
proto: "pyo3::class::basic::PyObjectRichcmpProtocol",
|
||||
},
|
||||
MethodProto::Unary {
|
||||
name: "__bool__",
|
||||
pyres: false,
|
||||
proto: "pyo3::class::basic::PyObjectBoolProtocol",
|
||||
},
|
||||
],
|
||||
py_methods: &[
|
||||
PyMethod::new("__format__", "pyo3::class::basic::FormatProtocolImpl"),
|
||||
PyMethod::new("__bytes__", "pyo3::class::basic::BytesProtocolImpl"),
|
||||
PyMethod::new("__unicode__", "pyo3::class::basic::UnicodeProtocolImpl"),
|
||||
],
|
||||
slot_setters: &[
|
||||
SlotSetter::new(&["__str__"], "set_str"),
|
||||
SlotSetter::new(&["__repr__"], "set_repr"),
|
||||
SlotSetter::new(&["__hash__"], "set_hash"),
|
||||
SlotSetter::new(&["__getattr__"], "set_getattr"),
|
||||
SlotSetter::new(&["__richcmp__"], "set_richcompare"),
|
||||
SlotSetter {
|
||||
proto_names: &["__setattr__", "__delattr__"],
|
||||
set_function: "set_setdelattr",
|
||||
skipped_setters: &["set_setattr", "set_delattr"],
|
||||
},
|
||||
SlotSetter::new(&["__setattr__"], "set_setattr"),
|
||||
SlotSetter::new(&["__delattr__"], "set_delattr"),
|
||||
SlotSetter::new(&["__bool__"], "set_bool"),
|
||||
],
|
||||
};
|
||||
|
||||
pub const ASYNC: Proto = Proto {
|
||||
name: "Async",
|
||||
slot_table: "pyo3::ffi::PyAsyncMethods",
|
||||
set_slot_table: "set_async_methods",
|
||||
methods: &[
|
||||
MethodProto::Unary {
|
||||
MethodProto::UnaryS {
|
||||
name: "__await__",
|
||||
arg: "Receiver",
|
||||
pyres: true,
|
||||
proto: "pyo3::class::pyasync::PyAsyncAwaitProtocol",
|
||||
},
|
||||
MethodProto::Unary {
|
||||
MethodProto::UnaryS {
|
||||
name: "__aiter__",
|
||||
arg: "Receiver",
|
||||
pyres: true,
|
||||
proto: "pyo3::class::pyasync::PyAsyncAiterProtocol",
|
||||
},
|
||||
MethodProto::Unary {
|
||||
MethodProto::UnaryS {
|
||||
name: "__anext__",
|
||||
arg: "Receiver",
|
||||
pyres: true,
|
||||
proto: "pyo3::class::pyasync::PyAsyncAnextProtocol",
|
||||
},
|
||||
|
@ -155,10 +211,17 @@ pub const ASYNC: Proto = Proto {
|
|||
"pyo3::class::pyasync::PyAsyncAexitProtocolImpl",
|
||||
),
|
||||
],
|
||||
slot_setters: &[
|
||||
SlotSetter::new(&["__await__"], "set_await"),
|
||||
SlotSetter::new(&["__aiter__"], "set_aiter"),
|
||||
SlotSetter::new(&["__anext__"], "set_anext"),
|
||||
],
|
||||
};
|
||||
|
||||
pub const BUFFER: Proto = Proto {
|
||||
name: "Buffer",
|
||||
slot_table: "pyo3::ffi::PyBufferProcs",
|
||||
set_slot_table: "set_buffer_methods",
|
||||
methods: &[
|
||||
MethodProto::Unary {
|
||||
name: "bf_getbuffer",
|
||||
|
@ -172,10 +235,16 @@ pub const BUFFER: Proto = Proto {
|
|||
},
|
||||
],
|
||||
py_methods: &[],
|
||||
slot_setters: &[
|
||||
SlotSetter::new(&["bf_getbuffer"], "set_getbuffer"),
|
||||
SlotSetter::new(&["bf_releasebuffer"], "set_releasebuffer"),
|
||||
],
|
||||
};
|
||||
|
||||
pub const CONTEXT: Proto = Proto {
|
||||
name: "Context",
|
||||
slot_table: "",
|
||||
set_slot_table: "",
|
||||
methods: &[
|
||||
MethodProto::Unary {
|
||||
name: "__enter__",
|
||||
|
@ -200,10 +269,13 @@ pub const CONTEXT: Proto = Proto {
|
|||
"pyo3::class::context::PyContextExitProtocolImpl",
|
||||
),
|
||||
],
|
||||
slot_setters: &[],
|
||||
};
|
||||
|
||||
pub const GC: Proto = Proto {
|
||||
name: "GC",
|
||||
slot_table: "pyo3::class::gc::PyGCMethods",
|
||||
set_slot_table: "set_gc_methods",
|
||||
methods: &[
|
||||
MethodProto::Free {
|
||||
name: "__traverse__",
|
||||
|
@ -215,23 +287,31 @@ pub const GC: Proto = Proto {
|
|||
},
|
||||
],
|
||||
py_methods: &[],
|
||||
slot_setters: &[
|
||||
SlotSetter::new(&["__traverse__"], "set_traverse"),
|
||||
SlotSetter::new(&["__clear__"], "set_clear"),
|
||||
],
|
||||
};
|
||||
|
||||
pub const DESCR: Proto = Proto {
|
||||
name: "Descriptor",
|
||||
slot_table: "pyo3::class::descr::PyDescrMethods",
|
||||
set_slot_table: "set_descr_methods",
|
||||
methods: &[
|
||||
MethodProto::Ternary {
|
||||
MethodProto::TernaryS {
|
||||
name: "__get__",
|
||||
arg1: "Inst",
|
||||
arg2: "Owner",
|
||||
arg1: "Receiver",
|
||||
arg2: "Inst",
|
||||
arg3: "Owner",
|
||||
pyres: true,
|
||||
proto: "pyo3::class::descr::PyDescrGetProtocol",
|
||||
},
|
||||
MethodProto::Ternary {
|
||||
MethodProto::TernaryS {
|
||||
name: "__set__",
|
||||
arg1: "Inst",
|
||||
arg2: "Value",
|
||||
pyres: true,
|
||||
arg1: "Receiver",
|
||||
arg2: "Inst",
|
||||
arg3: "Value",
|
||||
pyres: false,
|
||||
proto: "pyo3::class::descr::PyDescrSetProtocol",
|
||||
},
|
||||
MethodProto::Binary {
|
||||
|
@ -254,10 +334,16 @@ pub const DESCR: Proto = Proto {
|
|||
"pyo3::class::context::PyDescrNameProtocolImpl",
|
||||
),
|
||||
],
|
||||
slot_setters: &[
|
||||
SlotSetter::new(&["__get__"], "set_descr_get"),
|
||||
SlotSetter::new(&["__set__"], "set_descr_set"),
|
||||
],
|
||||
};
|
||||
|
||||
pub const ITER: Proto = Proto {
|
||||
name: "Iter",
|
||||
slot_table: "pyo3::class::iter::PyIterMethods",
|
||||
set_slot_table: "set_iter_methods",
|
||||
py_methods: &[],
|
||||
methods: &[
|
||||
MethodProto::UnaryS {
|
||||
|
@ -273,10 +359,16 @@ pub const ITER: Proto = Proto {
|
|||
proto: "pyo3::class::iter::PyIterNextProtocol",
|
||||
},
|
||||
],
|
||||
slot_setters: &[
|
||||
SlotSetter::new(&["__iter__"], "set_iter"),
|
||||
SlotSetter::new(&["__next__"], "set_iternext"),
|
||||
],
|
||||
};
|
||||
|
||||
pub const MAPPING: Proto = Proto {
|
||||
name: "Mapping",
|
||||
slot_table: "pyo3::ffi::PyMappingMethods",
|
||||
set_slot_table: "set_mapping_methods",
|
||||
methods: &[
|
||||
MethodProto::Unary {
|
||||
name: "__len__",
|
||||
|
@ -312,10 +404,23 @@ pub const MAPPING: Proto = Proto {
|
|||
"__reversed__",
|
||||
"pyo3::class::mapping::PyMappingReversedProtocolImpl",
|
||||
)],
|
||||
slot_setters: &[
|
||||
SlotSetter::new(&["__len__"], "set_length"),
|
||||
SlotSetter::new(&["__getitem__"], "set_getitem"),
|
||||
SlotSetter {
|
||||
proto_names: &["__setitem__", "__delitem__"],
|
||||
set_function: "set_setdelitem",
|
||||
skipped_setters: &["set_setitem", "set_delitem"],
|
||||
},
|
||||
SlotSetter::new(&["__setitem__"], "set_setitem"),
|
||||
SlotSetter::new(&["__delitem__"], "set_delitem"),
|
||||
],
|
||||
};
|
||||
|
||||
pub const SEQ: Proto = Proto {
|
||||
name: "Sequence",
|
||||
slot_table: "pyo3::ffi::PySequenceMethods",
|
||||
set_slot_table: "set_sequence_methods",
|
||||
methods: &[
|
||||
MethodProto::Unary {
|
||||
name: "__len__",
|
||||
|
@ -373,10 +478,28 @@ pub const SEQ: Proto = Proto {
|
|||
},
|
||||
],
|
||||
py_methods: &[],
|
||||
slot_setters: &[
|
||||
SlotSetter::new(&["__len__"], "set_len"),
|
||||
SlotSetter::new(&["__concat__"], "set_concat"),
|
||||
SlotSetter::new(&["__repeat__"], "set_repeat"),
|
||||
SlotSetter::new(&["__getitem__"], "set_getitem"),
|
||||
SlotSetter {
|
||||
proto_names: &["__setitem__", "__delitem__"],
|
||||
set_function: "set_setdelitem",
|
||||
skipped_setters: &["set_setitem", "set_delitem"],
|
||||
},
|
||||
SlotSetter::new(&["__setitem__"], "set_setitem"),
|
||||
SlotSetter::new(&["__delitem__"], "set_delitem"),
|
||||
SlotSetter::new(&["__contains__"], "set_contains"),
|
||||
SlotSetter::new(&["__inplace_concat__"], "set_inplace_concat"),
|
||||
SlotSetter::new(&["__inplace_repeat__"], "set_inplace_repeat"),
|
||||
],
|
||||
};
|
||||
|
||||
pub const NUM: Proto = Proto {
|
||||
name: "Number",
|
||||
slot_table: "pyo3::ffi::PyNumberMethods",
|
||||
set_slot_table: "set_number_methods",
|
||||
methods: &[
|
||||
MethodProto::BinaryS {
|
||||
name: "__add__",
|
||||
|
@ -729,4 +852,106 @@ pub const NUM: Proto = Proto {
|
|||
"pyo3::class::number::PyNumberRoundProtocolImpl",
|
||||
),
|
||||
],
|
||||
slot_setters: &[
|
||||
SlotSetter {
|
||||
proto_names: &["__add__"],
|
||||
set_function: "set_add",
|
||||
skipped_setters: &["set_radd"],
|
||||
},
|
||||
SlotSetter::new(&["__radd__"], "set_radd"),
|
||||
SlotSetter {
|
||||
proto_names: &["__sub__"],
|
||||
set_function: "set_sub",
|
||||
skipped_setters: &["set_rsub"],
|
||||
},
|
||||
SlotSetter::new(&["__rsub__"], "set_rsub"),
|
||||
SlotSetter {
|
||||
proto_names: &["__mul__"],
|
||||
set_function: "set_mul",
|
||||
skipped_setters: &["set_rmul"],
|
||||
},
|
||||
SlotSetter::new(&["__rmul__"], "set_rmul"),
|
||||
SlotSetter::new(&["__mod__"], "set_mod"),
|
||||
SlotSetter {
|
||||
proto_names: &["__divmod__"],
|
||||
set_function: "set_divmod",
|
||||
skipped_setters: &["set_rdivmod"],
|
||||
},
|
||||
SlotSetter::new(&["__rdivmod__"], "set_rdivmod"),
|
||||
SlotSetter {
|
||||
proto_names: &["__pow__"],
|
||||
set_function: "set_pow",
|
||||
skipped_setters: &["set_rpow"],
|
||||
},
|
||||
SlotSetter::new(&["__rpow__"], "set_rpow"),
|
||||
SlotSetter::new(&["__neg__"], "set_neg"),
|
||||
SlotSetter::new(&["__pos__"], "set_pos"),
|
||||
SlotSetter::new(&["__abs__"], "set_abs"),
|
||||
SlotSetter::new(&["__invert__"], "set_invert"),
|
||||
SlotSetter::new(&["__rdivmod__"], "set_rdivmod"),
|
||||
SlotSetter {
|
||||
proto_names: &["__lshift__"],
|
||||
set_function: "set_lshift",
|
||||
skipped_setters: &["set_rlshift"],
|
||||
},
|
||||
SlotSetter::new(&["__rlshift__"], "set_rlshift"),
|
||||
SlotSetter {
|
||||
proto_names: &["__rshift__"],
|
||||
set_function: "set_rshift",
|
||||
skipped_setters: &["set_rrshift"],
|
||||
},
|
||||
SlotSetter::new(&["__rrshift__"], "set_rrshift"),
|
||||
SlotSetter {
|
||||
proto_names: &["__and__"],
|
||||
set_function: "set_and",
|
||||
skipped_setters: &["set_rand"],
|
||||
},
|
||||
SlotSetter::new(&["__rand__"], "set_rand"),
|
||||
SlotSetter {
|
||||
proto_names: &["__xor__"],
|
||||
set_function: "set_xor",
|
||||
skipped_setters: &["set_rxor"],
|
||||
},
|
||||
SlotSetter::new(&["__rxor__"], "set_rxor"),
|
||||
SlotSetter {
|
||||
proto_names: &["__or__"],
|
||||
set_function: "set_or",
|
||||
skipped_setters: &["set_ror"],
|
||||
},
|
||||
SlotSetter::new(&["__ror__"], "set_ror"),
|
||||
SlotSetter::new(&["__int__"], "set_int"),
|
||||
SlotSetter::new(&["__float__"], "set_float"),
|
||||
SlotSetter::new(&["__iadd__"], "set_iadd"),
|
||||
SlotSetter::new(&["__isub__"], "set_isub"),
|
||||
SlotSetter::new(&["__imul__"], "set_imul"),
|
||||
SlotSetter::new(&["__imod__"], "set_imod"),
|
||||
SlotSetter::new(&["__ipow__"], "set_ipow"),
|
||||
SlotSetter::new(&["__ilshift__"], "set_ilshift"),
|
||||
SlotSetter::new(&["__irshift__"], "set_irshift"),
|
||||
SlotSetter::new(&["__iand__"], "set_iand"),
|
||||
SlotSetter::new(&["__ixor__"], "set_ixor"),
|
||||
SlotSetter::new(&["__ior__"], "set_ior"),
|
||||
SlotSetter {
|
||||
proto_names: &["__floordiv__"],
|
||||
set_function: "set_floordiv",
|
||||
skipped_setters: &["set_rfloordiv"],
|
||||
},
|
||||
SlotSetter::new(&["__rfloordiv__"], "set_rfloordiv"),
|
||||
SlotSetter {
|
||||
proto_names: &["__truediv__"],
|
||||
set_function: "set_truediv",
|
||||
skipped_setters: &["set_rtruediv"],
|
||||
},
|
||||
SlotSetter::new(&["__rtruediv__"], "set_rtruediv"),
|
||||
SlotSetter::new(&["__ifloordiv__"], "set_ifloordiv"),
|
||||
SlotSetter::new(&["__itruediv__"], "set_itruediv"),
|
||||
SlotSetter::new(&["__index__"], "set_index"),
|
||||
SlotSetter {
|
||||
proto_names: &["__matmul__"],
|
||||
set_function: "set_matmul",
|
||||
skipped_setters: &["set_rmatmul"],
|
||||
},
|
||||
SlotSetter::new(&["__rmatmul__"], "set_rmatmul"),
|
||||
SlotSetter::new(&["__imatmul__"], "set_imatmul"),
|
||||
],
|
||||
};
|
||||
|
|
|
@ -236,6 +236,19 @@ fn impl_methods_inventory(cls: &syn::Ident) -> TokenStream {
|
|||
}
|
||||
}
|
||||
|
||||
/// Implement `HasProtoRegistry` for the class for lazy protocol initialization.
|
||||
fn impl_proto_registry(cls: &syn::Ident) -> TokenStream {
|
||||
quote! {
|
||||
impl pyo3::class::proto_methods::HasProtoRegistry for #cls {
|
||||
fn registry() -> &'static pyo3::class::proto_methods::PyProtoRegistry {
|
||||
static REGISTRY: pyo3::class::proto_methods::PyProtoRegistry
|
||||
= pyo3::class::proto_methods::PyProtoRegistry::new();
|
||||
®ISTRY
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_class_python_name(cls: &syn::Ident, attr: &PyClassArgs) -> TokenStream {
|
||||
match &attr.name {
|
||||
Some(name) => quote! { #name },
|
||||
|
@ -340,6 +353,7 @@ fn impl_class(
|
|||
};
|
||||
|
||||
let impl_inventory = impl_methods_inventory(&cls);
|
||||
let impl_proto_registry = impl_proto_registry(&cls);
|
||||
|
||||
let base = &attr.base;
|
||||
let flags = &attr.flags;
|
||||
|
@ -414,6 +428,8 @@ fn impl_class(
|
|||
|
||||
#impl_inventory
|
||||
|
||||
#impl_proto_registry
|
||||
|
||||
#extra
|
||||
|
||||
#gc_impl
|
||||
|
|
|
@ -4,9 +4,10 @@ use crate::defs;
|
|||
use crate::func::impl_method_proto;
|
||||
use crate::method::FnSpec;
|
||||
use crate::pymethod;
|
||||
use proc_macro2::TokenStream;
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::quote;
|
||||
use quote::ToTokens;
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub fn build_py_proto(ast: &mut syn::ItemImpl) -> syn::Result<TokenStream> {
|
||||
if let Some((_, ref mut path, _)) = ast.trait_ {
|
||||
|
@ -60,12 +61,17 @@ fn impl_proto_impl(
|
|||
) -> syn::Result<TokenStream> {
|
||||
let mut trait_impls = TokenStream::new();
|
||||
let mut py_methods = Vec::new();
|
||||
let mut method_names = HashSet::new();
|
||||
|
||||
for iimpl in impls.iter_mut() {
|
||||
if let syn::ImplItem::Method(ref mut met) = iimpl {
|
||||
// impl Py~Protocol<'p> { type = ... }
|
||||
if let Some(m) = proto.get_proto(&met.sig.ident) {
|
||||
impl_method_proto(ty, &mut met.sig, m).to_tokens(&mut trait_impls);
|
||||
// Insert the method to the HashSet
|
||||
method_names.insert(met.sig.ident.to_string());
|
||||
}
|
||||
// Add non-slot methods to inventory like `#[pymethods]`
|
||||
if let Some(m) = proto.get_method(&met.sig.ident) {
|
||||
let name = &met.sig.ident;
|
||||
let fn_spec = FnSpec::parse(&met.sig, &mut met.attrs, false)?;
|
||||
|
@ -76,7 +82,7 @@ fn impl_proto_impl(
|
|||
} else {
|
||||
quote!(0)
|
||||
};
|
||||
// TODO(kngwyu): doc
|
||||
// TODO(kngwyu): Set ml_doc
|
||||
py_methods.push(quote! {
|
||||
pyo3::class::PyMethodDefType::Method({
|
||||
#method
|
||||
|
@ -91,20 +97,78 @@ fn impl_proto_impl(
|
|||
}
|
||||
}
|
||||
}
|
||||
let inventory_submission = inventory_submission(py_methods, ty);
|
||||
let slot_initialization = slot_initialization(method_names, ty, proto)?;
|
||||
Ok(quote! {
|
||||
#trait_impls
|
||||
#inventory_submission
|
||||
#slot_initialization
|
||||
})
|
||||
}
|
||||
|
||||
fn inventory_submission(py_methods: Vec<TokenStream>, ty: &syn::Type) -> TokenStream {
|
||||
if py_methods.is_empty() {
|
||||
return Ok(quote! { #trait_impls });
|
||||
return quote! {};
|
||||
}
|
||||
let inventory_submission = quote! {
|
||||
quote! {
|
||||
pyo3::inventory::submit! {
|
||||
#![crate = pyo3] {
|
||||
type Inventory = <#ty as pyo3::class::methods::HasMethodsInventory>::Methods;
|
||||
<Inventory as pyo3::class::methods::PyMethodsInventory>::new(&[#(#py_methods),*])
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn slot_initialization(
|
||||
method_names: HashSet<String>,
|
||||
ty: &syn::Type,
|
||||
proto: &defs::Proto,
|
||||
) -> syn::Result<TokenStream> {
|
||||
// Some setters cannot coexist.
|
||||
// E.g., if we have `__add__`, we need to skip `set_radd`.
|
||||
let mut skipped_setters = Vec::new();
|
||||
// Collect initializers
|
||||
let mut initializers: Vec<TokenStream> = vec![];
|
||||
'outer_loop: for m in proto.slot_setters {
|
||||
if skipped_setters.contains(&m.set_function) {
|
||||
continue;
|
||||
}
|
||||
for name in m.proto_names {
|
||||
// If this `#[pyproto]` block doesn't provide all required methods,
|
||||
// let's skip implementing this method.
|
||||
if !method_names.contains(*name) {
|
||||
continue 'outer_loop;
|
||||
}
|
||||
}
|
||||
skipped_setters.extend_from_slice(m.skipped_setters);
|
||||
// Add slot methods to PyProtoRegistry
|
||||
let set = syn::Ident::new(m.set_function, Span::call_site());
|
||||
initializers.push(quote! { table.#set::<#ty>(); });
|
||||
}
|
||||
if initializers.is_empty() {
|
||||
return Ok(quote! {});
|
||||
}
|
||||
let table: syn::Path = syn::parse_str(proto.slot_table)?;
|
||||
let set = syn::Ident::new(proto.set_slot_table, Span::call_site());
|
||||
let ty_hash = typename_hash(ty);
|
||||
let init = syn::Ident::new(
|
||||
&format!("__init_{}_{}", proto.name, ty_hash),
|
||||
Span::call_site(),
|
||||
);
|
||||
Ok(quote! {
|
||||
#trait_impls
|
||||
#inventory_submission
|
||||
#[pyo3::ctor::ctor]
|
||||
fn #init() {
|
||||
let mut table = #table::default();
|
||||
#(#initializers)*
|
||||
<#ty as pyo3::class::proto_methods::HasProtoRegistry>::registry().#set(table);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn typename_hash(ty: &syn::Type) -> u64 {
|
||||
use std::hash::{Hash, Hasher};
|
||||
let mut hasher = std::collections::hash_map::DefaultHasher::new();
|
||||
ty.hash(&mut hasher);
|
||||
hasher.finish()
|
||||
}
|
||||
|
|
|
@ -77,13 +77,6 @@ pub trait PyObjectProtocol<'p>: PyClass {
|
|||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __bool__(&'p self) -> Self::Result
|
||||
where
|
||||
Self: PyObjectBoolProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __bytes__(&'p self) -> Self::Result
|
||||
where
|
||||
Self: PyObjectBytesProtocol<'p>,
|
||||
|
@ -97,6 +90,12 @@ pub trait PyObjectProtocol<'p>: PyClass {
|
|||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __bool__(&'p self) -> Self::Result
|
||||
where
|
||||
Self: PyObjectBoolProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PyObjectGetAttrProtocol<'p>: PyObjectProtocol<'p> {
|
||||
|
@ -142,311 +141,160 @@ pub trait PyObjectRichcmpProtocol<'p>: PyObjectProtocol<'p> {
|
|||
type Result: Into<PyResult<Self::Success>>;
|
||||
}
|
||||
|
||||
/// All FFI functions for basic protocols.
|
||||
#[derive(Default)]
|
||||
pub struct PyObjectMethods {
|
||||
pub tp_str: Option<ffi::reprfunc>,
|
||||
pub tp_repr: Option<ffi::reprfunc>,
|
||||
pub tp_hash: Option<ffi::hashfunc>,
|
||||
pub tp_getattro: Option<ffi::getattrofunc>,
|
||||
pub tp_richcompare: Option<ffi::richcmpfunc>,
|
||||
pub tp_setattro: Option<ffi::setattrofunc>,
|
||||
pub nb_bool: Option<ffi::inquiry>,
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait PyObjectProtocolImpl {
|
||||
fn tp_as_object(_type_object: &mut ffi::PyTypeObject);
|
||||
fn nb_bool_fn() -> Option<ffi::inquiry>;
|
||||
}
|
||||
|
||||
impl<T> PyObjectProtocolImpl for T {
|
||||
default fn tp_as_object(_type_object: &mut ffi::PyTypeObject) {}
|
||||
default fn nb_bool_fn() -> Option<ffi::inquiry> {
|
||||
None
|
||||
impl PyObjectMethods {
|
||||
pub(crate) fn update_typeobj(&self, type_object: &mut ffi::PyTypeObject) {
|
||||
type_object.tp_str = self.tp_str;
|
||||
type_object.tp_repr = self.tp_repr;
|
||||
type_object.tp_hash = self.tp_hash;
|
||||
type_object.tp_getattro = self.tp_getattro;
|
||||
type_object.tp_richcompare = self.tp_richcompare;
|
||||
type_object.tp_setattro = self.tp_setattro;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, T> PyObjectProtocolImpl for T
|
||||
where
|
||||
T: PyObjectProtocol<'p>,
|
||||
{
|
||||
fn tp_as_object(type_object: &mut ffi::PyTypeObject) {
|
||||
type_object.tp_str = Self::tp_str();
|
||||
type_object.tp_repr = Self::tp_repr();
|
||||
type_object.tp_hash = Self::tp_hash();
|
||||
type_object.tp_getattro = Self::tp_getattro();
|
||||
type_object.tp_richcompare = Self::tp_richcompare();
|
||||
type_object.tp_setattro = tp_setattro_impl::tp_setattro::<Self>();
|
||||
}
|
||||
fn nb_bool_fn() -> Option<ffi::inquiry> {
|
||||
Self::nb_bool()
|
||||
}
|
||||
}
|
||||
|
||||
trait GetAttrProtocolImpl {
|
||||
fn tp_getattro() -> Option<ffi::binaryfunc>;
|
||||
}
|
||||
|
||||
impl<'p, T> GetAttrProtocolImpl for T
|
||||
where
|
||||
T: PyObjectProtocol<'p>,
|
||||
{
|
||||
default fn tp_getattro() -> Option<ffi::binaryfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> GetAttrProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PyObjectGetAttrProtocol<'p>,
|
||||
{
|
||||
fn tp_getattro() -> Option<ffi::binaryfunc> {
|
||||
#[allow(unused_mut)]
|
||||
unsafe extern "C" fn wrap<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
arg: *mut ffi::PyObject,
|
||||
) -> *mut ffi::PyObject
|
||||
where
|
||||
T: for<'p> PyObjectGetAttrProtocol<'p>,
|
||||
{
|
||||
crate::callback_body!(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 Ok(existing);
|
||||
}
|
||||
|
||||
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
|
||||
let arg = py.from_borrowed_ptr::<PyAny>(arg);
|
||||
call_ref!(slf, __getattr__, arg)
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
}
|
||||
}
|
||||
|
||||
/// An object may support setting attributes (by implementing PyObjectSetAttrProtocol)
|
||||
/// and may support deleting attributes (by implementing PyObjectDelAttrProtocol).
|
||||
/// We need to generate a single "extern C" function that supports only setting, only deleting
|
||||
/// or both, and return None in case none of the two is supported.
|
||||
mod tp_setattro_impl {
|
||||
use super::*;
|
||||
|
||||
/// setattrofunc PyTypeObject.tp_setattro
|
||||
///
|
||||
/// An optional pointer to the function for setting and deleting attributes.
|
||||
///
|
||||
/// The signature is the same as for PyObject_SetAttr(), but setting v to NULL to delete an
|
||||
/// attribute must be supported. It is usually convenient to set this field to
|
||||
/// PyObject_GenericSetAttr(), which implements the normal way of setting object attributes.
|
||||
pub(super) fn tp_setattro<'p, T: PyObjectProtocol<'p>>() -> Option<ffi::setattrofunc> {
|
||||
if let Some(set_del) = T::set_del_attr() {
|
||||
Some(set_del)
|
||||
} else if let Some(set) = T::set_attr() {
|
||||
Some(set)
|
||||
} else if let Some(del) = T::del_attr() {
|
||||
Some(del)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
trait SetAttr {
|
||||
fn set_attr() -> Option<ffi::setattrofunc>;
|
||||
}
|
||||
|
||||
impl<'p, T: PyObjectProtocol<'p>> SetAttr for T {
|
||||
default fn set_attr() -> Option<ffi::setattrofunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SetAttr for T
|
||||
// Set functions used by `#[pyproto]`.
|
||||
pub fn set_str<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectSetAttrProtocol<'p>,
|
||||
T: for<'p> PyObjectStrProtocol<'p>,
|
||||
{
|
||||
fn set_attr() -> Option<ffi::setattrofunc> {
|
||||
py_func_set!(PyObjectSetAttrProtocol, T, __setattr__)
|
||||
}
|
||||
self.tp_str = py_unary_func!(PyObjectStrProtocol, T::__str__);
|
||||
}
|
||||
|
||||
trait DelAttr {
|
||||
fn del_attr() -> Option<ffi::setattrofunc>;
|
||||
}
|
||||
|
||||
impl<'p, T> DelAttr for T
|
||||
pub fn set_repr<T>(&mut self)
|
||||
where
|
||||
T: PyObjectProtocol<'p>,
|
||||
T: for<'p> PyObjectReprProtocol<'p>,
|
||||
{
|
||||
default fn del_attr() -> Option<ffi::setattrofunc> {
|
||||
None
|
||||
}
|
||||
self.tp_repr = py_unary_func!(PyObjectReprProtocol, T::__repr__);
|
||||
}
|
||||
|
||||
impl<T> DelAttr for T
|
||||
pub fn set_hash<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectDelAttrProtocol<'p>,
|
||||
T: for<'p> PyObjectHashProtocol<'p>,
|
||||
{
|
||||
fn del_attr() -> Option<ffi::setattrofunc> {
|
||||
py_func_del!(PyObjectDelAttrProtocol, T, __delattr__)
|
||||
}
|
||||
}
|
||||
|
||||
trait SetDelAttr {
|
||||
fn set_del_attr() -> Option<ffi::setattrofunc>;
|
||||
}
|
||||
|
||||
impl<'p, T> SetDelAttr for T
|
||||
where
|
||||
T: PyObjectProtocol<'p>,
|
||||
{
|
||||
default fn set_del_attr() -> Option<ffi::setattrofunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SetDelAttr for T
|
||||
where
|
||||
T: for<'p> PyObjectSetAttrProtocol<'p> + for<'p> PyObjectDelAttrProtocol<'p>,
|
||||
{
|
||||
fn set_del_attr() -> Option<ffi::setattrofunc> {
|
||||
py_func_set_del!(
|
||||
PyObjectSetAttrProtocol,
|
||||
PyObjectDelAttrProtocol,
|
||||
T,
|
||||
__setattr__,
|
||||
__delattr__
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait StrProtocolImpl {
|
||||
fn tp_str() -> Option<ffi::unaryfunc>;
|
||||
}
|
||||
impl<'p, T> StrProtocolImpl for T
|
||||
where
|
||||
T: PyObjectProtocol<'p>,
|
||||
{
|
||||
default fn tp_str() -> Option<ffi::unaryfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
impl<T> StrProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PyObjectStrProtocol<'p>,
|
||||
{
|
||||
fn tp_str() -> Option<ffi::unaryfunc> {
|
||||
py_unary_func!(PyObjectStrProtocol, T::__str__)
|
||||
}
|
||||
}
|
||||
|
||||
trait ReprProtocolImpl {
|
||||
fn tp_repr() -> Option<ffi::unaryfunc>;
|
||||
}
|
||||
impl<'p, T> ReprProtocolImpl for T
|
||||
where
|
||||
T: PyObjectProtocol<'p>,
|
||||
{
|
||||
default fn tp_repr() -> Option<ffi::unaryfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
impl<T> ReprProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PyObjectReprProtocol<'p>,
|
||||
{
|
||||
fn tp_repr() -> Option<ffi::unaryfunc> {
|
||||
py_unary_func!(PyObjectReprProtocol, T::__repr__)
|
||||
}
|
||||
}
|
||||
|
||||
trait HashProtocolImpl {
|
||||
fn tp_hash() -> Option<ffi::hashfunc>;
|
||||
}
|
||||
impl<'p, T> HashProtocolImpl for T
|
||||
where
|
||||
T: PyObjectProtocol<'p>,
|
||||
{
|
||||
default fn tp_hash() -> Option<ffi::hashfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
impl<T> HashProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PyObjectHashProtocol<'p>,
|
||||
{
|
||||
fn tp_hash() -> Option<ffi::hashfunc> {
|
||||
py_unary_func!(
|
||||
self.tp_hash = py_unary_func!(
|
||||
PyObjectHashProtocol,
|
||||
T::__hash__,
|
||||
ffi::Py_hash_t,
|
||||
HashCallbackOutput
|
||||
);
|
||||
}
|
||||
pub fn set_getattr<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectGetAttrProtocol<'p>,
|
||||
{
|
||||
self.tp_getattro = tp_getattro::<T>();
|
||||
}
|
||||
pub fn set_richcompare<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectRichcmpProtocol<'p>,
|
||||
{
|
||||
self.tp_richcompare = tp_richcompare::<T>();
|
||||
}
|
||||
pub fn set_setattr<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectSetAttrProtocol<'p>,
|
||||
{
|
||||
self.tp_setattro = py_func_set!(PyObjectSetAttrProtocol, T, __setattr__);
|
||||
}
|
||||
pub fn set_delattr<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectDelAttrProtocol<'p>,
|
||||
{
|
||||
self.tp_setattro = py_func_del!(PyObjectDelAttrProtocol, T, __delattr__);
|
||||
}
|
||||
pub fn set_setdelattr<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectSetAttrProtocol<'p> + for<'p> PyObjectDelAttrProtocol<'p>,
|
||||
{
|
||||
self.tp_setattro = py_func_set_del!(
|
||||
PyObjectSetAttrProtocol,
|
||||
PyObjectDelAttrProtocol,
|
||||
T,
|
||||
__setattr__,
|
||||
__delattr__
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
trait BoolProtocolImpl {
|
||||
fn nb_bool() -> Option<ffi::inquiry>;
|
||||
}
|
||||
impl<'p, T> BoolProtocolImpl for T
|
||||
where
|
||||
T: PyObjectProtocol<'p>,
|
||||
{
|
||||
default fn nb_bool() -> Option<ffi::inquiry> {
|
||||
None
|
||||
}
|
||||
}
|
||||
impl<T> BoolProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PyObjectBoolProtocol<'p>,
|
||||
{
|
||||
fn nb_bool() -> Option<ffi::inquiry> {
|
||||
py_unary_func!(PyObjectBoolProtocol, T::__bool__, c_int)
|
||||
pub fn set_bool<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectBoolProtocol<'p>,
|
||||
{
|
||||
self.nb_bool = py_unary_func!(PyObjectBoolProtocol, T::__bool__, c_int);
|
||||
}
|
||||
}
|
||||
|
||||
trait RichcmpProtocolImpl {
|
||||
fn tp_richcompare() -> Option<ffi::richcmpfunc>;
|
||||
}
|
||||
impl<'p, T> RichcmpProtocolImpl for T
|
||||
fn tp_getattro<T>() -> Option<ffi::binaryfunc>
|
||||
where
|
||||
T: PyObjectProtocol<'p>,
|
||||
T: for<'p> PyObjectGetAttrProtocol<'p>,
|
||||
{
|
||||
default fn tp_richcompare() -> Option<ffi::richcmpfunc> {
|
||||
None
|
||||
unsafe extern "C" fn wrap<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
arg: *mut ffi::PyObject,
|
||||
) -> *mut ffi::PyObject
|
||||
where
|
||||
T: for<'p> PyObjectGetAttrProtocol<'p>,
|
||||
{
|
||||
crate::callback_body!(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 Ok(existing);
|
||||
}
|
||||
|
||||
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
|
||||
let arg = py.from_borrowed_ptr::<PyAny>(arg);
|
||||
call_ref!(slf, __getattr__, arg)
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
}
|
||||
impl<T> RichcmpProtocolImpl for T
|
||||
|
||||
fn tp_richcompare<T>() -> Option<ffi::richcmpfunc>
|
||||
where
|
||||
T: for<'p> PyObjectRichcmpProtocol<'p>,
|
||||
{
|
||||
fn tp_richcompare() -> Option<ffi::richcmpfunc> {
|
||||
unsafe extern "C" fn wrap<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
arg: *mut ffi::PyObject,
|
||||
op: c_int,
|
||||
) -> *mut ffi::PyObject
|
||||
where
|
||||
T: for<'p> PyObjectRichcmpProtocol<'p>,
|
||||
{
|
||||
crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
|
||||
let arg = py.from_borrowed_ptr::<PyAny>(arg);
|
||||
|
||||
let op = extract_op(op)?;
|
||||
let arg = arg.extract()?;
|
||||
|
||||
slf.try_borrow()?.__richcmp__(arg, op).into()
|
||||
})
|
||||
fn extract_op(op: c_int) -> PyResult<CompareOp> {
|
||||
match op {
|
||||
ffi::Py_LT => Ok(CompareOp::Lt),
|
||||
ffi::Py_LE => Ok(CompareOp::Le),
|
||||
ffi::Py_EQ => Ok(CompareOp::Eq),
|
||||
ffi::Py_NE => Ok(CompareOp::Ne),
|
||||
ffi::Py_GT => Ok(CompareOp::Gt),
|
||||
ffi::Py_GE => Ok(CompareOp::Ge),
|
||||
_ => Err(PyErr::new::<exceptions::ValueError, _>(
|
||||
"tp_richcompare called with invalid comparison operator",
|
||||
)),
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
}
|
||||
}
|
||||
unsafe extern "C" fn wrap<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
arg: *mut ffi::PyObject,
|
||||
op: c_int,
|
||||
) -> *mut ffi::PyObject
|
||||
where
|
||||
T: for<'p> PyObjectRichcmpProtocol<'p>,
|
||||
{
|
||||
crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
|
||||
let arg = py.from_borrowed_ptr::<PyAny>(arg);
|
||||
|
||||
fn extract_op(op: c_int) -> PyResult<CompareOp> {
|
||||
match op {
|
||||
ffi::Py_LT => Ok(CompareOp::Lt),
|
||||
ffi::Py_LE => Ok(CompareOp::Le),
|
||||
ffi::Py_EQ => Ok(CompareOp::Eq),
|
||||
ffi::Py_NE => Ok(CompareOp::Ne),
|
||||
ffi::Py_GT => Ok(CompareOp::Gt),
|
||||
ffi::Py_GE => Ok(CompareOp::Ge),
|
||||
_ => Err(PyErr::new::<exceptions::ValueError, _>(
|
||||
"tp_richcompare called with invalid comparison operator",
|
||||
)),
|
||||
let op = extract_op(op)?;
|
||||
let arg = arg.extract()?;
|
||||
|
||||
slf.try_borrow()?.__richcmp__(arg, op).into()
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,10 @@
|
|||
//! For more information check [buffer protocol](https://docs.python.org/3/c-api/buffer.html)
|
||||
//! c-api
|
||||
use crate::err::PyResult;
|
||||
use crate::{ffi, PyCell, PyClass, PyRefMut};
|
||||
use crate::{
|
||||
ffi::{self, PyBufferProcs},
|
||||
PyCell, PyClass, PyRefMut,
|
||||
};
|
||||
use std::os::raw::c_int;
|
||||
|
||||
/// Buffer protocol interface
|
||||
|
@ -37,96 +40,55 @@ pub trait PyBufferReleaseBufferProtocol<'p>: PyBufferProtocol<'p> {
|
|||
type Result: Into<PyResult<()>>;
|
||||
}
|
||||
|
||||
/// Set functions used by `#[pyproto]`.
|
||||
#[doc(hidden)]
|
||||
pub trait PyBufferProtocolImpl {
|
||||
fn tp_as_buffer() -> Option<ffi::PyBufferProcs>;
|
||||
}
|
||||
|
||||
impl<T> PyBufferProtocolImpl for T {
|
||||
default fn tp_as_buffer() -> Option<ffi::PyBufferProcs> {
|
||||
None
|
||||
impl PyBufferProcs {
|
||||
pub fn set_getbuffer<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyBufferGetBufferProtocol<'p>,
|
||||
{
|
||||
self.bf_getbuffer = bf_getbuffer::<T>();
|
||||
}
|
||||
pub fn set_releasebuffer<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyBufferReleaseBufferProtocol<'p>,
|
||||
{
|
||||
self.bf_releasebuffer = bf_releasebuffer::<T>();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, T> PyBufferProtocolImpl for T
|
||||
where
|
||||
T: PyBufferProtocol<'p>,
|
||||
{
|
||||
#[inline]
|
||||
#[allow(clippy::needless_update)] // For python 2 it's not useless
|
||||
fn tp_as_buffer() -> Option<ffi::PyBufferProcs> {
|
||||
Some(ffi::PyBufferProcs {
|
||||
bf_getbuffer: Self::cb_bf_getbuffer(),
|
||||
bf_releasebuffer: Self::cb_bf_releasebuffer(),
|
||||
..ffi::PyBufferProcs_INIT
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
trait PyBufferGetBufferProtocolImpl {
|
||||
fn cb_bf_getbuffer() -> Option<ffi::getbufferproc>;
|
||||
}
|
||||
|
||||
impl<'p, T> PyBufferGetBufferProtocolImpl for T
|
||||
where
|
||||
T: PyBufferProtocol<'p>,
|
||||
{
|
||||
default fn cb_bf_getbuffer() -> Option<ffi::getbufferproc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PyBufferGetBufferProtocolImpl for T
|
||||
fn bf_getbuffer<T>() -> Option<ffi::getbufferproc>
|
||||
where
|
||||
T: for<'p> PyBufferGetBufferProtocol<'p>,
|
||||
{
|
||||
#[inline]
|
||||
fn cb_bf_getbuffer() -> Option<ffi::getbufferproc> {
|
||||
unsafe extern "C" fn wrap<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
arg1: *mut ffi::Py_buffer,
|
||||
arg2: c_int,
|
||||
) -> c_int
|
||||
where
|
||||
T: for<'p> PyBufferGetBufferProtocol<'p>,
|
||||
{
|
||||
crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
|
||||
T::bf_getbuffer(slf.try_borrow_mut()?, arg1, arg2).into()
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
unsafe extern "C" fn wrap<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
arg1: *mut ffi::Py_buffer,
|
||||
arg2: c_int,
|
||||
) -> c_int
|
||||
where
|
||||
T: for<'p> PyBufferGetBufferProtocol<'p>,
|
||||
{
|
||||
crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
|
||||
T::bf_getbuffer(slf.try_borrow_mut()?, arg1, arg2).into()
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
}
|
||||
|
||||
trait PyBufferReleaseBufferProtocolImpl {
|
||||
fn cb_bf_releasebuffer() -> Option<ffi::releasebufferproc>;
|
||||
}
|
||||
|
||||
impl<'p, T> PyBufferReleaseBufferProtocolImpl for T
|
||||
where
|
||||
T: PyBufferProtocol<'p>,
|
||||
{
|
||||
default fn cb_bf_releasebuffer() -> Option<ffi::releasebufferproc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PyBufferReleaseBufferProtocolImpl for T
|
||||
fn bf_releasebuffer<T>() -> Option<ffi::releasebufferproc>
|
||||
where
|
||||
T: for<'p> PyBufferReleaseBufferProtocol<'p>,
|
||||
{
|
||||
#[inline]
|
||||
fn cb_bf_releasebuffer() -> Option<ffi::releasebufferproc> {
|
||||
unsafe extern "C" fn wrap<T>(slf: *mut ffi::PyObject, arg1: *mut ffi::Py_buffer)
|
||||
where
|
||||
T: for<'p> PyBufferReleaseBufferProtocol<'p>,
|
||||
{
|
||||
crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
|
||||
T::bf_releasebuffer(slf.try_borrow_mut()?, arg1).into()
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
unsafe extern "C" fn wrap<T>(slf: *mut ffi::PyObject, arg1: *mut ffi::Py_buffer)
|
||||
where
|
||||
T: for<'p> PyBufferReleaseBufferProtocol<'p>,
|
||||
{
|
||||
crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
|
||||
T::bf_releasebuffer(slf.try_borrow_mut()?, arg1).into()
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
}
|
||||
|
|
|
@ -5,23 +5,26 @@
|
|||
//! [Python information](
|
||||
//! https://docs.python.org/3/reference/datamodel.html#implementing-descriptors)
|
||||
|
||||
use crate::class::methods::PyMethodDef;
|
||||
use crate::err::PyResult;
|
||||
use crate::types::{PyAny, PyType};
|
||||
use crate::types::PyAny;
|
||||
use crate::{ffi, FromPyObject, IntoPy, PyClass, PyObject};
|
||||
use std::os::raw::c_int;
|
||||
|
||||
/// Descriptor interface
|
||||
#[allow(unused_variables)]
|
||||
pub trait PyDescrProtocol<'p>: PyClass {
|
||||
fn __get__(&'p self, instance: &'p PyAny, owner: Option<&'p PyType>) -> Self::Result
|
||||
fn __get__(
|
||||
slf: Self::Receiver,
|
||||
instance: Self::Inst,
|
||||
owner: Option<Self::Owner>,
|
||||
) -> Self::Result
|
||||
where
|
||||
Self: PyDescrGetProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __set__(&'p self, instance: &'p PyAny, value: &'p PyAny) -> Self::Result
|
||||
fn __set__(slf: Self::Receiver, instance: Self::Inst, value: Self::Value) -> Self::Result
|
||||
where
|
||||
Self: PyDescrSetProtocol<'p>,
|
||||
{
|
||||
|
@ -44,6 +47,7 @@ pub trait PyDescrProtocol<'p>: PyClass {
|
|||
}
|
||||
|
||||
pub trait PyDescrGetProtocol<'p>: PyDescrProtocol<'p> {
|
||||
type Receiver: crate::derive_utils::TryFromPyCell<'p, Self>;
|
||||
type Inst: FromPyObject<'p>;
|
||||
type Owner: FromPyObject<'p>;
|
||||
type Success: IntoPy<PyObject>;
|
||||
|
@ -51,6 +55,7 @@ pub trait PyDescrGetProtocol<'p>: PyDescrProtocol<'p> {
|
|||
}
|
||||
|
||||
pub trait PyDescrSetProtocol<'p>: PyDescrProtocol<'p> {
|
||||
type Receiver: crate::derive_utils::TryFromPyCell<'p, Self>;
|
||||
type Inst: FromPyObject<'p>;
|
||||
type Value: FromPyObject<'p>;
|
||||
type Result: Into<PyResult<()>>;
|
||||
|
@ -66,76 +71,29 @@ pub trait PyDescrSetNameProtocol<'p>: PyDescrProtocol<'p> {
|
|||
type Result: Into<PyResult<()>>;
|
||||
}
|
||||
|
||||
trait PyDescrGetProtocolImpl {
|
||||
fn tp_descr_get() -> Option<ffi::descrgetfunc>;
|
||||
/// All FFI functions for description protocols.
|
||||
#[derive(Default)]
|
||||
pub struct PyDescrMethods {
|
||||
pub tp_descr_get: Option<ffi::descrgetfunc>,
|
||||
pub tp_descr_set: Option<ffi::descrsetfunc>,
|
||||
}
|
||||
impl<'p, T> PyDescrGetProtocolImpl for T
|
||||
where
|
||||
T: PyDescrProtocol<'p>,
|
||||
{
|
||||
default fn tp_descr_get() -> Option<ffi::descrgetfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PyDescrGetProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PyDescrGetProtocol<'p>,
|
||||
{
|
||||
fn tp_descr_get() -> Option<ffi::descrgetfunc> {
|
||||
py_ternary_func!(PyDescrGetProtocol, T::__get__)
|
||||
}
|
||||
}
|
||||
|
||||
trait PyDescrSetProtocolImpl {
|
||||
fn tp_descr_set() -> Option<ffi::descrsetfunc>;
|
||||
}
|
||||
impl<'p, T> PyDescrSetProtocolImpl for T
|
||||
where
|
||||
T: PyDescrProtocol<'p>,
|
||||
{
|
||||
default fn tp_descr_set() -> Option<ffi::descrsetfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
impl<T> PyDescrSetProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PyDescrSetProtocol<'p>,
|
||||
{
|
||||
fn tp_descr_set() -> Option<ffi::descrsetfunc> {
|
||||
py_ternary_func!(PyDescrSetProtocol, T::__set__, c_int)
|
||||
}
|
||||
}
|
||||
|
||||
trait PyDescrDelProtocolImpl {
|
||||
fn __del__() -> Option<PyMethodDef> {
|
||||
None
|
||||
}
|
||||
}
|
||||
impl<'p, T> PyDescrDelProtocolImpl for T where T: PyDescrProtocol<'p> {}
|
||||
|
||||
trait PyDescrSetNameProtocolImpl {
|
||||
fn __set_name__() -> Option<PyMethodDef> {
|
||||
None
|
||||
}
|
||||
}
|
||||
impl<'p, T> PyDescrSetNameProtocolImpl for T where T: PyDescrProtocol<'p> {}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait PyDescrProtocolImpl {
|
||||
fn tp_as_descr(_type_object: &mut ffi::PyTypeObject);
|
||||
}
|
||||
|
||||
impl<T> PyDescrProtocolImpl for T {
|
||||
default fn tp_as_descr(_type_object: &mut ffi::PyTypeObject) {}
|
||||
}
|
||||
|
||||
impl<'p, T> PyDescrProtocolImpl for T
|
||||
where
|
||||
T: PyDescrProtocol<'p>,
|
||||
{
|
||||
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();
|
||||
impl PyDescrMethods {
|
||||
pub(crate) fn update_typeobj(&self, type_object: &mut ffi::PyTypeObject) {
|
||||
type_object.tp_descr_get = self.tp_descr_get;
|
||||
type_object.tp_descr_set = self.tp_descr_set;
|
||||
}
|
||||
pub fn set_descr_get<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyDescrGetProtocol<'p>,
|
||||
{
|
||||
self.tp_descr_get = py_ternarys_func!(PyDescrGetProtocol, T::__get__);
|
||||
}
|
||||
pub fn set_descr_set<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyDescrSetProtocol<'p>,
|
||||
{
|
||||
self.tp_descr_set = py_ternarys_func!(PyDescrSetProtocol, T::__set__, c_int);
|
||||
}
|
||||
}
|
||||
|
|
145
src/class/gc.rs
145
src/class/gc.rs
|
@ -18,25 +18,36 @@ pub trait PyGCProtocol<'p>: PyClass {
|
|||
pub trait PyGCTraverseProtocol<'p>: PyGCProtocol<'p> {}
|
||||
pub trait PyGCClearProtocol<'p>: PyGCProtocol<'p> {}
|
||||
|
||||
/// All FFI functions for gc protocols.
|
||||
#[derive(Default)]
|
||||
pub struct PyGCMethods {
|
||||
pub tp_traverse: Option<ffi::traverseproc>,
|
||||
pub tp_clear: Option<ffi::inquiry>,
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait PyGCProtocolImpl {
|
||||
fn update_type_object(_type_object: &mut ffi::PyTypeObject);
|
||||
}
|
||||
impl PyGCMethods {
|
||||
pub(crate) fn update_typeobj(&self, type_object: &mut ffi::PyTypeObject) {
|
||||
type_object.tp_traverse = self.tp_traverse;
|
||||
type_object.tp_clear = self.tp_clear;
|
||||
}
|
||||
|
||||
impl<'p, T> PyGCProtocolImpl for T {
|
||||
default fn update_type_object(_type_object: &mut ffi::PyTypeObject) {}
|
||||
}
|
||||
pub fn set_traverse<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyGCTraverseProtocol<'p>,
|
||||
{
|
||||
self.tp_traverse = tp_traverse::<T>();
|
||||
}
|
||||
|
||||
impl<'p, T> PyGCProtocolImpl for T
|
||||
where
|
||||
T: PyGCProtocol<'p>,
|
||||
{
|
||||
fn update_type_object(type_object: &mut ffi::PyTypeObject) {
|
||||
type_object.tp_traverse = Self::tp_traverse();
|
||||
type_object.tp_clear = Self::tp_clear();
|
||||
pub fn set_clear<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyGCClearProtocol<'p>,
|
||||
{
|
||||
self.tp_clear = tp_clear::<T>();
|
||||
}
|
||||
}
|
||||
|
||||
/// Object visitor for GC.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct PyVisit<'p> {
|
||||
visit: ffi::visitproc,
|
||||
|
@ -48,6 +59,7 @@ pub struct PyVisit<'p> {
|
|||
}
|
||||
|
||||
impl<'p> PyVisit<'p> {
|
||||
/// Visit `obj`.
|
||||
pub fn call<T>(&self, obj: &T) -> Result<(), PyTraverseError>
|
||||
where
|
||||
T: AsPyPointer,
|
||||
|
@ -61,88 +73,55 @@ impl<'p> PyVisit<'p> {
|
|||
}
|
||||
}
|
||||
|
||||
trait PyGCTraverseProtocolImpl {
|
||||
fn tp_traverse() -> Option<ffi::traverseproc>;
|
||||
}
|
||||
|
||||
impl<'p, T> PyGCTraverseProtocolImpl for T
|
||||
where
|
||||
T: PyGCProtocol<'p>,
|
||||
{
|
||||
default fn tp_traverse() -> Option<ffi::traverseproc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl<T> PyGCTraverseProtocolImpl for T
|
||||
fn tp_traverse<T>() -> Option<ffi::traverseproc>
|
||||
where
|
||||
T: for<'p> PyGCTraverseProtocol<'p>,
|
||||
{
|
||||
#[inline]
|
||||
fn tp_traverse() -> Option<ffi::traverseproc> {
|
||||
unsafe extern "C" fn tp_traverse<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
visit: ffi::visitproc,
|
||||
arg: *mut c_void,
|
||||
) -> c_int
|
||||
where
|
||||
T: for<'p> PyGCTraverseProtocol<'p>,
|
||||
{
|
||||
let pool = crate::GILPool::new();
|
||||
let py = pool.python();
|
||||
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
|
||||
unsafe extern "C" fn tp_traverse<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
visit: ffi::visitproc,
|
||||
arg: *mut c_void,
|
||||
) -> c_int
|
||||
where
|
||||
T: for<'p> PyGCTraverseProtocol<'p>,
|
||||
{
|
||||
let pool = crate::GILPool::new();
|
||||
let py = pool.python();
|
||||
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
|
||||
|
||||
let visit = PyVisit {
|
||||
visit,
|
||||
arg,
|
||||
_py: py,
|
||||
};
|
||||
let borrow = slf.try_borrow();
|
||||
if let Ok(borrow) = borrow {
|
||||
match borrow.__traverse__(visit) {
|
||||
Ok(()) => 0,
|
||||
Err(PyTraverseError(code)) => code,
|
||||
}
|
||||
} else {
|
||||
0
|
||||
let visit = PyVisit {
|
||||
visit,
|
||||
arg,
|
||||
_py: py,
|
||||
};
|
||||
let borrow = slf.try_borrow();
|
||||
if let Ok(borrow) = borrow {
|
||||
match borrow.__traverse__(visit) {
|
||||
Ok(()) => 0,
|
||||
Err(PyTraverseError(code)) => code,
|
||||
}
|
||||
} else {
|
||||
0
|
||||
}
|
||||
|
||||
Some(tp_traverse::<T>)
|
||||
}
|
||||
|
||||
Some(tp_traverse::<T>)
|
||||
}
|
||||
|
||||
trait PyGCClearProtocolImpl {
|
||||
fn tp_clear() -> Option<ffi::inquiry>;
|
||||
}
|
||||
|
||||
impl<'p, T> PyGCClearProtocolImpl for T
|
||||
where
|
||||
T: PyGCProtocol<'p>,
|
||||
{
|
||||
default fn tp_clear() -> Option<ffi::inquiry> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PyGCClearProtocolImpl for T
|
||||
fn tp_clear<T>() -> Option<ffi::inquiry>
|
||||
where
|
||||
T: for<'p> PyGCClearProtocol<'p>,
|
||||
{
|
||||
#[inline]
|
||||
fn tp_clear() -> Option<ffi::inquiry> {
|
||||
unsafe extern "C" fn tp_clear<T>(slf: *mut ffi::PyObject) -> c_int
|
||||
where
|
||||
T: for<'p> PyGCClearProtocol<'p>,
|
||||
{
|
||||
let pool = crate::GILPool::new();
|
||||
let py = pool.python();
|
||||
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
|
||||
unsafe extern "C" fn tp_clear<T>(slf: *mut ffi::PyObject) -> c_int
|
||||
where
|
||||
T: for<'p> PyGCClearProtocol<'p>,
|
||||
{
|
||||
let pool = crate::GILPool::new();
|
||||
let py = pool.python();
|
||||
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
|
||||
|
||||
slf.borrow_mut().__clear__();
|
||||
0
|
||||
}
|
||||
Some(tp_clear::<T>)
|
||||
slf.borrow_mut().__clear__();
|
||||
0
|
||||
}
|
||||
Some(tp_clear::<T>)
|
||||
}
|
||||
|
|
|
@ -40,69 +40,29 @@ pub trait PyIterNextProtocol<'p>: PyIterProtocol<'p> {
|
|||
type Result: Into<PyResult<Option<Self::Success>>>;
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct PyIterMethods {
|
||||
pub tp_iter: Option<ffi::getiterfunc>,
|
||||
pub tp_iternext: Option<ffi::iternextfunc>,
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait PyIterProtocolImpl {
|
||||
fn tp_as_iter(_typeob: &mut ffi::PyTypeObject);
|
||||
}
|
||||
|
||||
impl<T> PyIterProtocolImpl for T {
|
||||
default fn tp_as_iter(_typeob: &mut ffi::PyTypeObject) {}
|
||||
}
|
||||
|
||||
impl<'p, T> PyIterProtocolImpl for T
|
||||
where
|
||||
T: PyIterProtocol<'p>,
|
||||
{
|
||||
#[inline]
|
||||
fn tp_as_iter(typeob: &mut ffi::PyTypeObject) {
|
||||
typeob.tp_iter = Self::tp_iter();
|
||||
typeob.tp_iternext = Self::tp_iternext();
|
||||
impl PyIterMethods {
|
||||
pub(crate) fn update_typeobj(&self, type_object: &mut ffi::PyTypeObject) {
|
||||
type_object.tp_iter = self.tp_iter;
|
||||
type_object.tp_iternext = self.tp_iternext;
|
||||
}
|
||||
}
|
||||
|
||||
trait PyIterIterProtocolImpl {
|
||||
fn tp_iter() -> Option<ffi::getiterfunc>;
|
||||
}
|
||||
|
||||
impl<'p, T> PyIterIterProtocolImpl for T
|
||||
where
|
||||
T: PyIterProtocol<'p>,
|
||||
{
|
||||
default fn tp_iter() -> Option<ffi::getiterfunc> {
|
||||
None
|
||||
pub fn set_iter<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyIterIterProtocol<'p>,
|
||||
{
|
||||
self.tp_iter = py_unarys_func!(PyIterIterProtocol, T::__iter__);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PyIterIterProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PyIterIterProtocol<'p>,
|
||||
{
|
||||
#[inline]
|
||||
fn tp_iter() -> Option<ffi::getiterfunc> {
|
||||
py_unarys_func!(PyIterIterProtocol, T::__iter__)
|
||||
}
|
||||
}
|
||||
|
||||
trait PyIterNextProtocolImpl {
|
||||
fn tp_iternext() -> Option<ffi::iternextfunc>;
|
||||
}
|
||||
|
||||
impl<'p, T> PyIterNextProtocolImpl for T
|
||||
where
|
||||
T: PyIterProtocol<'p>,
|
||||
{
|
||||
default fn tp_iternext() -> Option<ffi::iternextfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PyIterNextProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PyIterNextProtocol<'p>,
|
||||
{
|
||||
#[inline]
|
||||
fn tp_iternext() -> Option<ffi::iternextfunc> {
|
||||
py_unarys_func!(PyIterNextProtocol, T::__next__, IterNextConverter)
|
||||
pub fn set_iternext<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyIterNextProtocol<'p>,
|
||||
{
|
||||
self.tp_iternext = py_unarys_func!(PyIterNextProtocol, T::__next__, IterNextConverter);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,8 +34,9 @@ macro_rules! py_unarys_func {
|
|||
{
|
||||
$crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
|
||||
let borrow = <T::Receiver>::try_from_pycell(slf)
|
||||
.map_err(|e| e.into())?;
|
||||
let borrow =
|
||||
<T::Receiver as $crate::derive_utils::TryFromPyCell<_>>::try_from_pycell(slf)
|
||||
.map_err(|e| e.into())?;
|
||||
|
||||
$class::$f(borrow).into()$(.map($conv))?
|
||||
})
|
||||
|
@ -106,7 +107,7 @@ macro_rules! py_binary_num_func {
|
|||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! py_binary_reverse_num_func {
|
||||
macro_rules! py_binary_reversed_num_func {
|
||||
($trait:ident, $class:ident :: $f:ident) => {{
|
||||
unsafe extern "C" fn wrap<T>(
|
||||
lhs: *mut ffi::PyObject,
|
||||
|
@ -177,7 +178,7 @@ macro_rules! py_ssizearg_func {
|
|||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! py_ternary_func {
|
||||
macro_rules! py_ternarys_func {
|
||||
($trait:ident, $class:ident :: $f:ident, $return_type:ty) => {{
|
||||
unsafe extern "C" fn wrap<T>(
|
||||
slf: *mut $crate::ffi::PyObject,
|
||||
|
@ -189,6 +190,9 @@ macro_rules! py_ternary_func {
|
|||
{
|
||||
$crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
|
||||
let slf =
|
||||
<T::Receiver as $crate::derive_utils::TryFromPyCell<_>>::try_from_pycell(slf)
|
||||
.map_err(|e| e.into())?;
|
||||
let arg1 = py
|
||||
.from_borrowed_ptr::<$crate::types::PyAny>(arg1)
|
||||
.extract()?;
|
||||
|
@ -196,14 +200,14 @@ macro_rules! py_ternary_func {
|
|||
.from_borrowed_ptr::<$crate::types::PyAny>(arg2)
|
||||
.extract()?;
|
||||
|
||||
slf.try_borrow()?.$f(arg1, arg2).into()
|
||||
$class::$f(slf, arg1, arg2).into()
|
||||
})
|
||||
}
|
||||
|
||||
Some(wrap::<T>)
|
||||
}};
|
||||
($trait:ident, $class:ident :: $f:ident) => {
|
||||
py_ternary_func!($trait, $class::$f, *mut $crate::ffi::PyObject);
|
||||
py_ternarys_func!($trait, $class::$f, *mut $crate::ffi::PyObject);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -240,7 +244,7 @@ macro_rules! py_ternary_num_func {
|
|||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! py_ternary_reverse_num_func {
|
||||
macro_rules! py_ternary_reversed_num_func {
|
||||
($trait:ident, $class:ident :: $f:ident) => {{
|
||||
unsafe extern "C" fn wrap<T>(
|
||||
arg1: *mut $crate::ffi::PyObject,
|
||||
|
|
|
@ -75,154 +75,41 @@ pub trait PyMappingReversedProtocol<'p>: PyMappingProtocol<'p> {
|
|||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait PyMappingProtocolImpl {
|
||||
fn tp_as_mapping() -> Option<ffi::PyMappingMethods>;
|
||||
}
|
||||
|
||||
impl<T> PyMappingProtocolImpl for T {
|
||||
default fn tp_as_mapping() -> Option<ffi::PyMappingMethods> {
|
||||
None
|
||||
impl ffi::PyMappingMethods {
|
||||
pub fn set_length<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyMappingLenProtocol<'p>,
|
||||
{
|
||||
self.mp_length = py_len_func!(PyMappingLenProtocol, T::__len__);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, T> PyMappingProtocolImpl for T
|
||||
where
|
||||
T: PyMappingProtocol<'p>,
|
||||
{
|
||||
#[inline]
|
||||
fn tp_as_mapping() -> Option<ffi::PyMappingMethods> {
|
||||
let f = if let Some(df) = Self::mp_del_subscript() {
|
||||
Some(df)
|
||||
} else {
|
||||
Self::mp_ass_subscript()
|
||||
};
|
||||
|
||||
Some(ffi::PyMappingMethods {
|
||||
mp_length: Self::mp_length(),
|
||||
mp_subscript: Self::mp_subscript(),
|
||||
mp_ass_subscript: f,
|
||||
})
|
||||
pub fn set_getitem<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyMappingGetItemProtocol<'p>,
|
||||
{
|
||||
self.mp_subscript = py_binary_func!(PyMappingGetItemProtocol, T::__getitem__);
|
||||
}
|
||||
}
|
||||
|
||||
trait PyMappingLenProtocolImpl {
|
||||
fn mp_length() -> Option<ffi::lenfunc>;
|
||||
}
|
||||
|
||||
impl<'p, T> PyMappingLenProtocolImpl for T
|
||||
where
|
||||
T: PyMappingProtocol<'p>,
|
||||
{
|
||||
default fn mp_length() -> Option<ffi::lenfunc> {
|
||||
None
|
||||
pub fn set_setitem<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyMappingSetItemProtocol<'p>,
|
||||
{
|
||||
self.mp_ass_subscript = py_func_set!(PyMappingSetItemProtocol, T, __setitem__);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PyMappingLenProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PyMappingLenProtocol<'p>,
|
||||
{
|
||||
#[inline]
|
||||
fn mp_length() -> Option<ffi::lenfunc> {
|
||||
py_len_func!(PyMappingLenProtocol, T::__len__)
|
||||
pub fn set_delitem<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyMappingDelItemProtocol<'p>,
|
||||
{
|
||||
self.mp_ass_subscript = py_func_del!(PyMappingDelItemProtocol, T, __delitem__);
|
||||
}
|
||||
}
|
||||
|
||||
trait PyMappingGetItemProtocolImpl {
|
||||
fn mp_subscript() -> Option<ffi::binaryfunc>;
|
||||
}
|
||||
|
||||
impl<'p, T> PyMappingGetItemProtocolImpl for T
|
||||
where
|
||||
T: PyMappingProtocol<'p>,
|
||||
{
|
||||
default fn mp_subscript() -> Option<ffi::binaryfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PyMappingGetItemProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PyMappingGetItemProtocol<'p>,
|
||||
{
|
||||
#[inline]
|
||||
fn mp_subscript() -> Option<ffi::binaryfunc> {
|
||||
py_binary_func!(PyMappingGetItemProtocol, T::__getitem__)
|
||||
}
|
||||
}
|
||||
|
||||
trait PyMappingSetItemProtocolImpl {
|
||||
fn mp_ass_subscript() -> Option<ffi::objobjargproc>;
|
||||
}
|
||||
|
||||
impl<'p, T> PyMappingSetItemProtocolImpl for T
|
||||
where
|
||||
T: PyMappingProtocol<'p>,
|
||||
{
|
||||
default fn mp_ass_subscript() -> Option<ffi::objobjargproc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PyMappingSetItemProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PyMappingSetItemProtocol<'p>,
|
||||
{
|
||||
#[inline]
|
||||
fn mp_ass_subscript() -> Option<ffi::objobjargproc> {
|
||||
py_func_set!(PyMappingSetItemProtocol, T, __setitem__)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `None` if PyMappingDelItemProtocol isn't implemented, otherwise dispatches to
|
||||
/// `DelSetItemDispatch`
|
||||
trait DeplItemDipatch {
|
||||
fn mp_del_subscript() -> Option<ffi::objobjargproc>;
|
||||
}
|
||||
|
||||
impl<'p, T> DeplItemDipatch for T
|
||||
where
|
||||
T: PyMappingProtocol<'p>,
|
||||
{
|
||||
default fn mp_del_subscript() -> Option<ffi::objobjargproc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `py_func_set_del` if PyMappingSetItemProtocol is implemented, otherwise `py_func_del`
|
||||
trait DelSetItemDispatch: Sized + for<'p> PyMappingDelItemProtocol<'p> {
|
||||
fn det_set_dispatch() -> Option<ffi::objobjargproc>;
|
||||
}
|
||||
|
||||
impl<T> DelSetItemDispatch for T
|
||||
where
|
||||
T: Sized + for<'p> PyMappingDelItemProtocol<'p>,
|
||||
{
|
||||
default fn det_set_dispatch() -> Option<ffi::objobjargproc> {
|
||||
py_func_del!(PyMappingDelItemProtocol, Self, __delitem__)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DelSetItemDispatch for T
|
||||
where
|
||||
T: for<'p> PyMappingSetItemProtocol<'p> + for<'p> PyMappingDelItemProtocol<'p>,
|
||||
{
|
||||
fn det_set_dispatch() -> Option<ffi::objobjargproc> {
|
||||
py_func_set_del!(
|
||||
pub fn set_setdelitem<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyMappingSetItemProtocol<'p> + for<'p> PyMappingDelItemProtocol<'p>,
|
||||
{
|
||||
self.mp_ass_subscript = py_func_set_del!(
|
||||
PyMappingSetItemProtocol,
|
||||
PyMappingDelItemProtocol,
|
||||
T,
|
||||
__setitem__,
|
||||
__delitem__
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DeplItemDipatch for T
|
||||
where
|
||||
T: Sized + for<'p> PyMappingDelItemProtocol<'p>,
|
||||
{
|
||||
fn mp_del_subscript() -> Option<ffi::objobjargproc> {
|
||||
<T as DelSetItemDispatch>::det_set_dispatch()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ pub mod iter;
|
|||
pub mod mapping;
|
||||
pub mod methods;
|
||||
pub mod number;
|
||||
pub mod proto_methods;
|
||||
pub mod pyasync;
|
||||
pub mod sequence;
|
||||
|
||||
|
|
1413
src/class/number.rs
1413
src/class/number.rs
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,154 @@
|
|||
use crate::class::{
|
||||
basic::PyObjectMethods, descr::PyDescrMethods, gc::PyGCMethods, iter::PyIterMethods,
|
||||
};
|
||||
use crate::ffi::{
|
||||
PyAsyncMethods, PyBufferProcs, PyMappingMethods, PyNumberMethods, PySequenceMethods,
|
||||
};
|
||||
use std::{
|
||||
ptr::{self, NonNull},
|
||||
sync::atomic::{AtomicPtr, Ordering},
|
||||
};
|
||||
|
||||
/// Defines all method tables we need for object protocols.
|
||||
// Note(kngwyu): default implementations are for rust-numpy. Please don't remove them.
|
||||
pub trait PyProtoMethods {
|
||||
fn async_methods() -> Option<NonNull<PyAsyncMethods>> {
|
||||
None
|
||||
}
|
||||
fn basic_methods() -> Option<NonNull<PyObjectMethods>> {
|
||||
None
|
||||
}
|
||||
fn buffer_methods() -> Option<NonNull<PyBufferProcs>> {
|
||||
None
|
||||
}
|
||||
fn descr_methods() -> Option<NonNull<PyDescrMethods>> {
|
||||
None
|
||||
}
|
||||
fn gc_methods() -> Option<NonNull<PyGCMethods>> {
|
||||
None
|
||||
}
|
||||
fn mapping_methods() -> Option<NonNull<PyMappingMethods>> {
|
||||
None
|
||||
}
|
||||
fn number_methods() -> Option<NonNull<PyNumberMethods>> {
|
||||
None
|
||||
}
|
||||
fn iter_methods() -> Option<NonNull<PyIterMethods>> {
|
||||
None
|
||||
}
|
||||
fn sequence_methods() -> Option<NonNull<PySequenceMethods>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Indicates that a type has a protocol registry. Implemented by `#[pyclass]`.
|
||||
#[doc(hidden)]
|
||||
pub trait HasProtoRegistry: Sized + 'static {
|
||||
fn registry() -> &'static PyProtoRegistry;
|
||||
}
|
||||
|
||||
impl<T: HasProtoRegistry> PyProtoMethods for T {
|
||||
fn async_methods() -> Option<NonNull<PyAsyncMethods>> {
|
||||
NonNull::new(Self::registry().async_methods.load(Ordering::Relaxed))
|
||||
}
|
||||
fn basic_methods() -> Option<NonNull<PyObjectMethods>> {
|
||||
NonNull::new(Self::registry().basic_methods.load(Ordering::Relaxed))
|
||||
}
|
||||
fn buffer_methods() -> Option<NonNull<PyBufferProcs>> {
|
||||
NonNull::new(Self::registry().buffer_methods.load(Ordering::Relaxed))
|
||||
}
|
||||
fn descr_methods() -> Option<NonNull<PyDescrMethods>> {
|
||||
NonNull::new(Self::registry().descr_methods.load(Ordering::Relaxed))
|
||||
}
|
||||
fn gc_methods() -> Option<NonNull<PyGCMethods>> {
|
||||
NonNull::new(Self::registry().gc_methods.load(Ordering::Relaxed))
|
||||
}
|
||||
fn mapping_methods() -> Option<NonNull<PyMappingMethods>> {
|
||||
NonNull::new(Self::registry().mapping_methods.load(Ordering::Relaxed))
|
||||
}
|
||||
fn number_methods() -> Option<NonNull<PyNumberMethods>> {
|
||||
NonNull::new(Self::registry().number_methods.load(Ordering::Relaxed))
|
||||
}
|
||||
fn iter_methods() -> Option<NonNull<PyIterMethods>> {
|
||||
NonNull::new(Self::registry().iter_methods.load(Ordering::Relaxed))
|
||||
}
|
||||
fn sequence_methods() -> Option<NonNull<PySequenceMethods>> {
|
||||
NonNull::new(Self::registry().sequence_methods.load(Ordering::Relaxed))
|
||||
}
|
||||
}
|
||||
|
||||
/// Stores all method protocols.
|
||||
/// Used in the proc-macro code as a static variable.
|
||||
#[doc(hidden)]
|
||||
pub struct PyProtoRegistry {
|
||||
/// Async protocols.
|
||||
async_methods: AtomicPtr<PyAsyncMethods>,
|
||||
/// Basic protocols.
|
||||
basic_methods: AtomicPtr<PyObjectMethods>,
|
||||
/// Buffer protocols.
|
||||
buffer_methods: AtomicPtr<PyBufferProcs>,
|
||||
/// Descr pProtocols.
|
||||
descr_methods: AtomicPtr<PyDescrMethods>,
|
||||
/// GC protocols.
|
||||
gc_methods: AtomicPtr<PyGCMethods>,
|
||||
/// Mapping protocols.
|
||||
mapping_methods: AtomicPtr<PyMappingMethods>,
|
||||
/// Number protocols.
|
||||
number_methods: AtomicPtr<PyNumberMethods>,
|
||||
/// Iterator protocols.
|
||||
iter_methods: AtomicPtr<PyIterMethods>,
|
||||
/// Sequence protocols.
|
||||
sequence_methods: AtomicPtr<PySequenceMethods>,
|
||||
}
|
||||
|
||||
impl PyProtoRegistry {
|
||||
pub const fn new() -> Self {
|
||||
PyProtoRegistry {
|
||||
async_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
basic_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
buffer_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
descr_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
gc_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
mapping_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
number_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
iter_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
sequence_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
}
|
||||
}
|
||||
pub fn set_async_methods(&self, methods: PyAsyncMethods) {
|
||||
self.async_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::Relaxed)
|
||||
}
|
||||
pub fn set_basic_methods(&self, methods: PyObjectMethods) {
|
||||
self.basic_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::Relaxed)
|
||||
}
|
||||
pub fn set_buffer_methods(&self, methods: PyBufferProcs) {
|
||||
self.buffer_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::Relaxed)
|
||||
}
|
||||
pub fn set_descr_methods(&self, methods: PyDescrMethods) {
|
||||
self.descr_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::Relaxed)
|
||||
}
|
||||
pub fn set_gc_methods(&self, methods: PyGCMethods) {
|
||||
self.gc_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::Relaxed)
|
||||
}
|
||||
pub fn set_mapping_methods(&self, methods: PyMappingMethods) {
|
||||
self.mapping_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::Relaxed)
|
||||
}
|
||||
pub fn set_number_methods(&self, methods: PyNumberMethods) {
|
||||
self.number_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::Relaxed)
|
||||
}
|
||||
pub fn set_iter_methods(&self, methods: PyIterMethods) {
|
||||
self.iter_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::Relaxed)
|
||||
}
|
||||
pub fn set_sequence_methods(&self, methods: PySequenceMethods) {
|
||||
self.sequence_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::Relaxed)
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@
|
|||
//! [PEP-0492](https://www.python.org/dev/peps/pep-0492/)
|
||||
//!
|
||||
|
||||
use crate::derive_utils::TryFromPyCell;
|
||||
use crate::err::PyResult;
|
||||
use crate::{ffi, PyClass, PyObject};
|
||||
|
||||
|
@ -16,21 +17,21 @@ use crate::{ffi, PyClass, PyObject};
|
|||
/// Each method in this trait corresponds to Python async/await implementation.
|
||||
#[allow(unused_variables)]
|
||||
pub trait PyAsyncProtocol<'p>: PyClass {
|
||||
fn __await__(&'p self) -> Self::Result
|
||||
fn __await__(slf: Self::Receiver) -> Self::Result
|
||||
where
|
||||
Self: PyAsyncAwaitProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __aiter__(&'p self) -> Self::Result
|
||||
fn __aiter__(slf: Self::Receiver) -> Self::Result
|
||||
where
|
||||
Self: PyAsyncAiterProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __anext__(&'p mut self) -> Self::Result
|
||||
fn __anext__(slf: Self::Receiver) -> Self::Result
|
||||
where
|
||||
Self: PyAsyncAnextProtocol<'p>,
|
||||
{
|
||||
|
@ -58,16 +59,19 @@ pub trait PyAsyncProtocol<'p>: PyClass {
|
|||
}
|
||||
|
||||
pub trait PyAsyncAwaitProtocol<'p>: PyAsyncProtocol<'p> {
|
||||
type Receiver: TryFromPyCell<'p, Self>;
|
||||
type Success: crate::IntoPy<PyObject>;
|
||||
type Result: Into<PyResult<Self::Success>>;
|
||||
}
|
||||
|
||||
pub trait PyAsyncAiterProtocol<'p>: PyAsyncProtocol<'p> {
|
||||
type Receiver: TryFromPyCell<'p, Self>;
|
||||
type Success: crate::IntoPy<PyObject>;
|
||||
type Result: Into<PyResult<Self::Success>>;
|
||||
}
|
||||
|
||||
pub trait PyAsyncAnextProtocol<'p>: PyAsyncProtocol<'p> {
|
||||
type Receiver: TryFromPyCell<'p, Self>;
|
||||
type Success: crate::IntoPy<PyObject>;
|
||||
type Result: Into<PyResult<Option<Self::Success>>>;
|
||||
}
|
||||
|
@ -86,91 +90,29 @@ pub trait PyAsyncAexitProtocol<'p>: PyAsyncProtocol<'p> {
|
|||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait PyAsyncProtocolImpl {
|
||||
fn tp_as_async() -> Option<ffi::PyAsyncMethods>;
|
||||
}
|
||||
|
||||
impl<T> PyAsyncProtocolImpl for T {
|
||||
default fn tp_as_async() -> Option<ffi::PyAsyncMethods> {
|
||||
None
|
||||
impl ffi::PyAsyncMethods {
|
||||
pub fn set_await<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyAsyncAwaitProtocol<'p>,
|
||||
{
|
||||
self.am_await = py_unarys_func!(PyAsyncAwaitProtocol, T::__await__);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, T> PyAsyncProtocolImpl for T
|
||||
where
|
||||
T: PyAsyncProtocol<'p>,
|
||||
{
|
||||
#[inline]
|
||||
fn tp_as_async() -> Option<ffi::PyAsyncMethods> {
|
||||
Some(ffi::PyAsyncMethods {
|
||||
am_await: Self::am_await(),
|
||||
am_aiter: Self::am_aiter(),
|
||||
am_anext: Self::am_anext(),
|
||||
})
|
||||
pub fn set_aiter<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyAsyncAiterProtocol<'p>,
|
||||
{
|
||||
self.am_aiter = py_unarys_func!(PyAsyncAiterProtocol, T::__aiter__);
|
||||
}
|
||||
}
|
||||
|
||||
trait PyAsyncAwaitProtocolImpl {
|
||||
fn am_await() -> Option<ffi::unaryfunc>;
|
||||
}
|
||||
|
||||
impl<'p, T> PyAsyncAwaitProtocolImpl for T
|
||||
where
|
||||
T: PyAsyncProtocol<'p>,
|
||||
{
|
||||
default fn am_await() -> Option<ffi::unaryfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PyAsyncAwaitProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PyAsyncAwaitProtocol<'p>,
|
||||
{
|
||||
#[inline]
|
||||
fn am_await() -> Option<ffi::unaryfunc> {
|
||||
py_unary_func!(PyAsyncAwaitProtocol, T::__await__)
|
||||
}
|
||||
}
|
||||
|
||||
trait PyAsyncAiterProtocolImpl {
|
||||
fn am_aiter() -> Option<ffi::unaryfunc>;
|
||||
}
|
||||
|
||||
impl<'p, T> PyAsyncAiterProtocolImpl for T
|
||||
where
|
||||
T: PyAsyncProtocol<'p>,
|
||||
{
|
||||
default fn am_aiter() -> Option<ffi::unaryfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PyAsyncAiterProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PyAsyncAiterProtocol<'p>,
|
||||
{
|
||||
#[inline]
|
||||
fn am_aiter() -> Option<ffi::unaryfunc> {
|
||||
py_unary_func!(PyAsyncAiterProtocol, T::__aiter__)
|
||||
}
|
||||
}
|
||||
|
||||
trait PyAsyncAnextProtocolImpl {
|
||||
fn am_anext() -> Option<ffi::unaryfunc>;
|
||||
}
|
||||
|
||||
impl<'p, T> PyAsyncAnextProtocolImpl for T
|
||||
where
|
||||
T: PyAsyncProtocol<'p>,
|
||||
{
|
||||
default fn am_anext() -> Option<ffi::unaryfunc> {
|
||||
None
|
||||
pub fn set_anext<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyAsyncAnextProtocol<'p>,
|
||||
{
|
||||
self.am_anext = anext::am_anext::<T>();
|
||||
}
|
||||
}
|
||||
|
||||
mod anext {
|
||||
use super::{PyAsyncAnextProtocol, PyAsyncAnextProtocolImpl};
|
||||
use super::PyAsyncAnextProtocol;
|
||||
use crate::callback::IntoPyCallbackOutput;
|
||||
use crate::err::PyResult;
|
||||
use crate::IntoPyPointer;
|
||||
|
@ -191,19 +133,11 @@ mod anext {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> PyAsyncAnextProtocolImpl for T
|
||||
#[inline]
|
||||
pub(super) fn am_anext<T>() -> Option<ffi::unaryfunc>
|
||||
where
|
||||
T: for<'p> PyAsyncAnextProtocol<'p>,
|
||||
{
|
||||
#[inline]
|
||||
fn am_anext() -> Option<ffi::unaryfunc> {
|
||||
py_unary_func!(
|
||||
PyAsyncAnextProtocol,
|
||||
T::__anext__,
|
||||
call_mut,
|
||||
*mut crate::ffi::PyObject,
|
||||
IterANextOutput
|
||||
)
|
||||
}
|
||||
py_unarys_func!(PyAsyncAnextProtocol, T::__anext__, IterANextOutput)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -127,77 +127,75 @@ pub trait PySequenceInplaceRepeatProtocol<'p>: PySequenceProtocol<'p> + IntoPy<P
|
|||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait PySequenceProtocolImpl {
|
||||
fn tp_as_sequence() -> Option<ffi::PySequenceMethods>;
|
||||
}
|
||||
|
||||
impl<T> PySequenceProtocolImpl for T {
|
||||
default fn tp_as_sequence() -> Option<ffi::PySequenceMethods> {
|
||||
None
|
||||
impl ffi::PySequenceMethods {
|
||||
pub fn set_len<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PySequenceLenProtocol<'p>,
|
||||
{
|
||||
self.sq_length = py_len_func!(PySequenceLenProtocol, T::__len__);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, T> PySequenceProtocolImpl for T
|
||||
where
|
||||
T: PySequenceProtocol<'p>,
|
||||
{
|
||||
fn tp_as_sequence() -> Option<ffi::PySequenceMethods> {
|
||||
Some(ffi::PySequenceMethods {
|
||||
sq_length: Self::sq_length(),
|
||||
sq_concat: Self::sq_concat(),
|
||||
sq_repeat: Self::sq_repeat(),
|
||||
sq_item: Self::sq_item(),
|
||||
was_sq_slice: ::std::ptr::null_mut(),
|
||||
sq_ass_item: sq_ass_item_impl::sq_ass_item::<Self>(),
|
||||
was_sq_ass_slice: ::std::ptr::null_mut(),
|
||||
sq_contains: Self::sq_contains(),
|
||||
sq_inplace_concat: Self::sq_inplace_concat(),
|
||||
sq_inplace_repeat: Self::sq_inplace_repeat(),
|
||||
})
|
||||
pub fn set_concat<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PySequenceConcatProtocol<'p>,
|
||||
{
|
||||
self.sq_concat = py_binary_func!(PySequenceConcatProtocol, T::__concat__);
|
||||
}
|
||||
}
|
||||
|
||||
trait PySequenceLenProtocolImpl {
|
||||
fn sq_length() -> Option<ffi::lenfunc>;
|
||||
}
|
||||
|
||||
impl<'p, T> PySequenceLenProtocolImpl for T
|
||||
where
|
||||
T: PySequenceProtocol<'p>,
|
||||
{
|
||||
default fn sq_length() -> Option<ffi::lenfunc> {
|
||||
None
|
||||
pub fn set_repeat<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PySequenceRepeatProtocol<'p>,
|
||||
{
|
||||
self.sq_repeat = py_ssizearg_func!(PySequenceRepeatProtocol, T::__repeat__);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PySequenceLenProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PySequenceLenProtocol<'p>,
|
||||
{
|
||||
fn sq_length() -> Option<ffi::lenfunc> {
|
||||
py_len_func!(PySequenceLenProtocol, T::__len__)
|
||||
pub fn set_getitem<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PySequenceGetItemProtocol<'p>,
|
||||
{
|
||||
self.sq_item = py_ssizearg_func!(PySequenceGetItemProtocol, T::__getitem__);
|
||||
}
|
||||
}
|
||||
|
||||
trait PySequenceGetItemProtocolImpl {
|
||||
fn sq_item() -> Option<ffi::ssizeargfunc>;
|
||||
}
|
||||
|
||||
impl<'p, T> PySequenceGetItemProtocolImpl for T
|
||||
where
|
||||
T: PySequenceProtocol<'p>,
|
||||
{
|
||||
default fn sq_item() -> Option<ffi::ssizeargfunc> {
|
||||
None
|
||||
pub fn set_setitem<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PySequenceSetItemProtocol<'p>,
|
||||
{
|
||||
self.sq_ass_item = sq_ass_item_impl::set_item::<T>();
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PySequenceGetItemProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PySequenceGetItemProtocol<'p>,
|
||||
{
|
||||
fn sq_item() -> Option<ffi::ssizeargfunc> {
|
||||
py_ssizearg_func!(PySequenceGetItemProtocol, T::__getitem__)
|
||||
pub fn set_delitem<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PySequenceDelItemProtocol<'p>,
|
||||
{
|
||||
self.sq_ass_item = sq_ass_item_impl::del_item::<T>();
|
||||
}
|
||||
pub fn set_setdelitem<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PySequenceDelItemProtocol<'p> + for<'p> PySequenceSetItemProtocol<'p>,
|
||||
{
|
||||
self.sq_ass_item = sq_ass_item_impl::set_del_item::<T>();
|
||||
}
|
||||
pub fn set_contains<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PySequenceContainsProtocol<'p>,
|
||||
{
|
||||
self.sq_contains = py_binary_func!(PySequenceContainsProtocol, T::__contains__, c_int);
|
||||
}
|
||||
pub fn set_inplace_concat<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PySequenceInplaceConcatProtocol<'p>,
|
||||
{
|
||||
self.sq_inplace_concat = py_binary_func!(
|
||||
PySequenceInplaceConcatProtocol,
|
||||
T::__inplace_concat__,
|
||||
*mut ffi::PyObject,
|
||||
call_mut
|
||||
)
|
||||
}
|
||||
pub fn set_inplace_repeat<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PySequenceInplaceRepeatProtocol<'p>,
|
||||
{
|
||||
self.sq_inplace_repeat = py_ssizearg_func!(
|
||||
PySequenceInplaceRepeatProtocol,
|
||||
T::__inplace_repeat__,
|
||||
call_mut
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -207,275 +205,90 @@ where
|
|||
mod sq_ass_item_impl {
|
||||
use super::*;
|
||||
|
||||
/// ssizeobjargproc PySequenceMethods.sq_ass_item
|
||||
///
|
||||
/// This function is used by PySequence_SetItem() and has the same signature. It is also used
|
||||
/// by PyObject_SetItem() and PyObject_DelItem(), after trying the item assignment and deletion
|
||||
/// via the mp_ass_subscript slot. This slot may be left to NULL if the object does not support
|
||||
/// item assignment and deletion.
|
||||
pub(super) fn sq_ass_item<'p, T>() -> Option<ffi::ssizeobjargproc>
|
||||
where
|
||||
T: PySequenceProtocol<'p>,
|
||||
{
|
||||
if let Some(del_set_item) = T::del_set_item() {
|
||||
Some(del_set_item)
|
||||
} else if let Some(del_item) = T::del_item() {
|
||||
Some(del_item)
|
||||
} else if let Some(set_item) = T::set_item() {
|
||||
Some(set_item)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
trait SetItem {
|
||||
fn set_item() -> Option<ffi::ssizeobjargproc>;
|
||||
}
|
||||
|
||||
impl<'p, T> SetItem for T
|
||||
where
|
||||
T: PySequenceProtocol<'p>,
|
||||
{
|
||||
default fn set_item() -> Option<ffi::ssizeobjargproc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SetItem for T
|
||||
pub(super) fn set_item<T>() -> Option<ffi::ssizeobjargproc>
|
||||
where
|
||||
T: for<'p> PySequenceSetItemProtocol<'p>,
|
||||
{
|
||||
fn set_item() -> Option<ffi::ssizeobjargproc> {
|
||||
unsafe extern "C" fn wrap<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
key: ffi::Py_ssize_t,
|
||||
value: *mut ffi::PyObject,
|
||||
) -> c_int
|
||||
where
|
||||
T: for<'p> PySequenceSetItemProtocol<'p>,
|
||||
{
|
||||
crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
|
||||
unsafe extern "C" fn wrap<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
key: ffi::Py_ssize_t,
|
||||
value: *mut ffi::PyObject,
|
||||
) -> c_int
|
||||
where
|
||||
T: for<'p> PySequenceSetItemProtocol<'p>,
|
||||
{
|
||||
crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
|
||||
|
||||
if value.is_null() {
|
||||
return Err(PyErr::new::<exceptions::NotImplementedError, _>(format!(
|
||||
"Item deletion is not supported by {:?}",
|
||||
stringify!(T)
|
||||
)));
|
||||
}
|
||||
if value.is_null() {
|
||||
return Err(PyErr::new::<exceptions::NotImplementedError, _>(format!(
|
||||
"Item deletion is not supported by {:?}",
|
||||
stringify!(T)
|
||||
)));
|
||||
}
|
||||
|
||||
let mut slf = slf.try_borrow_mut()?;
|
||||
let value = py.from_borrowed_ptr::<PyAny>(value);
|
||||
let value = value.extract()?;
|
||||
slf.__setitem__(key.into(), value).into()
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
let mut slf = slf.try_borrow_mut()?;
|
||||
let value = py.from_borrowed_ptr::<PyAny>(value);
|
||||
let value = value.extract()?;
|
||||
slf.__setitem__(key.into(), value).into()
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
}
|
||||
|
||||
trait DelItem {
|
||||
fn del_item() -> Option<ffi::ssizeobjargproc>;
|
||||
}
|
||||
|
||||
impl<'p, T> DelItem for T
|
||||
where
|
||||
T: PySequenceProtocol<'p>,
|
||||
{
|
||||
default fn del_item() -> Option<ffi::ssizeobjargproc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DelItem for T
|
||||
pub(super) fn del_item<T>() -> Option<ffi::ssizeobjargproc>
|
||||
where
|
||||
T: for<'p> PySequenceDelItemProtocol<'p>,
|
||||
{
|
||||
fn del_item() -> Option<ffi::ssizeobjargproc> {
|
||||
unsafe extern "C" fn wrap<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
key: ffi::Py_ssize_t,
|
||||
value: *mut ffi::PyObject,
|
||||
) -> c_int
|
||||
where
|
||||
T: for<'p> PySequenceDelItemProtocol<'p>,
|
||||
{
|
||||
crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
|
||||
unsafe extern "C" fn wrap<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
key: ffi::Py_ssize_t,
|
||||
value: *mut ffi::PyObject,
|
||||
) -> c_int
|
||||
where
|
||||
T: for<'p> PySequenceDelItemProtocol<'p>,
|
||||
{
|
||||
crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
|
||||
|
||||
if value.is_null() {
|
||||
slf.borrow_mut().__delitem__(key.into()).into()
|
||||
} else {
|
||||
Err(PyErr::new::<exceptions::NotImplementedError, _>(format!(
|
||||
"Item assignment not supported by {:?}",
|
||||
stringify!(T)
|
||||
)))
|
||||
}
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
if value.is_null() {
|
||||
slf.borrow_mut().__delitem__(key.into()).into()
|
||||
} else {
|
||||
Err(PyErr::new::<exceptions::NotImplementedError, _>(format!(
|
||||
"Item assignment not supported by {:?}",
|
||||
stringify!(T)
|
||||
)))
|
||||
}
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
}
|
||||
|
||||
trait DelSetItem {
|
||||
fn del_set_item() -> Option<ffi::ssizeobjargproc>;
|
||||
}
|
||||
|
||||
impl<'p, T> DelSetItem for T
|
||||
where
|
||||
T: PySequenceProtocol<'p>,
|
||||
{
|
||||
default fn del_set_item() -> Option<ffi::ssizeobjargproc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DelSetItem for T
|
||||
pub(super) fn set_del_item<T>() -> Option<ffi::ssizeobjargproc>
|
||||
where
|
||||
T: for<'p> PySequenceSetItemProtocol<'p> + for<'p> PySequenceDelItemProtocol<'p>,
|
||||
{
|
||||
fn del_set_item() -> Option<ffi::ssizeobjargproc> {
|
||||
unsafe extern "C" fn wrap<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
key: ffi::Py_ssize_t,
|
||||
value: *mut ffi::PyObject,
|
||||
) -> c_int
|
||||
where
|
||||
T: for<'p> PySequenceSetItemProtocol<'p> + for<'p> PySequenceDelItemProtocol<'p>,
|
||||
{
|
||||
crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
|
||||
unsafe extern "C" fn wrap<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
key: ffi::Py_ssize_t,
|
||||
value: *mut ffi::PyObject,
|
||||
) -> c_int
|
||||
where
|
||||
T: for<'p> PySequenceSetItemProtocol<'p> + for<'p> PySequenceDelItemProtocol<'p>,
|
||||
{
|
||||
crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
|
||||
|
||||
if value.is_null() {
|
||||
call_mut!(slf, __delitem__; key.into())
|
||||
} else {
|
||||
let value = py.from_borrowed_ptr::<PyAny>(value);
|
||||
let mut slf_ = slf.try_borrow_mut()?;
|
||||
let value = value.extract()?;
|
||||
slf_.__setitem__(key.into(), value).into()
|
||||
}
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
if value.is_null() {
|
||||
call_mut!(slf, __delitem__; key.into())
|
||||
} else {
|
||||
let value = py.from_borrowed_ptr::<PyAny>(value);
|
||||
let mut slf_ = slf.try_borrow_mut()?;
|
||||
let value = value.extract()?;
|
||||
slf_.__setitem__(key.into(), value).into()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait PySequenceContainsProtocolImpl {
|
||||
fn sq_contains() -> Option<ffi::objobjproc>;
|
||||
}
|
||||
|
||||
impl<'p, T> PySequenceContainsProtocolImpl for T
|
||||
where
|
||||
T: PySequenceProtocol<'p>,
|
||||
{
|
||||
default fn sq_contains() -> Option<ffi::objobjproc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PySequenceContainsProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PySequenceContainsProtocol<'p>,
|
||||
{
|
||||
fn sq_contains() -> Option<ffi::objobjproc> {
|
||||
py_binary_func!(PySequenceContainsProtocol, T::__contains__, c_int)
|
||||
}
|
||||
}
|
||||
|
||||
trait PySequenceConcatProtocolImpl {
|
||||
fn sq_concat() -> Option<ffi::binaryfunc>;
|
||||
}
|
||||
|
||||
impl<'p, T> PySequenceConcatProtocolImpl for T
|
||||
where
|
||||
T: PySequenceProtocol<'p>,
|
||||
{
|
||||
default fn sq_concat() -> Option<ffi::binaryfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PySequenceConcatProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PySequenceConcatProtocol<'p>,
|
||||
{
|
||||
fn sq_concat() -> Option<ffi::binaryfunc> {
|
||||
py_binary_func!(PySequenceConcatProtocol, T::__concat__)
|
||||
}
|
||||
}
|
||||
|
||||
trait PySequenceRepeatProtocolImpl {
|
||||
fn sq_repeat() -> Option<ffi::ssizeargfunc>;
|
||||
}
|
||||
|
||||
impl<'p, T> PySequenceRepeatProtocolImpl for T
|
||||
where
|
||||
T: PySequenceProtocol<'p>,
|
||||
{
|
||||
default fn sq_repeat() -> Option<ffi::ssizeargfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PySequenceRepeatProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PySequenceRepeatProtocol<'p>,
|
||||
{
|
||||
fn sq_repeat() -> Option<ffi::ssizeargfunc> {
|
||||
py_ssizearg_func!(PySequenceRepeatProtocol, T::__repeat__)
|
||||
}
|
||||
}
|
||||
|
||||
trait PySequenceInplaceConcatProtocolImpl {
|
||||
fn sq_inplace_concat() -> Option<ffi::binaryfunc>;
|
||||
}
|
||||
|
||||
impl<'p, T> PySequenceInplaceConcatProtocolImpl for T
|
||||
where
|
||||
T: PySequenceProtocol<'p>,
|
||||
{
|
||||
default fn sq_inplace_concat() -> Option<ffi::binaryfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PySequenceInplaceConcatProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PySequenceInplaceConcatProtocol<'p>,
|
||||
{
|
||||
fn sq_inplace_concat() -> Option<ffi::binaryfunc> {
|
||||
py_binary_func!(
|
||||
PySequenceInplaceConcatProtocol,
|
||||
T::__inplace_concat__,
|
||||
*mut ffi::PyObject,
|
||||
call_mut
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
trait PySequenceInplaceRepeatProtocolImpl {
|
||||
fn sq_inplace_repeat() -> Option<ffi::ssizeargfunc>;
|
||||
}
|
||||
|
||||
impl<'p, T> PySequenceInplaceRepeatProtocolImpl for T
|
||||
where
|
||||
T: PySequenceProtocol<'p>,
|
||||
{
|
||||
default fn sq_inplace_repeat() -> Option<ffi::ssizeargfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PySequenceInplaceRepeatProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PySequenceInplaceRepeatProtocol<'p>,
|
||||
{
|
||||
fn sq_inplace_repeat() -> Option<ffi::ssizeargfunc> {
|
||||
py_ssizearg_func!(
|
||||
PySequenceInplaceRepeatProtocol,
|
||||
T::__inplace_repeat__,
|
||||
call_mut
|
||||
)
|
||||
Some(wrap::<T>)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -438,14 +438,16 @@ mod typeobject {
|
|||
impl Default for PyAsyncMethods {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
unsafe { mem::zeroed() }
|
||||
PyAsyncMethods_INIT
|
||||
}
|
||||
}
|
||||
|
||||
pub const PyAsyncMethods_INIT: PyAsyncMethods = PyAsyncMethods {
|
||||
am_await: None,
|
||||
am_aiter: None,
|
||||
am_anext: None,
|
||||
};
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct PyBufferProcs {
|
||||
|
@ -456,9 +458,10 @@ mod typeobject {
|
|||
impl Default for PyBufferProcs {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
unsafe { mem::zeroed() }
|
||||
PyBufferProcs_INIT
|
||||
}
|
||||
}
|
||||
|
||||
pub const PyBufferProcs_INIT: PyBufferProcs = PyBufferProcs {
|
||||
bf_getbuffer: None,
|
||||
bf_releasebuffer: None,
|
||||
|
|
|
@ -47,7 +47,6 @@ pub unsafe trait PyNativeType: Sized {
|
|||
pub struct Py<T>(NonNull<ffi::PyObject>, PhantomData<T>);
|
||||
|
||||
unsafe impl<T> Send for Py<T> {}
|
||||
|
||||
unsafe impl<T> Sync for Py<T> {}
|
||||
|
||||
impl<T> Py<T>
|
||||
|
|
|
@ -153,6 +153,7 @@ pub use crate::types::PyAny;
|
|||
#[cfg(feature = "macros")]
|
||||
#[doc(hidden)]
|
||||
pub use {
|
||||
ctor, // Re-exported for pyproto
|
||||
indoc, // Re-exported for py_run
|
||||
inventory, // Re-exported for pymethods
|
||||
paste, // Re-exported for wrap_function
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
//! `PyClass` trait
|
||||
use crate::class::methods::{PyClassAttributeDef, PyMethodDefType, PyMethods};
|
||||
use crate::class::proto_methods::PyProtoMethods;
|
||||
use crate::conversion::{IntoPyPointer, ToPyObject};
|
||||
use crate::pyclass_slots::{PyClassDict, PyClassWeakRef};
|
||||
use crate::type_object::{type_flags, PyLayout};
|
||||
|
@ -77,6 +78,7 @@ pub trait PyClass:
|
|||
+ Sized
|
||||
+ PyClassAlloc
|
||||
+ PyMethods
|
||||
+ PyProtoMethods
|
||||
+ Send
|
||||
{
|
||||
/// Specify this class has `#[pyclass(dict)]` or not.
|
||||
|
@ -141,35 +143,43 @@ where
|
|||
}
|
||||
|
||||
// GC support
|
||||
<T as class::gc::PyGCProtocolImpl>::update_type_object(type_object);
|
||||
if let Some(gc) = T::gc_methods() {
|
||||
unsafe { gc.as_ref() }.update_typeobj(type_object);
|
||||
}
|
||||
|
||||
// descriptor protocol
|
||||
<T as class::descr::PyDescrProtocolImpl>::tp_as_descr(type_object);
|
||||
if let Some(descr) = T::descr_methods() {
|
||||
unsafe { descr.as_ref() }.update_typeobj(type_object);
|
||||
}
|
||||
|
||||
// iterator methods
|
||||
<T as class::iter::PyIterProtocolImpl>::tp_as_iter(type_object);
|
||||
if let Some(iter) = T::iter_methods() {
|
||||
unsafe { iter.as_ref() }.update_typeobj(type_object);
|
||||
}
|
||||
|
||||
// nb_bool is a part of PyObjectProtocol, but should be placed under tp_as_number
|
||||
let mut nb_bool = None;
|
||||
// basic methods
|
||||
<T as class::basic::PyObjectProtocolImpl>::tp_as_object(type_object);
|
||||
|
||||
fn to_ptr<T>(value: Option<T>) -> *mut T {
|
||||
value
|
||||
.map(|v| Box::into_raw(Box::new(v)))
|
||||
.unwrap_or_else(ptr::null_mut)
|
||||
if let Some(basic) = T::basic_methods() {
|
||||
unsafe { basic.as_ref() }.update_typeobj(type_object);
|
||||
nb_bool = unsafe { basic.as_ref() }.nb_bool;
|
||||
}
|
||||
|
||||
// number methods
|
||||
type_object.tp_as_number = to_ptr(<T as class::number::PyNumberProtocolImpl>::tp_as_number());
|
||||
type_object.tp_as_number = T::number_methods()
|
||||
.map(|mut p| {
|
||||
unsafe { p.as_mut() }.nb_bool = nb_bool;
|
||||
p.as_ptr()
|
||||
})
|
||||
.unwrap_or_else(|| nb_bool.map_or_else(ptr::null_mut, ffi::PyNumberMethods::from_nb_bool));
|
||||
// mapping methods
|
||||
type_object.tp_as_mapping =
|
||||
to_ptr(<T as class::mapping::PyMappingProtocolImpl>::tp_as_mapping());
|
||||
type_object.tp_as_mapping = T::mapping_methods().map_or_else(ptr::null_mut, |p| p.as_ptr());
|
||||
// sequence methods
|
||||
type_object.tp_as_sequence =
|
||||
to_ptr(<T as class::sequence::PySequenceProtocolImpl>::tp_as_sequence());
|
||||
type_object.tp_as_sequence = T::sequence_methods().map_or_else(ptr::null_mut, |p| p.as_ptr());
|
||||
// async methods
|
||||
type_object.tp_as_async = to_ptr(<T as class::pyasync::PyAsyncProtocolImpl>::tp_as_async());
|
||||
type_object.tp_as_async = T::async_methods().map_or_else(ptr::null_mut, |p| p.as_ptr());
|
||||
// buffer protocol
|
||||
type_object.tp_as_buffer = to_ptr(<T as class::buffer::PyBufferProtocolImpl>::tp_as_buffer());
|
||||
type_object.tp_as_buffer = T::buffer_methods().map_or_else(ptr::null_mut, |p| p.as_ptr());
|
||||
|
||||
let (new, call, mut methods, attrs) = py_class_method_defs::<T>();
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use pyo3::class::{
|
||||
PyContextProtocol, PyIterProtocol, PyMappingProtocol, PyObjectProtocol, PySequenceProtocol,
|
||||
PyAsyncProtocol, PyContextProtocol, PyDescrProtocol, PyIterProtocol, PyMappingProtocol,
|
||||
PyObjectProtocol, PySequenceProtocol,
|
||||
};
|
||||
use pyo3::exceptions::{IndexError, ValueError};
|
||||
use pyo3::prelude::*;
|
||||
|
@ -552,3 +553,131 @@ fn getattr_doesnt_override_member() {
|
|||
py_assert!(py, inst, "inst.data == 4");
|
||||
py_assert!(py, inst, "inst.a == 8");
|
||||
}
|
||||
|
||||
/// Wraps a Python future and yield it once.
|
||||
#[pyclass]
|
||||
struct OnceFuture {
|
||||
future: PyObject,
|
||||
polled: bool,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl OnceFuture {
|
||||
#[new]
|
||||
fn new(future: PyObject) -> Self {
|
||||
OnceFuture {
|
||||
future,
|
||||
polled: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pyproto]
|
||||
impl PyAsyncProtocol for OnceFuture {
|
||||
fn __await__(slf: PyRef<'p, Self>) -> PyResult<PyRef<'p, Self>> {
|
||||
Ok(slf)
|
||||
}
|
||||
}
|
||||
|
||||
#[pyproto]
|
||||
impl PyIterProtocol for OnceFuture {
|
||||
fn __iter__(slf: PyRef<'p, Self>) -> PyResult<PyRef<'p, Self>> {
|
||||
Ok(slf)
|
||||
}
|
||||
fn __next__(mut slf: PyRefMut<Self>) -> PyResult<Option<PyObject>> {
|
||||
if !slf.polled {
|
||||
slf.polled = true;
|
||||
Ok(Some(slf.future.clone()))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_await() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let once = py.get_type::<OnceFuture>();
|
||||
let source = pyo3::indoc::indoc!(
|
||||
r#"
|
||||
import asyncio
|
||||
import sys
|
||||
|
||||
async def main():
|
||||
res = await Once(await asyncio.sleep(0.1))
|
||||
return res
|
||||
# For an odd error similar to https://bugs.python.org/issue38563
|
||||
if sys.platform == "win32" and sys.version_info >= (3, 8, 0):
|
||||
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
||||
# get_event_loop can raise an error: https://github.com/PyO3/pyo3/pull/961#issuecomment-645238579
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
assert loop.run_until_complete(main()) is None
|
||||
loop.close()
|
||||
"#
|
||||
);
|
||||
let globals = PyModule::import(py, "__main__").unwrap().dict();
|
||||
globals.set_item("Once", once).unwrap();
|
||||
py.run(source, Some(globals), None)
|
||||
.map_err(|e| e.print(py))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
/// Increment the count when `__get__` is called.
|
||||
#[pyclass]
|
||||
struct DescrCounter {
|
||||
#[pyo3(get)]
|
||||
count: usize,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl DescrCounter {
|
||||
#[new]
|
||||
fn new() -> Self {
|
||||
DescrCounter { count: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
#[pyproto]
|
||||
impl PyDescrProtocol for DescrCounter {
|
||||
fn __get__(
|
||||
mut slf: PyRefMut<'p, Self>,
|
||||
_instance: &PyAny,
|
||||
_owner: Option<&'p PyType>,
|
||||
) -> PyResult<PyRefMut<'p, Self>> {
|
||||
slf.count += 1;
|
||||
Ok(slf)
|
||||
}
|
||||
fn __set__(
|
||||
_slf: PyRef<'p, Self>,
|
||||
_instance: &PyAny,
|
||||
mut new_value: PyRefMut<'p, Self>,
|
||||
) -> PyResult<()> {
|
||||
new_value.count = _slf.count;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn descr_getset() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let counter = py.get_type::<DescrCounter>();
|
||||
let source = pyo3::indoc::indoc!(
|
||||
r#"
|
||||
class Class:
|
||||
counter = Counter()
|
||||
c = Class()
|
||||
c.counter # count += 1
|
||||
assert c.counter.count == 2
|
||||
c.counter = Counter()
|
||||
assert c.counter.count == 3
|
||||
"#
|
||||
);
|
||||
let globals = PyModule::import(py, "__main__").unwrap().dict();
|
||||
globals.set_item("Counter", counter).unwrap();
|
||||
py.run(source, Some(globals), None)
|
||||
.map_err(|e| e.print(py))
|
||||
.unwrap();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue