Merge pull request #1328 from davidhewitt/pyproto-no-inventory

pyproto: remove inventory from implementation
This commit is contained in:
David Hewitt 2020-12-22 15:29:20 +00:00 committed by GitHub
commit 33b3da3337
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 1162 additions and 1954 deletions

View file

@ -772,23 +772,31 @@ impl pyo3::class::methods::HasMethodsInventory for MyClass {
}
pyo3::inventory::collect!(Pyo3MethodsInventoryForMyClass);
impl pyo3::class::proto_methods::PyProtoMethods for MyClass {
fn for_each_proto_slot<Visitor: FnMut(pyo3::ffi::PyType_Slot)>(visitor: Visitor) {
// Implementation which uses dtolnay specialization to load all slots.
use pyo3::class::proto_methods::*;
let protocols = PyClassProtocols::<MyClass>::new();
protocols.object_protocol_slots()
.iter()
.chain(protocols.number_protocol_slots())
.chain(protocols.iter_protocol_slots())
.chain(protocols.gc_protocol_slots())
.chain(protocols.descr_protocol_slots())
.chain(protocols.mapping_protocol_slots())
.chain(protocols.sequence_protocol_slots())
.chain(protocols.async_protocol_slots())
.chain(protocols.buffer_protocol_slots())
.cloned()
.for_each(visitor);
}
pub struct Pyo3ProtoInventoryForMyClass {
def: pyo3::class::proto_methods::PyProtoMethodDef,
}
impl pyo3::class::proto_methods::PyProtoInventory for Pyo3ProtoInventoryForMyClass {
fn new(def: pyo3::class::proto_methods::PyProtoMethodDef) -> Self {
Self { def }
}
fn get(&'static self) -> &'static pyo3::class::proto_methods::PyProtoMethodDef {
&self.def
fn get_buffer() -> Option<&'static pyo3::class::proto_methods::PyBufferProcs> {
use pyo3::class::proto_methods::*;
let protocols = PyClassProtocols::<MyClass>::new();
protocols.buffer_procs()
}
}
impl pyo3::class::proto_methods::HasProtoInventory for MyClass {
type ProtoMethods = Pyo3ProtoInventoryForMyClass;
}
pyo3::inventory::collect!(Pyo3ProtoInventoryForMyClass);
impl pyo3::pyclass::PyClassSend for MyClass {
type ThreadChecker = pyo3::pyclass::ThreadCheckerStub<MyClass>;

View file

@ -6,14 +6,18 @@ use std::collections::HashSet;
pub struct Proto {
/// The name of this protocol. E.g., Iter.
pub name: &'static str,
/// Extension trait that has `get_*` methods
pub extension_trait: &'static str,
/// The path to the module which contains this proto implementation.
module: &'static str,
/// Trait which stores the slots
pub slots_trait: &'static str,
/// Trait method which accesses the slots.
pub slots_trait_slots: &'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.
slot_getters: &'static [SlotGetter],
slot_defs: &'static [SlotDef],
}
impl Proto {
@ -23,32 +27,41 @@ impl Proto {
{
self.methods.iter().find(|m| query == m.name)
}
pub(crate) fn get_method<Q>(&self, query: Q) -> Option<&'static PyMethod>
where
Q: PartialEq<&'static str>,
{
self.py_methods.iter().find(|m| query == m.name)
}
// Returns the hard-coded module as a path
#[inline]
pub(crate) fn module(&self) -> syn::Path {
syn::parse_str(self.module).expect("module def not valid path")
}
// Since the order matters, we expose only the iterator instead of the slice.
pub(crate) fn slot_getters(
pub(crate) fn slot_defs(
&self,
mut implemented_protocols: HashSet<String>,
) -> impl Iterator<Item = &'static str> {
self.slot_getters.iter().filter_map(move |getter| {
// If any required method is not implemented, we skip this setter.
if getter
) -> impl Iterator<Item = &'static SlotDef> {
self.slot_defs.iter().filter(move |slot_def| {
// If any required method is not implemented, we skip this def.
let all_methods_implemented = slot_def
.proto_names
.iter()
.any(|name| !implemented_protocols.contains(*name))
{
return None;
}
// To use 'paired' setter in priority, we remove used protocols.
// For example, if set_add_radd is already used, we shouldn't use set_add and set_radd.
for name in getter.proto_names {
.all(|name| implemented_protocols.contains(*name));
if all_methods_implemented {
// To use 'paired' def in priority, we remove used protocols.
// For example, if add_radd is already used, we shouldn't use add and radd.
for name in slot_def.proto_names {
implemented_protocols.remove(*name);
}
Some(getter.get_function)
}
all_methods_implemented
})
}
}
@ -79,584 +92,517 @@ impl PyMethod {
}
}
/// Represents a setter used to register a method to the method table.
struct SlotGetter {
/// Protocols necessary for invoking this setter.
/// Represents a slot definition.
pub struct SlotDef {
/// Protocols necessary to meet this def.
/// 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 get_function: &'static str,
/// The Python slot name.
pub slot: &'static str,
/// The name of the function in pyo3 which implements the slot.
pub slot_impl: &'static str,
}
impl SlotGetter {
const fn new(names: &'static [&'static str], get_function: &'static str) -> Self {
SlotGetter {
proto_names: names,
get_function,
impl SlotDef {
const fn new(
proto_names: &'static [&'static str],
slot: &'static str,
slot_impl: &'static str,
) -> Self {
SlotDef {
proto_names,
slot,
slot_impl,
}
}
}
pub const OBJECT: Proto = Proto {
name: "Object",
extension_trait: "pyo3::class::basic::PyBasicSlots",
module: "pyo3::class::basic",
slots_trait: "PyObjectProtocolSlots",
slots_trait_slots: "object_protocol_slots",
methods: &[
MethodProto::new("__getattr__", "pyo3::class::basic::PyObjectGetAttrProtocol")
MethodProto::new("__getattr__", "PyObjectGetAttrProtocol")
.args(&["Name"])
.has_self(),
MethodProto::new("__setattr__", "pyo3::class::basic::PyObjectSetAttrProtocol")
MethodProto::new("__setattr__", "PyObjectSetAttrProtocol")
.args(&["Name", "Value"])
.has_self(),
MethodProto::new("__delattr__", "pyo3::class::basic::PyObjectDelAttrProtocol")
MethodProto::new("__delattr__", "PyObjectDelAttrProtocol")
.args(&["Name"])
.has_self(),
MethodProto::new("__str__", "pyo3::class::basic::PyObjectStrProtocol").has_self(),
MethodProto::new("__repr__", "pyo3::class::basic::PyObjectReprProtocol").has_self(),
MethodProto::new("__format__", "pyo3::class::basic::PyObjectFormatProtocol")
MethodProto::new("__str__", "PyObjectStrProtocol").has_self(),
MethodProto::new("__repr__", "PyObjectReprProtocol").has_self(),
MethodProto::new("__format__", "PyObjectFormatProtocol")
.args(&["Format"])
.has_self(),
MethodProto::new("__hash__", "pyo3::class::basic::PyObjectHashProtocol").has_self(),
MethodProto::new("__bytes__", "pyo3::class::basic::PyObjectBytesProtocol").has_self(),
MethodProto::new("__richcmp__", "pyo3::class::basic::PyObjectRichcmpProtocol")
MethodProto::new("__hash__", "PyObjectHashProtocol").has_self(),
MethodProto::new("__bytes__", "PyObjectBytesProtocol").has_self(),
MethodProto::new("__richcmp__", "PyObjectRichcmpProtocol")
.args(&["Other"])
.has_self(),
MethodProto::new("__bool__", "pyo3::class::basic::PyObjectBoolProtocol").has_self(),
MethodProto::new("__bool__", "PyObjectBoolProtocol").has_self(),
],
py_methods: &[
PyMethod::new("__format__", "pyo3::class::basic::FormatProtocolImpl"),
PyMethod::new("__bytes__", "pyo3::class::basic::BytesProtocolImpl"),
PyMethod::new("__unicode__", "pyo3::class::basic::UnicodeProtocolImpl"),
PyMethod::new("__format__", "FormatProtocolImpl"),
PyMethod::new("__bytes__", "BytesProtocolImpl"),
PyMethod::new("__unicode__", "UnicodeProtocolImpl"),
],
slot_getters: &[
SlotGetter::new(&["__str__"], "get_str"),
SlotGetter::new(&["__repr__"], "get_repr"),
SlotGetter::new(&["__hash__"], "get_hash"),
SlotGetter::new(&["__getattr__"], "get_getattr"),
SlotGetter::new(&["__richcmp__"], "get_richcmp"),
SlotGetter::new(&["__setattr__", "__delattr__"], "get_setdelattr"),
SlotGetter::new(&["__setattr__"], "get_setattr"),
SlotGetter::new(&["__delattr__"], "get_delattr"),
SlotGetter::new(&["__bool__"], "get_bool"),
slot_defs: &[
SlotDef::new(&["__str__"], "Py_tp_str", "str"),
SlotDef::new(&["__repr__"], "Py_tp_repr", "repr"),
SlotDef::new(&["__hash__"], "Py_tp_hash", "hash"),
SlotDef::new(&["__getattr__"], "Py_tp_getattro", "getattr"),
SlotDef::new(&["__richcmp__"], "Py_tp_richcompare", "richcmp"),
SlotDef::new(
&["__setattr__", "__delattr__"],
"Py_tp_setattro",
"setdelattr",
),
SlotDef::new(&["__setattr__"], "Py_tp_setattro", "setattr"),
SlotDef::new(&["__delattr__"], "Py_tp_setattro", "delattr"),
SlotDef::new(&["__bool__"], "Py_nb_bool", "bool"),
],
};
pub const ASYNC: Proto = Proto {
name: "Async",
extension_trait: "pyo3::class::pyasync::PyAsyncSlots",
module: "pyo3::class::pyasync",
slots_trait: "PyAsyncProtocolSlots",
slots_trait_slots: "async_protocol_slots",
methods: &[
MethodProto::new("__await__", "pyo3::class::pyasync::PyAsyncAwaitProtocol")
.args(&["Receiver"]),
MethodProto::new("__aiter__", "pyo3::class::pyasync::PyAsyncAiterProtocol")
.args(&["Receiver"]),
MethodProto::new("__anext__", "pyo3::class::pyasync::PyAsyncAnextProtocol")
.args(&["Receiver"]),
MethodProto::new("__aenter__", "pyo3::class::pyasync::PyAsyncAenterProtocol").has_self(),
MethodProto::new("__aexit__", "pyo3::class::pyasync::PyAsyncAexitProtocol")
MethodProto::new("__await__", "PyAsyncAwaitProtocol").args(&["Receiver"]),
MethodProto::new("__aiter__", "PyAsyncAiterProtocol").args(&["Receiver"]),
MethodProto::new("__anext__", "PyAsyncAnextProtocol").args(&["Receiver"]),
MethodProto::new("__aenter__", "PyAsyncAenterProtocol").has_self(),
MethodProto::new("__aexit__", "PyAsyncAexitProtocol")
.args(&["ExcType", "ExcValue", "Traceback"])
.has_self(),
],
py_methods: &[
PyMethod::new(
"__aenter__",
"pyo3::class::pyasync::PyAsyncAenterProtocolImpl",
),
PyMethod::new(
"__aexit__",
"pyo3::class::pyasync::PyAsyncAexitProtocolImpl",
),
PyMethod::new("__aenter__", "PyAsyncAenterProtocolImpl"),
PyMethod::new("__aexit__", "PyAsyncAexitProtocolImpl"),
],
slot_getters: &[
SlotGetter::new(&["__await__"], "get_await"),
SlotGetter::new(&["__aiter__"], "get_aiter"),
SlotGetter::new(&["__anext__"], "get_anext"),
slot_defs: &[
SlotDef::new(&["__await__"], "Py_am_await", "await_"),
SlotDef::new(&["__aiter__"], "Py_am_aiter", "aiter"),
SlotDef::new(&["__anext__"], "Py_am_anext", "anext"),
],
};
pub const BUFFER: Proto = Proto {
name: "Buffer",
extension_trait: "pyo3::class::buffer::PyBufferSlots",
module: "pyo3::class::buffer",
slots_trait: "PyBufferProtocolSlots",
slots_trait_slots: "buffer_protocol_slots",
methods: &[
MethodProto::new(
"bf_getbuffer",
"pyo3::class::buffer::PyBufferGetBufferProtocol",
)
.has_self(),
MethodProto::new(
"bf_releasebuffer",
"pyo3::class::buffer::PyBufferReleaseBufferProtocol",
)
.has_self(),
MethodProto::new("bf_getbuffer", "PyBufferGetBufferProtocol").has_self(),
MethodProto::new("bf_releasebuffer", "PyBufferReleaseBufferProtocol").has_self(),
],
py_methods: &[],
slot_getters: &[
SlotGetter::new(&["bf_getbuffer"], "get_getbuffer"),
SlotGetter::new(&["bf_releasebuffer"], "get_releasebuffer"),
slot_defs: &[
SlotDef::new(&["bf_getbuffer"], "Py_bf_getbuffer", "getbuffer"),
SlotDef::new(
&["bf_releasebuffer"],
"Py_bf_releasebuffer",
"releasebuffer",
),
],
};
pub const CONTEXT: Proto = Proto {
name: "Context",
extension_trait: "",
module: "pyo3::class::context",
slots_trait: "",
slots_trait_slots: "",
methods: &[
MethodProto::new("__enter__", "pyo3::class::context::PyContextEnterProtocol").has_self(),
MethodProto::new("__exit__", "pyo3::class::context::PyContextExitProtocol")
MethodProto::new("__enter__", "PyContextEnterProtocol").has_self(),
MethodProto::new("__exit__", "PyContextExitProtocol")
.args(&["ExcType", "ExcValue", "Traceback"])
.has_self(),
],
py_methods: &[
PyMethod::new(
"__enter__",
"pyo3::class::context::PyContextEnterProtocolImpl",
),
PyMethod::new(
"__exit__",
"pyo3::class::context::PyContextExitProtocolImpl",
),
PyMethod::new("__enter__", "PyContextEnterProtocolImpl"),
PyMethod::new("__exit__", "PyContextExitProtocolImpl"),
],
slot_getters: &[],
slot_defs: &[],
};
pub const GC: Proto = Proto {
name: "GC",
extension_trait: "pyo3::class::gc::PyGCSlots",
module: "pyo3::class::gc",
slots_trait: "PyGCProtocolSlots",
slots_trait_slots: "gc_protocol_slots",
methods: &[
MethodProto::new("__traverse__", "pyo3::class::gc::PyGCTraverseProtocol")
MethodProto::new("__traverse__", "PyGCTraverseProtocol")
.has_self()
.no_result(),
MethodProto::new("__clear__", "pyo3::class::gc::PyGCClearProtocol")
MethodProto::new("__clear__", "PyGCClearProtocol")
.has_self()
.no_result(),
],
py_methods: &[],
slot_getters: &[
SlotGetter::new(&["__traverse__"], "get_traverse"),
SlotGetter::new(&["__clear__"], "get_clear"),
slot_defs: &[
SlotDef::new(&["__traverse__"], "Py_tp_traverse", "traverse"),
SlotDef::new(&["__clear__"], "Py_tp_clear", "clear"),
],
};
pub const DESCR: Proto = Proto {
name: "Descriptor",
extension_trait: "pyo3::class::descr::PyDescrSlots",
module: "pyo3::class::descr",
slots_trait: "PyDescrProtocolSlots",
slots_trait_slots: "descr_protocol_slots",
methods: &[
MethodProto::new("__get__", "pyo3::class::descr::PyDescrGetProtocol")
.args(&["Receiver", "Inst", "Owner"]),
MethodProto::new("__set__", "pyo3::class::descr::PyDescrSetProtocol")
.args(&["Receiver", "Inst", "Value"]),
MethodProto::new("__det__", "pyo3::class::descr::PyDescrDelProtocol")
MethodProto::new("__get__", "PyDescrGetProtocol").args(&["Receiver", "Inst", "Owner"]),
MethodProto::new("__set__", "PyDescrSetProtocol").args(&["Receiver", "Inst", "Value"]),
MethodProto::new("__det__", "PyDescrDelProtocol")
.args(&["Inst"])
.has_self(),
MethodProto::new("__set_name__", "pyo3::class::descr::PyDescrSetNameProtocol")
MethodProto::new("__set_name__", "PyDescrSetNameProtocol")
.args(&["Inst"])
.has_self(),
],
py_methods: &[
PyMethod::new("__del__", "pyo3::class::context::PyDescrDelProtocolImpl"),
PyMethod::new(
"__set_name__",
"pyo3::class::context::PyDescrNameProtocolImpl",
),
PyMethod::new("__del__", "PyDescrDelProtocolImpl"),
PyMethod::new("__set_name__", "PyDescrNameProtocolImpl"),
],
slot_getters: &[
SlotGetter::new(&["__get__"], "get_descr_get"),
SlotGetter::new(&["__set__"], "get_descr_set"),
slot_defs: &[
SlotDef::new(&["__get__"], "Py_tp_descr_get", "descr_get"),
SlotDef::new(&["__set__"], "Py_tp_descr_set", "descr_set"),
],
};
pub const ITER: Proto = Proto {
name: "Iter",
extension_trait: "pyo3::class::iter::PyIterSlots",
module: "pyo3::class::iter",
slots_trait: "PyIterProtocolSlots",
slots_trait_slots: "iter_protocol_slots",
py_methods: &[],
methods: &[
MethodProto::new("__iter__", "pyo3::class::iter::PyIterIterProtocol").args(&["Receiver"]),
MethodProto::new("__next__", "pyo3::class::iter::PyIterNextProtocol").args(&["Receiver"]),
MethodProto::new("__iter__", "PyIterIterProtocol").args(&["Receiver"]),
MethodProto::new("__next__", "PyIterNextProtocol").args(&["Receiver"]),
],
slot_getters: &[
SlotGetter::new(&["__iter__"], "get_iter"),
SlotGetter::new(&["__next__"], "get_iternext"),
slot_defs: &[
SlotDef::new(&["__iter__"], "Py_tp_iter", "iter"),
SlotDef::new(&["__next__"], "Py_tp_iternext", "iternext"),
],
};
pub const MAPPING: Proto = Proto {
name: "Mapping",
extension_trait: "pyo3::class::mapping::PyMappingSlots",
module: "pyo3::class::mapping",
slots_trait: "PyMappingProtocolSlots",
slots_trait_slots: "mapping_protocol_slots",
methods: &[
MethodProto::new("__len__", "pyo3::class::mapping::PyMappingLenProtocol").has_self(),
MethodProto::new(
"__getitem__",
"pyo3::class::mapping::PyMappingGetItemProtocol",
)
MethodProto::new("__len__", "PyMappingLenProtocol").has_self(),
MethodProto::new("__getitem__", "PyMappingGetItemProtocol")
.args(&["Key"])
.has_self(),
MethodProto::new(
"__setitem__",
"pyo3::class::mapping::PyMappingSetItemProtocol",
)
MethodProto::new("__setitem__", "PyMappingSetItemProtocol")
.args(&["Key", "Value"])
.has_self(),
MethodProto::new(
"__delitem__",
"pyo3::class::mapping::PyMappingDelItemProtocol",
)
MethodProto::new("__delitem__", "PyMappingDelItemProtocol")
.args(&["Key"])
.has_self(),
MethodProto::new(
"__reversed__",
"pyo3::class::mapping::PyMappingReversedProtocol",
)
.has_self(),
MethodProto::new("__reversed__", "PyMappingReversedProtocol").has_self(),
],
py_methods: &[PyMethod::new(
"__reversed__",
"pyo3::class::mapping::PyMappingReversedProtocolImpl",
"PyMappingReversedProtocolImpl",
)],
slot_getters: &[
SlotGetter::new(&["__len__"], "get_len"),
SlotGetter::new(&["__getitem__"], "get_getitem"),
SlotGetter::new(&["__setitem__", "__delitem__"], "get_setdelitem"),
SlotGetter::new(&["__setitem__"], "get_setitem"),
SlotGetter::new(&["__delitem__"], "get_delitem"),
slot_defs: &[
SlotDef::new(&["__len__"], "Py_mp_length", "len"),
SlotDef::new(&["__getitem__"], "Py_mp_subscript", "getitem"),
SlotDef::new(
&["__setitem__", "__delitem__"],
"Py_mp_ass_subscript",
"setdelitem",
),
SlotDef::new(&["__setitem__"], "Py_mp_ass_subscript", "setitem"),
SlotDef::new(&["__delitem__"], "Py_mp_ass_subscript", "delitem"),
],
};
pub const SEQ: Proto = Proto {
name: "Sequence",
extension_trait: "pyo3::class::sequence::PySequenceSlots",
module: "pyo3::class::sequence",
slots_trait: "PySequenceProtocolSlots",
slots_trait_slots: "sequence_protocol_slots",
methods: &[
MethodProto::new("__len__", "pyo3::class::sequence::PySequenceLenProtocol").has_self(),
MethodProto::new(
"__getitem__",
"pyo3::class::sequence::PySequenceGetItemProtocol",
)
MethodProto::new("__len__", "PySequenceLenProtocol").has_self(),
MethodProto::new("__getitem__", "PySequenceGetItemProtocol")
.args(&["Index"])
.has_self(),
MethodProto::new(
"__setitem__",
"pyo3::class::sequence::PySequenceSetItemProtocol",
)
MethodProto::new("__setitem__", "PySequenceSetItemProtocol")
.args(&["Index", "Value"])
.has_self(),
MethodProto::new(
"__delitem__",
"pyo3::class::sequence::PySequenceDelItemProtocol",
)
MethodProto::new("__delitem__", "PySequenceDelItemProtocol")
.args(&["Index"])
.has_self(),
MethodProto::new(
"__contains__",
"pyo3::class::sequence::PySequenceContainsProtocol",
)
MethodProto::new("__contains__", "PySequenceContainsProtocol")
.args(&["Item"])
.has_self(),
MethodProto::new(
"__concat__",
"pyo3::class::sequence::PySequenceConcatProtocol",
)
MethodProto::new("__concat__", "PySequenceConcatProtocol")
.args(&["Other"])
.has_self(),
MethodProto::new(
"__repeat__",
"pyo3::class::sequence::PySequenceRepeatProtocol",
)
MethodProto::new("__repeat__", "PySequenceRepeatProtocol")
.args(&["Index"])
.has_self(),
MethodProto::new(
"__inplace_concat__",
"pyo3::class::sequence::PySequenceInplaceConcatProtocol",
)
MethodProto::new("__inplace_concat__", "PySequenceInplaceConcatProtocol")
.args(&["Other"])
.has_self(),
MethodProto::new(
"__inplace_repeat__",
"pyo3::class::sequence::PySequenceInplaceRepeatProtocol",
)
MethodProto::new("__inplace_repeat__", "PySequenceInplaceRepeatProtocol")
.args(&["Index"])
.has_self(),
],
py_methods: &[],
slot_getters: &[
SlotGetter::new(&["__len__"], "get_len"),
SlotGetter::new(&["__concat__"], "get_concat"),
SlotGetter::new(&["__repeat__"], "get_repeat"),
SlotGetter::new(&["__getitem__"], "get_getitem"),
SlotGetter::new(&["__setitem__", "__delitem__"], "get_setdelitem"),
SlotGetter::new(&["__setitem__"], "get_setitem"),
SlotGetter::new(&["__delitem__"], "get_delitem"),
SlotGetter::new(&["__contains__"], "get_contains"),
SlotGetter::new(&["__inplace_concat__"], "get_inplace_concat"),
SlotGetter::new(&["__inplace_repeat__"], "get_inplace_repeat"),
slot_defs: &[
SlotDef::new(&["__len__"], "Py_sq_length", "len"),
SlotDef::new(&["__concat__"], "Py_sq_concat", "concat"),
SlotDef::new(&["__repeat__"], "Py_sq_repeat", "repeat"),
SlotDef::new(&["__getitem__"], "Py_sq_item", "getitem"),
SlotDef::new(
&["__setitem__", "__delitem__"],
"Py_sq_ass_item",
"setdelitem",
),
SlotDef::new(&["__setitem__"], "Py_sq_ass_item", "setitem"),
SlotDef::new(&["__delitem__"], "Py_sq_ass_item", "delitem"),
SlotDef::new(&["__contains__"], "Py_sq_contains", "contains"),
SlotDef::new(
&["__inplace_concat__"],
"Py_sq_inplace_concat",
"inplace_concat",
),
SlotDef::new(
&["__inplace_repeat__"],
"Py_sq_inplace_repeat",
"inplace_repeat",
),
],
};
pub const NUM: Proto = Proto {
name: "Number",
extension_trait: "pyo3::class::number::PyNumberSlots",
module: "pyo3::class::number",
slots_trait: "PyNumberProtocolSlots",
slots_trait_slots: "number_protocol_slots",
methods: &[
MethodProto::new("__add__", "pyo3::class::number::PyNumberAddProtocol")
.args(&["Left", "Right"]),
MethodProto::new("__sub__", "pyo3::class::number::PyNumberSubProtocol")
.args(&["Left", "Right"]),
MethodProto::new("__mul__", "pyo3::class::number::PyNumberMulProtocol")
.args(&["Left", "Right"]),
MethodProto::new("__matmul__", "pyo3::class::number::PyNumberMatmulProtocol")
.args(&["Left", "Right"]),
MethodProto::new(
"__truediv__",
"pyo3::class::number::PyNumberTruedivProtocol",
)
.args(&["Left", "Right"]),
MethodProto::new(
"__floordiv__",
"pyo3::class::number::PyNumberFloordivProtocol",
)
.args(&["Left", "Right"]),
MethodProto::new("__mod__", "pyo3::class::number::PyNumberModProtocol")
.args(&["Left", "Right"]),
MethodProto::new("__divmod__", "pyo3::class::number::PyNumberDivmodProtocol")
.args(&["Left", "Right"]),
MethodProto::new("__pow__", "pyo3::class::number::PyNumberPowProtocol")
.args(&["Left", "Right", "Modulo"]),
MethodProto::new("__lshift__", "pyo3::class::number::PyNumberLShiftProtocol")
.args(&["Left", "Right"]),
MethodProto::new("__rshift__", "pyo3::class::number::PyNumberRShiftProtocol")
.args(&["Left", "Right"]),
MethodProto::new("__and__", "pyo3::class::number::PyNumberAndProtocol")
.args(&["Left", "Right"]),
MethodProto::new("__xor__", "pyo3::class::number::PyNumberXorProtocol")
.args(&["Left", "Right"]),
MethodProto::new("__or__", "pyo3::class::number::PyNumberOrProtocol")
.args(&["Left", "Right"]),
MethodProto::new("__radd__", "pyo3::class::number::PyNumberRAddProtocol")
MethodProto::new("__add__", "PyNumberAddProtocol").args(&["Left", "Right"]),
MethodProto::new("__sub__", "PyNumberSubProtocol").args(&["Left", "Right"]),
MethodProto::new("__mul__", "PyNumberMulProtocol").args(&["Left", "Right"]),
MethodProto::new("__matmul__", "PyNumberMatmulProtocol").args(&["Left", "Right"]),
MethodProto::new("__truediv__", "PyNumberTruedivProtocol").args(&["Left", "Right"]),
MethodProto::new("__floordiv__", "PyNumberFloordivProtocol").args(&["Left", "Right"]),
MethodProto::new("__mod__", "PyNumberModProtocol").args(&["Left", "Right"]),
MethodProto::new("__divmod__", "PyNumberDivmodProtocol").args(&["Left", "Right"]),
MethodProto::new("__pow__", "PyNumberPowProtocol").args(&["Left", "Right", "Modulo"]),
MethodProto::new("__lshift__", "PyNumberLShiftProtocol").args(&["Left", "Right"]),
MethodProto::new("__rshift__", "PyNumberRShiftProtocol").args(&["Left", "Right"]),
MethodProto::new("__and__", "PyNumberAndProtocol").args(&["Left", "Right"]),
MethodProto::new("__xor__", "PyNumberXorProtocol").args(&["Left", "Right"]),
MethodProto::new("__or__", "PyNumberOrProtocol").args(&["Left", "Right"]),
MethodProto::new("__radd__", "PyNumberRAddProtocol")
.args(&["Other"])
.has_self(),
MethodProto::new("__rsub__", "pyo3::class::number::PyNumberRSubProtocol")
MethodProto::new("__rsub__", "PyNumberRSubProtocol")
.args(&["Other"])
.has_self(),
MethodProto::new("__rmul__", "pyo3::class::number::PyNumberRMulProtocol")
MethodProto::new("__rmul__", "PyNumberRMulProtocol")
.args(&["Other"])
.has_self(),
MethodProto::new(
"__rmatmul__",
"pyo3::class::number::PyNumberRMatmulProtocol",
)
MethodProto::new("__rmatmul__", "PyNumberRMatmulProtocol")
.args(&["Other"])
.has_self(),
MethodProto::new(
"__rtruediv__",
"pyo3::class::number::PyNumberRTruedivProtocol",
)
MethodProto::new("__rtruediv__", "PyNumberRTruedivProtocol")
.args(&["Other"])
.has_self(),
MethodProto::new(
"__rfloordiv__",
"pyo3::class::number::PyNumberRFloordivProtocol",
)
MethodProto::new("__rfloordiv__", "PyNumberRFloordivProtocol")
.args(&["Other"])
.has_self(),
MethodProto::new("__rmod__", "pyo3::class::number::PyNumberRModProtocol")
MethodProto::new("__rmod__", "PyNumberRModProtocol")
.args(&["Other"])
.has_self(),
MethodProto::new(
"__rdivmod__",
"pyo3::class::number::PyNumberRDivmodProtocol",
)
MethodProto::new("__rdivmod__", "PyNumberRDivmodProtocol")
.args(&["Other"])
.has_self(),
MethodProto::new("__rpow__", "pyo3::class::number::PyNumberRPowProtocol")
MethodProto::new("__rpow__", "PyNumberRPowProtocol")
.args(&["Other", "Modulo"])
.has_self(),
MethodProto::new(
"__rlshift__",
"pyo3::class::number::PyNumberRLShiftProtocol",
)
MethodProto::new("__rlshift__", "PyNumberRLShiftProtocol")
.args(&["Other"])
.has_self(),
MethodProto::new(
"__rrshift__",
"pyo3::class::number::PyNumberRRShiftProtocol",
)
MethodProto::new("__rrshift__", "PyNumberRRShiftProtocol")
.args(&["Other"])
.has_self(),
MethodProto::new("__rand__", "pyo3::class::number::PyNumberRAndProtocol")
MethodProto::new("__rand__", "PyNumberRAndProtocol")
.args(&["Other"])
.has_self(),
MethodProto::new("__rxor__", "pyo3::class::number::PyNumberRXorProtocol")
MethodProto::new("__rxor__", "PyNumberRXorProtocol")
.args(&["Other"])
.has_self(),
MethodProto::new("__ror__", "pyo3::class::number::PyNumberROrProtocol")
MethodProto::new("__ror__", "PyNumberROrProtocol")
.args(&["Other"])
.has_self(),
MethodProto::new("__iadd__", "pyo3::class::number::PyNumberIAddProtocol")
MethodProto::new("__iadd__", "PyNumberIAddProtocol")
.args(&["Other"])
.has_self(),
MethodProto::new("__isub__", "pyo3::class::number::PyNumberISubProtocol")
MethodProto::new("__isub__", "PyNumberISubProtocol")
.args(&["Other"])
.has_self(),
MethodProto::new("__imul__", "pyo3::class::number::PyNumberIMulProtocol")
MethodProto::new("__imul__", "PyNumberIMulProtocol")
.args(&["Other"])
.has_self(),
MethodProto::new(
"__imatmul__",
"pyo3::class::number::PyNumberIMatmulProtocol",
)
MethodProto::new("__imatmul__", "PyNumberIMatmulProtocol")
.args(&["Other"])
.has_self(),
MethodProto::new(
"__itruediv__",
"pyo3::class::number::PyNumberITruedivProtocol",
)
MethodProto::new("__itruediv__", "PyNumberITruedivProtocol")
.args(&["Other"])
.has_self(),
MethodProto::new(
"__ifloordiv__",
"pyo3::class::number::PyNumberIFloordivProtocol",
)
MethodProto::new("__ifloordiv__", "PyNumberIFloordivProtocol")
.args(&["Other"])
.has_self(),
MethodProto::new("__imod__", "pyo3::class::number::PyNumberIModProtocol")
MethodProto::new("__imod__", "PyNumberIModProtocol")
.args(&["Other"])
.has_self(),
MethodProto::new("__ipow__", "pyo3::class::number::PyNumberIPowProtocol")
MethodProto::new("__ipow__", "PyNumberIPowProtocol")
.args(&["Other"])
.has_self(),
MethodProto::new(
"__ilshift__",
"pyo3::class::number::PyNumberILShiftProtocol",
)
MethodProto::new("__ilshift__", "PyNumberILShiftProtocol")
.args(&["Other"])
.has_self(),
MethodProto::new(
"__irshift__",
"pyo3::class::number::PyNumberIRShiftProtocol",
)
MethodProto::new("__irshift__", "PyNumberIRShiftProtocol")
.args(&["Other"])
.has_self(),
MethodProto::new("__iand__", "pyo3::class::number::PyNumberIAndProtocol")
MethodProto::new("__iand__", "PyNumberIAndProtocol")
.args(&["Other"])
.has_self(),
MethodProto::new("__ixor__", "pyo3::class::number::PyNumberIXorProtocol")
MethodProto::new("__ixor__", "PyNumberIXorProtocol")
.args(&["Other"])
.has_self(),
MethodProto::new("__ior__", "pyo3::class::number::PyNumberIOrProtocol")
MethodProto::new("__ior__", "PyNumberIOrProtocol")
.args(&["Other"])
.has_self(),
MethodProto::new("__neg__", "pyo3::class::number::PyNumberNegProtocol").has_self(),
MethodProto::new("__pos__", "pyo3::class::number::PyNumberPosProtocol").has_self(),
MethodProto::new("__abs__", "pyo3::class::number::PyNumberAbsProtocol").has_self(),
MethodProto::new("__invert__", "pyo3::class::number::PyNumberInvertProtocol").has_self(),
MethodProto::new(
"__complex__",
"pyo3::class::number::PyNumberComplexProtocol",
)
.has_self(),
MethodProto::new("__int__", "pyo3::class::number::PyNumberIntProtocol").has_self(),
MethodProto::new("__float__", "pyo3::class::number::PyNumberFloatProtocol").has_self(),
MethodProto::new("__index__", "pyo3::class::number::PyNumberIndexProtocol").has_self(),
MethodProto::new("__round__", "pyo3::class::number::PyNumberRoundProtocol")
MethodProto::new("__neg__", "PyNumberNegProtocol").has_self(),
MethodProto::new("__pos__", "PyNumberPosProtocol").has_self(),
MethodProto::new("__abs__", "PyNumberAbsProtocol").has_self(),
MethodProto::new("__invert__", "PyNumberInvertProtocol").has_self(),
MethodProto::new("__complex__", "PyNumberComplexProtocol").has_self(),
MethodProto::new("__int__", "PyNumberIntProtocol").has_self(),
MethodProto::new("__float__", "PyNumberFloatProtocol").has_self(),
MethodProto::new("__index__", "PyNumberIndexProtocol").has_self(),
MethodProto::new("__round__", "PyNumberRoundProtocol")
.args(&["NDigits"])
.has_self(),
],
py_methods: &[
PyMethod::coexist("__radd__", "pyo3::class::number::PyNumberRAddProtocolImpl"),
PyMethod::coexist("__rsub__", "pyo3::class::number::PyNumberRSubProtocolImpl"),
PyMethod::coexist("__rmul__", "pyo3::class::number::PyNumberRMulProtocolImpl"),
PyMethod::coexist(
"__rmatmul__",
"pyo3::class::number::PyNumberRMatmulProtocolImpl",
),
PyMethod::coexist(
"__rtruediv__",
"pyo3::class::number::PyNumberRTruedivProtocolImpl",
),
PyMethod::coexist(
"__rfloordiv__",
"pyo3::class::number::PyNumberRFloordivProtocolImpl",
),
PyMethod::coexist("__rmod__", "pyo3::class::number::PyNumberRModProtocolImpl"),
PyMethod::coexist(
"__rdivmod__",
"pyo3::class::number::PyNumberRDivmodProtocolImpl",
),
PyMethod::coexist("__rpow__", "pyo3::class::number::PyNumberRPowProtocolImpl"),
PyMethod::coexist(
"__rlshift__",
"pyo3::class::number::PyNumberRLShiftProtocolImpl",
),
PyMethod::coexist(
"__rrshift__",
"pyo3::class::number::PyNumberRRShiftProtocolImpl",
),
PyMethod::coexist("__rand__", "pyo3::class::number::PyNumberRAndProtocolImpl"),
PyMethod::coexist("__rxor__", "pyo3::class::number::PyNumberRXorProtocolImpl"),
PyMethod::coexist("__ror__", "pyo3::class::number::PyNumberROrProtocolImpl"),
PyMethod::new(
"__complex__",
"pyo3::class::number::PyNumberComplexProtocolImpl",
),
PyMethod::new(
"__round__",
"pyo3::class::number::PyNumberRoundProtocolImpl",
),
PyMethod::coexist("__radd__", "PyNumberRAddProtocolImpl"),
PyMethod::coexist("__rsub__", "PyNumberRSubProtocolImpl"),
PyMethod::coexist("__rmul__", "PyNumberRMulProtocolImpl"),
PyMethod::coexist("__rmatmul__", "PyNumberRMatmulProtocolImpl"),
PyMethod::coexist("__rtruediv__", "PyNumberRTruedivProtocolImpl"),
PyMethod::coexist("__rfloordiv__", "PyNumberRFloordivProtocolImpl"),
PyMethod::coexist("__rmod__", "PyNumberRModProtocolImpl"),
PyMethod::coexist("__rdivmod__", "PyNumberRDivmodProtocolImpl"),
PyMethod::coexist("__rpow__", "PyNumberRPowProtocolImpl"),
PyMethod::coexist("__rlshift__", "PyNumberRLShiftProtocolImpl"),
PyMethod::coexist("__rrshift__", "PyNumberRRShiftProtocolImpl"),
PyMethod::coexist("__rand__", "PyNumberRAndProtocolImpl"),
PyMethod::coexist("__rxor__", "PyNumberRXorProtocolImpl"),
PyMethod::coexist("__ror__", "PyNumberROrProtocolImpl"),
PyMethod::new("__complex__", "PyNumberComplexProtocolImpl"),
PyMethod::new("__round__", "PyNumberRoundProtocolImpl"),
],
slot_getters: &[
SlotGetter::new(&["__add__", "__radd__"], "get_add_radd"),
SlotGetter::new(&["__add__"], "get_add"),
SlotGetter::new(&["__radd__"], "get_radd"),
SlotGetter::new(&["__sub__", "__rsub__"], "get_sub_rsub"),
SlotGetter::new(&["__sub__"], "get_sub"),
SlotGetter::new(&["__rsub__"], "get_rsub"),
SlotGetter::new(&["__mul__", "__rmul__"], "get_mul_rmul"),
SlotGetter::new(&["__mul__"], "get_mul"),
SlotGetter::new(&["__rmul__"], "get_rmul"),
SlotGetter::new(&["__mod__"], "get_mod"),
SlotGetter::new(&["__divmod__", "__rdivmod__"], "get_divmod_rdivmod"),
SlotGetter::new(&["__divmod__"], "get_divmod"),
SlotGetter::new(&["__rdivmod__"], "get_rdivmod"),
SlotGetter::new(&["__pow__", "__rpow__"], "get_pow_rpow"),
SlotGetter::new(&["__pow__"], "get_pow"),
SlotGetter::new(&["__rpow__"], "get_rpow"),
SlotGetter::new(&["__neg__"], "get_neg"),
SlotGetter::new(&["__pos__"], "get_pos"),
SlotGetter::new(&["__abs__"], "get_abs"),
SlotGetter::new(&["__invert__"], "get_invert"),
SlotGetter::new(&["__lshift__", "__rlshift__"], "get_lshift_rlshift"),
SlotGetter::new(&["__lshift__"], "get_lshift"),
SlotGetter::new(&["__rlshift__"], "get_rlshift"),
SlotGetter::new(&["__rshift__", "__rrshift__"], "get_rshift_rrshift"),
SlotGetter::new(&["__rshift__"], "get_rshift"),
SlotGetter::new(&["__rrshift__"], "get_rrshift"),
SlotGetter::new(&["__and__", "__rand__"], "get_and_rand"),
SlotGetter::new(&["__and__"], "get_and"),
SlotGetter::new(&["__rand__"], "get_rand"),
SlotGetter::new(&["__xor__", "__rxor__"], "get_xor_rxor"),
SlotGetter::new(&["__xor__"], "get_xor"),
SlotGetter::new(&["__rxor__"], "get_rxor"),
SlotGetter::new(&["__or__", "__ror__"], "get_or_ror"),
SlotGetter::new(&["__or__"], "get_or"),
SlotGetter::new(&["__ror__"], "get_ror"),
SlotGetter::new(&["__int__"], "get_int"),
SlotGetter::new(&["__float__"], "get_float"),
SlotGetter::new(&["__iadd__"], "get_iadd"),
SlotGetter::new(&["__isub__"], "get_isub"),
SlotGetter::new(&["__imul__"], "get_imul"),
SlotGetter::new(&["__imod__"], "get_imod"),
SlotGetter::new(&["__ipow__"], "get_ipow"),
SlotGetter::new(&["__ilshift__"], "get_ilshift"),
SlotGetter::new(&["__irshift__"], "get_irshift"),
SlotGetter::new(&["__iand__"], "get_iand"),
SlotGetter::new(&["__ixor__"], "get_ixor"),
SlotGetter::new(&["__ior__"], "get_ior"),
SlotGetter::new(&["__floordiv__", "__rfloordiv__"], "get_floordiv_rfloordiv"),
SlotGetter::new(&["__floordiv__"], "get_floordiv"),
SlotGetter::new(&["__rfloordiv__"], "get_rfloordiv"),
SlotGetter::new(&["__truediv__", "__rtruediv__"], "get_truediv_rtruediv"),
SlotGetter::new(&["__truediv__"], "get_truediv"),
SlotGetter::new(&["__rtruediv__"], "get_rtruediv"),
SlotGetter::new(&["__ifloordiv__"], "get_ifloordiv"),
SlotGetter::new(&["__itruediv__"], "get_itruediv"),
SlotGetter::new(&["__index__"], "get_index"),
SlotGetter::new(&["__matmul__", "__rmatmul__"], "get_matmul_rmatmul"),
SlotGetter::new(&["__matmul__"], "get_matmul"),
SlotGetter::new(&["__rmatmul__"], "get_rmatmul"),
SlotGetter::new(&["__imatmul__"], "get_imatmul"),
slot_defs: &[
SlotDef::new(&["__add__", "__radd__"], "Py_nb_add", "add_radd"),
SlotDef::new(&["__add__"], "Py_nb_add", "add"),
SlotDef::new(&["__radd__"], "Py_nb_add", "radd"),
SlotDef::new(&["__sub__", "__rsub__"], "Py_nb_subtract", "sub_rsub"),
SlotDef::new(&["__sub__"], "Py_nb_subtract", "sub"),
SlotDef::new(&["__rsub__"], "Py_nb_subtract", "rsub"),
SlotDef::new(&["__mul__", "__rmul__"], "Py_nb_multiply", "mul_rmul"),
SlotDef::new(&["__mul__"], "Py_nb_multiply", "mul"),
SlotDef::new(&["__rmul__"], "Py_nb_multiply", "rmul"),
SlotDef::new(&["__mod__"], "Py_nb_remainder", "mod_"),
SlotDef::new(
&["__divmod__", "__rdivmod__"],
"Py_nb_divmod",
"divmod_rdivmod",
),
SlotDef::new(&["__divmod__"], "Py_nb_divmod", "divmod"),
SlotDef::new(&["__rdivmod__"], "Py_nb_divmod", "rdivmod"),
SlotDef::new(&["__pow__", "__rpow__"], "Py_nb_power", "pow_rpow"),
SlotDef::new(&["__pow__"], "Py_nb_power", "pow"),
SlotDef::new(&["__rpow__"], "Py_nb_power", "rpow"),
SlotDef::new(&["__neg__"], "Py_nb_negative", "neg"),
SlotDef::new(&["__pos__"], "Py_nb_positive", "pos"),
SlotDef::new(&["__abs__"], "Py_nb_absolute", "abs"),
SlotDef::new(&["__invert__"], "Py_nb_invert", "invert"),
SlotDef::new(
&["__lshift__", "__rlshift__"],
"Py_nb_lshift",
"lshift_rlshift",
),
SlotDef::new(&["__lshift__"], "Py_nb_lshift", "lshift"),
SlotDef::new(&["__rlshift__"], "Py_nb_lshift", "rlshift"),
SlotDef::new(
&["__rshift__", "__rrshift__"],
"Py_nb_rshift",
"rshift_rrshift",
),
SlotDef::new(&["__rshift__"], "Py_nb_rshift", "rshift"),
SlotDef::new(&["__rrshift__"], "Py_nb_rshift", "rrshift"),
SlotDef::new(&["__and__", "__rand__"], "Py_nb_and", "and_rand"),
SlotDef::new(&["__and__"], "Py_nb_and", "and"),
SlotDef::new(&["__rand__"], "Py_nb_and", "rand"),
SlotDef::new(&["__xor__", "__rxor__"], "Py_nb_xor", "xor_rxor"),
SlotDef::new(&["__xor__"], "Py_nb_xor", "xor"),
SlotDef::new(&["__rxor__"], "Py_nb_xor", "rxor"),
SlotDef::new(&["__or__", "__ror__"], "Py_nb_or", "or_ror"),
SlotDef::new(&["__or__"], "Py_nb_or", "or"),
SlotDef::new(&["__ror__"], "Py_nb_or", "ror"),
SlotDef::new(&["__int__"], "Py_nb_int", "int"),
SlotDef::new(&["__float__"], "Py_nb_float", "float"),
SlotDef::new(&["__iadd__"], "Py_nb_inplace_add", "iadd"),
SlotDef::new(&["__isub__"], "Py_nb_inplace_subtract", "isub"),
SlotDef::new(&["__imul__"], "Py_nb_inplace_multiply", "imul"),
SlotDef::new(&["__imod__"], "Py_nb_inplace_remainder", "imod"),
SlotDef::new(&["__ipow__"], "Py_nb_inplace_power", "ipow"),
SlotDef::new(&["__ilshift__"], "Py_nb_inplace_lshift", "ilshift"),
SlotDef::new(&["__irshift__"], "Py_nb_inplace_rshift", "irshift"),
SlotDef::new(&["__iand__"], "Py_nb_inplace_and", "iand"),
SlotDef::new(&["__ixor__"], "Py_nb_inplace_xor", "ixor"),
SlotDef::new(&["__ior__"], "Py_nb_inplace_or", "ior"),
SlotDef::new(
&["__floordiv__", "__rfloordiv__"],
"Py_nb_floor_divide",
"floordiv_rfloordiv",
),
SlotDef::new(&["__floordiv__"], "Py_nb_floor_divide", "floordiv"),
SlotDef::new(&["__rfloordiv__"], "Py_nb_floor_divide", "rfloordiv"),
SlotDef::new(
&["__truediv__", "__rtruediv__"],
"Py_nb_true_divide",
"truediv_rtruediv",
),
SlotDef::new(&["__truediv__"], "Py_nb_true_divide", "truediv"),
SlotDef::new(&["__rtruediv__"], "Py_nb_true_divide", "rtruediv"),
SlotDef::new(
&["__ifloordiv__"],
"Py_nb_inplace_floor_divide",
"ifloordiv",
),
SlotDef::new(&["__itruediv__"], "Py_nb_inplace_true_divide", "itruediv"),
SlotDef::new(&["__index__"], "Py_nb_index", "index"),
SlotDef::new(
&["__matmul__", "__rmatmul__"],
"Py_nb_matrix_multiply",
"matmul_rmatmul",
),
SlotDef::new(&["__matmul__"], "Py_nb_matrix_multiply", "matmul"),
SlotDef::new(&["__rmatmul__"], "Py_nb_matrix_multiply", "rmatmul"),
SlotDef::new(&["__imatmul__"], "Py_nb_inplace_matrix_multiply", "imatmul"),
],
};

View file

@ -43,9 +43,10 @@ impl MethodProto {
pub(crate) fn impl_method_proto(
cls: &syn::Type,
sig: &mut syn::Signature,
module: &syn::Path,
meth: &MethodProto,
) -> syn::Result<TokenStream> {
let p: syn::Path = syn::parse_str(meth.proto).unwrap();
let proto: syn::Path = syn::parse_str(meth.proto).unwrap();
let mut impl_types = Vec::new();
for (i, arg) in meth.args.iter().enumerate() {
@ -55,8 +56,8 @@ pub(crate) fn impl_method_proto(
impl_types.push(quote! {type #arg_name = #arg_ty;});
let type1 = syn::parse_quote! { arg: <#cls as #p<'p>>::#arg_name};
let type2 = syn::parse_quote! { arg: Option<<#cls as #p<'p>>::#arg_name>};
let type1 = syn::parse_quote! { arg: <#cls as #module::#proto<'p>>::#arg_name};
let type2 = syn::parse_quote! { arg: Option<<#cls as #module::#proto<'p>>::#arg_name>};
modify_arg_ty(sig, idx, &type1, &type2)?;
}
@ -74,14 +75,14 @@ pub(crate) fn impl_method_proto(
}
};
sig.output = syn::parse_quote! { -> <#cls as #p<'p>>::Result };
sig.output = syn::parse_quote! { -> <#cls as #module::#proto<'p>>::Result };
quote! { type Result = #ret_ty; }
} else {
proc_macro2::TokenStream::new()
};
Ok(quote! {
impl<'p> #p<'p> for #cls {
impl<'p> #module::#proto<'p> for #cls {
#(#impl_types)*
#res_type_def
}

View file

@ -254,34 +254,6 @@ fn impl_methods_inventory(cls: &syn::Ident) -> TokenStream {
}
}
/// Implement `HasProtoInventory` for the class for lazy protocol initialization.
fn impl_proto_inventory(cls: &syn::Ident) -> TokenStream {
// Try to build a unique type for better error messages
let name = format!("Pyo3ProtoInventoryFor{}", cls);
let inventory_cls = syn::Ident::new(&name, Span::call_site());
quote! {
#[doc(hidden)]
pub struct #inventory_cls {
def: pyo3::class::proto_methods::PyProtoMethodDef,
}
impl pyo3::class::proto_methods::PyProtoInventory for #inventory_cls {
fn new(def: pyo3::class::proto_methods::PyProtoMethodDef) -> Self {
Self { def }
}
fn get(&'static self) -> &'static pyo3::class::proto_methods::PyProtoMethodDef {
&self.def
}
}
impl pyo3::class::proto_methods::HasProtoInventory for #cls {
type ProtoMethods = #inventory_cls;
}
pyo3::inventory::collect!(#inventory_cls);
}
}
fn get_class_python_name<'a>(cls: &'a syn::Ident, attr: &'a PyClassArgs) -> &'a syn::Ident {
attr.name.as_ref().unwrap_or(cls)
}
@ -383,7 +355,6 @@ fn impl_class(
};
let impl_inventory = impl_methods_inventory(&cls);
let impl_proto_inventory = impl_proto_inventory(&cls);
let base = &attr.base;
let flags = &attr.flags;
@ -472,7 +443,32 @@ fn impl_class(
#impl_inventory
#impl_proto_inventory
impl pyo3::class::proto_methods::PyProtoMethods for #cls {
fn for_each_proto_slot<Visitor: FnMut(pyo3::ffi::PyType_Slot)>(visitor: Visitor) {
// Implementation which uses dtolnay specialization to load all slots.
use pyo3::class::proto_methods::*;
let protocols = PyClassProtocols::<#cls>::new();
protocols.object_protocol_slots()
.iter()
.chain(protocols.number_protocol_slots())
.chain(protocols.iter_protocol_slots())
.chain(protocols.gc_protocol_slots())
.chain(protocols.descr_protocol_slots())
.chain(protocols.mapping_protocol_slots())
.chain(protocols.sequence_protocol_slots())
.chain(protocols.async_protocol_slots())
.chain(protocols.buffer_protocol_slots())
.cloned()
.for_each(visitor);
}
fn get_buffer() -> Option<&'static pyo3::class::proto_methods::PyBufferProcs> {
use pyo3::class::proto_methods::*;
let protocols = PyClassProtocols::<#cls>::new();
protocols.buffer_procs()
}
}
#extra

View file

@ -62,12 +62,13 @@ fn impl_proto_impl(
let mut trait_impls = TokenStream::new();
let mut py_methods = Vec::new();
let mut method_names = HashSet::new();
let module = proto.module();
for iimpl in impls.iter_mut() {
if let syn::ImplItem::Method(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);
impl_method_proto(ty, &mut met.sig, &module, m)?.to_tokens(&mut trait_impls);
// Insert the method to the HashSet
method_names.insert(met.sig.ident.to_string());
}
@ -107,7 +108,7 @@ fn impl_proto_impl(
}
}
let normal_methods = submit_normal_methods(py_methods, ty);
let protocol_methods = submit_protocol_methods(method_names, ty, proto)?;
let protocol_methods = impl_proto_methods(method_names, ty, proto);
Ok(quote! {
#trait_impls
#normal_methods
@ -129,49 +130,69 @@ fn submit_normal_methods(py_methods: Vec<TokenStream>, ty: &syn::Type) -> TokenS
}
}
fn submit_protocol_methods(
fn impl_proto_methods(
method_names: HashSet<String>,
ty: &syn::Type,
proto: &defs::Proto,
) -> syn::Result<TokenStream> {
if proto.extension_trait == "" {
return Ok(quote! {});
) -> TokenStream {
if proto.slots_trait.is_empty() {
return TokenStream::default();
}
let ext_trait: syn::Path = syn::parse_str(proto.extension_trait)?;
let mut tokens = vec![];
let module = proto.module();
let slots_trait = syn::Ident::new(proto.slots_trait, Span::call_site());
let slots_trait_slots = syn::Ident::new(proto.slots_trait_slots, Span::call_site());
let mut maybe_buffer_methods = None;
if proto.name == "Buffer" {
// For buffer, we construct `PyProtoMethods` from PyBufferProcs
tokens.push(quote! {
let mut proto_methods = pyo3::ffi::PyBufferProcs::default();
});
for getter in proto.slot_getters(method_names) {
let get = syn::Ident::new(getter, Span::call_site());
let field = syn::Ident::new(&format!("bf_{}", &getter[4..]), Span::call_site());
tokens.push(quote! { proto_methods.#field = Some(<#ty as #ext_trait>::#get()); });
}
} else {
// For other protocols, we construct `PyProtoMethods` from Vec<ffi::PyType_Slot>
tokens.push(quote! { let mut proto_methods = vec![]; });
for getter in proto.slot_getters(method_names) {
let get = syn::Ident::new(getter, Span::call_site());
tokens.push(quote! {
let slot = <#ty as #ext_trait>::#get();
proto_methods.push(pyo3::ffi::PyType_Slot { slot: slot.0, pfunc: slot.1 as _ });
});
}
// On Python 3.9 we have to use PyBufferProcs to set buffer slots.
// For now we emit this always for buffer methods, even on 3.9+.
// Maybe in the future we can access Py_3_9 here and define it.
maybe_buffer_methods = Some(quote! {
impl pyo3::class::proto_methods::PyBufferProtocolProcs<#ty>
for pyo3::class::proto_methods::PyClassProtocols<#ty>
{
fn buffer_procs(
self
) -> Option<&'static pyo3::class::proto_methods::PyBufferProcs> {
static PROCS: pyo3::class::proto_methods::PyBufferProcs
= pyo3::class::proto_methods::PyBufferProcs {
bf_getbuffer: Some(pyo3::class::buffer::getbuffer::<#ty>),
bf_releasebuffer: Some(pyo3::class::buffer::releasebuffer::<#ty>),
};
if tokens.len() <= 1 {
return Ok(quote! {});
}
Ok(quote! {
pyo3::inventory::submit! {
#![crate = pyo3] {
type Inventory =
<#ty as pyo3::class::proto_methods::HasProtoInventory>::ProtoMethods;
<Inventory as pyo3::class::proto_methods::PyProtoInventory>::new(
{ #(#tokens)* proto_methods.into() }
)
Some(&PROCS)
}
}
});
}
let mut tokens = proto
.slot_defs(method_names)
.map(|def| {
let slot = syn::Ident::new(def.slot, Span::call_site());
let slot_impl = syn::Ident::new(def.slot_impl, Span::call_site());
quote! {{
pyo3::ffi::PyType_Slot {
slot: pyo3::ffi::#slot,
pfunc: #module::#slot_impl::<#ty> as _
}
}}
})
.peekable();
if tokens.peek().is_none() {
return TokenStream::default();
}
quote! {
#maybe_buffer_methods
impl pyo3::class::proto_methods::#slots_trait<#ty>
for pyo3::class::proto_methods::PyClassProtocols<#ty>
{
fn #slots_trait_slots(self) -> &'static [pyo3::ffi::PyType_Slot] {
&[#(#tokens),*]
}
}
}
}

View file

@ -8,9 +8,8 @@
//! Parts of the documentation are copied from the respective methods from the
//! [typeobj docs](https://docs.python.org/3/c-api/typeobj.html)
use super::proto_methods::TypedSlot;
use crate::callback::{HashCallbackOutput, IntoPyCallbackOutput};
use crate::{exceptions, ffi, FromPyObject, PyAny, PyCell, PyClass, PyObject, PyResult};
use crate::{exceptions, ffi, FromPyObject, PyAny, PyCell, PyClass, PyObject};
use std::os::raw::c_int;
/// Operators for the __richcmp__ method
@ -134,44 +133,12 @@ pub trait PyObjectRichcmpProtocol<'p>: PyObjectProtocol<'p> {
type Result: IntoPyCallbackOutput<PyObject>;
}
/// Extension trait for proc-macro backend.
py_unary_func!(str, PyObjectStrProtocol, T::__str__);
py_unary_func!(repr, PyObjectReprProtocol, T::__repr__);
py_unary_func!(hash, PyObjectHashProtocol, T::__hash__, ffi::Py_hash_t);
#[doc(hidden)]
pub trait PyBasicSlots {
fn get_str() -> TypedSlot<ffi::reprfunc>
where
Self: for<'p> PyObjectStrProtocol<'p>,
{
TypedSlot(
ffi::Py_tp_str,
py_unary_func!(PyObjectStrProtocol, Self::__str__),
)
}
fn get_repr() -> TypedSlot<ffi::reprfunc>
where
Self: for<'p> PyObjectReprProtocol<'p>,
{
TypedSlot(
ffi::Py_tp_repr,
py_unary_func!(PyObjectReprProtocol, Self::__repr__),
)
}
fn get_hash() -> TypedSlot<ffi::hashfunc>
where
Self: for<'p> PyObjectHashProtocol<'p>,
{
TypedSlot(
ffi::Py_tp_hash,
py_unary_func!(PyObjectHashProtocol, Self::__hash__, ffi::Py_hash_t),
)
}
fn get_getattr() -> TypedSlot<ffi::getattrofunc>
where
Self: for<'p> PyObjectGetAttrProtocol<'p>,
{
unsafe extern "C" fn wrap<T>(
pub unsafe extern "C" fn getattr<T>(
slf: *mut ffi::PyObject,
arg: *mut ffi::PyObject,
) -> *mut ffi::PyObject
@ -194,27 +161,9 @@ pub trait PyBasicSlots {
call_ref!(slf, __getattr__, arg).convert(py)
})
}
TypedSlot(ffi::Py_tp_getattro, wrap::<Self>)
}
fn get_richcmp() -> TypedSlot<ffi::richcmpfunc>
where
Self: for<'p> PyObjectRichcmpProtocol<'p>,
{
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(exceptions::PyValueError::new_err(
"tp_richcompare called with invalid comparison operator",
)),
}
}
unsafe extern "C" fn wrap<T>(
#[doc(hidden)]
pub unsafe extern "C" fn richcmp<T>(
slf: *mut ffi::PyObject,
arg: *mut ffi::PyObject,
op: c_int,
@ -225,59 +174,32 @@ pub trait PyBasicSlots {
crate::callback_body!(py, {
let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
let arg = extract_or_return_not_implemented!(py, arg);
let op = extract_op(op)?;
let op = match op {
ffi::Py_LT => CompareOp::Lt,
ffi::Py_LE => CompareOp::Le,
ffi::Py_EQ => CompareOp::Eq,
ffi::Py_NE => CompareOp::Ne,
ffi::Py_GT => CompareOp::Gt,
ffi::Py_GE => CompareOp::Ge,
_ => {
return Err(exceptions::PyValueError::new_err(
"tp_richcompare called with invalid comparison operator",
))
}
};
slf.try_borrow()?.__richcmp__(arg, op).convert(py)
})
}
TypedSlot(ffi::Py_tp_richcompare, wrap::<Self>)
}
fn get_setattr() -> TypedSlot<ffi::setattrofunc>
where
Self: for<'p> PyObjectSetAttrProtocol<'p>,
{
TypedSlot(
ffi::Py_tp_setattro,
py_func_set!(PyObjectSetAttrProtocol, Self::__setattr__),
)
}
fn get_delattr() -> TypedSlot<ffi::setattrofunc>
where
Self: for<'p> PyObjectDelAttrProtocol<'p>,
{
TypedSlot(
ffi::Py_tp_setattro,
py_func_del!(PyObjectDelAttrProtocol, Self::__delattr__),
)
}
fn get_setdelattr() -> TypedSlot<ffi::setattrofunc>
where
Self: for<'p> PyObjectSetAttrProtocol<'p> + for<'p> PyObjectDelAttrProtocol<'p>,
{
TypedSlot(
ffi::Py_tp_setattro,
py_func_set!(setattr, PyObjectSetAttrProtocol, T::__setattr__);
py_func_del!(delattr, PyObjectDelAttrProtocol, T::__delattr__);
py_func_set_del!(
setdelattr,
PyObjectSetAttrProtocol,
PyObjectDelAttrProtocol,
Self,
__setattr__,
__delattr__
),
)
}
fn get_bool() -> TypedSlot<ffi::inquiry>
where
Self: for<'p> PyObjectBoolProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_bool,
py_unary_func!(PyObjectBoolProtocol, Self::__bool__, c_int),
)
}
}
impl<'p, T> PyBasicSlots for T where T: PyObjectProtocol<'p> {}
);
py_unary_func!(bool, PyObjectBoolProtocol, T::__bool__, c_int);

View file

@ -11,22 +11,18 @@ use std::os::raw::c_int;
/// Buffer protocol interface
///
/// For more information check [buffer protocol](https://docs.python.org/3/c-api/buffer.html)
/// c-api
/// c-api.
#[allow(unused_variables)]
pub trait PyBufferProtocol<'p>: PyClass {
// No default implementations so that implementors of this trait provide both methods.
fn bf_getbuffer(slf: PyRefMut<Self>, view: *mut ffi::Py_buffer, flags: c_int) -> Self::Result
where
Self: PyBufferGetBufferProtocol<'p>,
{
unimplemented!()
}
Self: PyBufferGetBufferProtocol<'p>;
fn bf_releasebuffer(slf: PyRefMut<Self>, view: *mut ffi::Py_buffer) -> Self::Result
where
Self: PyBufferReleaseBufferProtocol<'p>,
{
unimplemented!()
}
Self: PyBufferReleaseBufferProtocol<'p>;
}
pub trait PyBufferGetBufferProtocol<'p>: PyBufferProtocol<'p> {
@ -37,14 +33,8 @@ pub trait PyBufferReleaseBufferProtocol<'p>: PyBufferProtocol<'p> {
type Result: IntoPyCallbackOutput<()>;
}
/// Extension trait for proc-macro backend.
#[doc(hidden)]
pub trait PyBufferSlots {
fn get_getbuffer() -> ffi::getbufferproc
where
Self: for<'p> PyBufferGetBufferProtocol<'p>,
{
unsafe extern "C" fn wrap<T>(
pub unsafe extern "C" fn getbuffer<T>(
slf: *mut ffi::PyObject,
arg1: *mut ffi::Py_buffer,
arg2: c_int,
@ -58,14 +48,8 @@ pub trait PyBufferSlots {
})
}
wrap::<Self>
}
fn get_releasebuffer() -> ffi::releasebufferproc
where
Self: for<'p> PyBufferReleaseBufferProtocol<'p>,
{
unsafe extern "C" fn wrap<T>(slf: *mut ffi::PyObject, arg1: *mut ffi::Py_buffer)
#[doc(hidden)]
pub unsafe extern "C" fn releasebuffer<T>(slf: *mut ffi::PyObject, arg1: *mut ffi::Py_buffer)
where
T: for<'p> PyBufferReleaseBufferProtocol<'p>,
{
@ -74,9 +58,3 @@ pub trait PyBufferSlots {
T::bf_releasebuffer(slf.try_borrow_mut()?, arg1).convert(py)
})
}
wrap::<Self>
}
}
impl<'p, T> PyBufferSlots for T where T: PyBufferProtocol<'p> {}

View file

@ -5,10 +5,9 @@
//! [Python information](
//! https://docs.python.org/3/reference/datamodel.html#implementing-descriptors)
use super::proto_methods::TypedSlot;
use crate::callback::IntoPyCallbackOutput;
use crate::types::PyAny;
use crate::{ffi, FromPyObject, PyClass, PyObject};
use crate::{FromPyObject, PyClass, PyObject};
use std::os::raw::c_int;
/// Descriptor interface
@ -71,28 +70,5 @@ pub trait PyDescrSetNameProtocol<'p>: PyDescrProtocol<'p> {
type Result: IntoPyCallbackOutput<()>;
}
/// Extension trait for our proc-macro backend.
#[doc(hidden)]
pub trait PyDescrSlots {
fn get_descr_get() -> TypedSlot<ffi::descrgetfunc>
where
Self: for<'p> PyDescrGetProtocol<'p>,
{
TypedSlot(
ffi::Py_tp_descr_get,
py_ternarys_func!(PyDescrGetProtocol, Self::__get__),
)
}
fn get_descr_set() -> TypedSlot<ffi::descrsetfunc>
where
Self: for<'p> PyDescrSetProtocol<'p>,
{
TypedSlot(
ffi::Py_tp_descr_set,
py_ternarys_func!(PyDescrSetProtocol, Self::__set__, c_int),
)
}
}
impl<'p, T> PyDescrSlots for T where T: PyDescrProtocol<'p> {}
py_ternarys_func!(descr_get, PyDescrGetProtocol, Self::__get__);
py_ternarys_func!(descr_set, PyDescrSetProtocol, Self::__set__, c_int);

View file

@ -3,7 +3,6 @@
//! Python GC support
//!
use super::proto_methods::TypedSlot;
use crate::{ffi, AsPyPointer, PyCell, PyClass, Python};
use std::os::raw::{c_int, c_void};
@ -19,14 +18,8 @@ pub trait PyGCProtocol<'p>: PyClass {
pub trait PyGCTraverseProtocol<'p>: PyGCProtocol<'p> {}
pub trait PyGCClearProtocol<'p>: PyGCProtocol<'p> {}
/// Extension trait for proc-macro backend.
#[doc(hidden)]
pub trait PyGCSlots {
fn get_traverse() -> TypedSlot<ffi::traverseproc>
where
Self: for<'p> PyGCTraverseProtocol<'p>,
{
unsafe extern "C" fn wrap<T>(
pub unsafe extern "C" fn traverse<T>(
slf: *mut ffi::PyObject,
visit: ffi::visitproc,
arg: *mut c_void,
@ -54,14 +47,8 @@ pub trait PyGCSlots {
}
}
TypedSlot(ffi::Py_tp_traverse, wrap::<Self>)
}
fn get_clear() -> TypedSlot<ffi::inquiry>
where
Self: for<'p> PyGCClearProtocol<'p>,
{
unsafe extern "C" fn wrap<T>(slf: *mut ffi::PyObject) -> c_int
#[doc(hidden)]
pub unsafe extern "C" fn clear<T>(slf: *mut ffi::PyObject) -> c_int
where
T: for<'p> PyGCClearProtocol<'p>,
{
@ -72,12 +59,6 @@ pub trait PyGCSlots {
0
}
TypedSlot(ffi::Py_tp_clear, wrap::<Self>)
}
}
impl<'p, T> PyGCSlots for T where T: PyGCProtocol<'p> {}
/// Object visitor for GC.
#[derive(Clone)]
pub struct PyVisit<'p> {

View file

@ -2,7 +2,6 @@
//! Python Iterator Interface.
//! Trait and support implementation for implementing iterators
use super::proto_methods::TypedSlot;
use crate::callback::IntoPyCallbackOutput;
use crate::derive_utils::TryFromPyCell;
use crate::err::PyResult;
@ -72,30 +71,8 @@ pub trait PyIterNextProtocol<'p>: PyIterProtocol<'p> {
type Result: IntoPyCallbackOutput<PyIterNextOutput>;
}
/// Extension trait for proc-macro backend.
#[doc(hidden)]
pub trait PyIterSlots {
fn get_iter() -> TypedSlot<ffi::getiterfunc>
where
Self: for<'p> PyIterIterProtocol<'p>,
{
TypedSlot(
ffi::Py_tp_iter,
py_unarys_func!(PyIterIterProtocol, Self::__iter__),
)
}
fn get_iternext() -> TypedSlot<ffi::iternextfunc>
where
Self: for<'p> PyIterNextProtocol<'p>,
{
TypedSlot(
ffi::Py_tp_iternext,
py_unarys_func!(PyIterNextProtocol, Self::__next__),
)
}
}
impl<'p, T> PyIterSlots for T where T: PyIterProtocol<'p> {}
py_unarys_func!(iter, PyIterIterProtocol, Self::__iter__);
py_unarys_func!(iternext, PyIterNextProtocol, Self::__next__);
/// Output of `__next__` which can either `yield` the next value in the iteration, or
/// `return` a value to raise `StopIteration` in Python.

View file

@ -1,8 +1,9 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
macro_rules! py_unary_func {
($trait: ident, $class:ident :: $f:ident, $call:ident, $ret_type: ty) => {{
unsafe extern "C" fn wrap<T>(slf: *mut $crate::ffi::PyObject) -> $ret_type
($name:ident, $trait:ident, $class:ident :: $f:ident, $call:ident, $ret_type: ty) => {
#[doc(hidden)]
pub unsafe extern "C" fn $name<T>(slf: *mut $crate::ffi::PyObject) -> $ret_type
where
T: for<'p> $trait<'p>,
{
@ -11,20 +12,28 @@ macro_rules! py_unary_func {
$call!(slf, $f).convert(py)
})
}
wrap::<$class>
}};
// Use call_ref! by default
($trait:ident, $class:ident :: $f:ident, $ret_type:ty) => {
py_unary_func!($trait, $class::$f, call_ref, $ret_type);
};
($trait:ident, $class:ident :: $f:ident) => {
py_unary_func!($trait, $class::$f, call_ref, *mut $crate::ffi::PyObject);
// Use call_ref! by default
($name:ident, $trait:ident, $class:ident :: $f:ident, $ret_type:ty) => {
py_unary_func!($name, $trait, $class::$f, call_ref, $ret_type);
};
($name:ident, $trait:ident, $class:ident :: $f:ident) => {
py_unary_func!(
$name,
$trait,
$class::$f,
call_ref,
*mut $crate::ffi::PyObject
);
};
}
macro_rules! py_unarys_func {
($trait:ident, $class:ident :: $f:ident) => {{
unsafe extern "C" fn wrap<T>(slf: *mut $crate::ffi::PyObject) -> *mut $crate::ffi::PyObject
($name:ident, $trait:ident, $class:ident :: $f:ident) => {
#[doc(hidden)]
pub unsafe extern "C" fn $name<T>(
slf: *mut $crate::ffi::PyObject,
) -> *mut $crate::ffi::PyObject
where
T: for<'p> $trait<'p>,
{
@ -37,20 +46,23 @@ macro_rules! py_unarys_func {
T::$f(borrow).convert(py)
})
}
wrap::<$class>
}};
};
}
macro_rules! py_len_func {
($trait:ident, $class:ident :: $f:ident) => {
py_unary_func!($trait, $class::$f, $crate::ffi::Py_ssize_t)
($name:ident, $trait:ident, $class:ident :: $f:ident) => {
py_unary_func!($name, $trait, $class::$f, $crate::ffi::Py_ssize_t);
};
}
macro_rules! py_binary_func {
// Use call_ref! by default
($trait:ident, $class:ident :: $f:ident, $return:ty, $call:ident) => {{
unsafe extern "C" fn wrap<T>(slf: *mut ffi::PyObject, arg: *mut ffi::PyObject) -> $return
($name:ident, $trait:ident, $class:ident :: $f:ident, $return:ty, $call:ident) => {
#[doc(hidden)]
pub unsafe extern "C" fn $name<T>(
slf: *mut ffi::PyObject,
arg: *mut ffi::PyObject,
) -> $return
where
T: for<'p> $trait<'p>,
{
@ -60,19 +72,19 @@ macro_rules! py_binary_func {
$call!(slf, $f, arg).convert(py)
})
}
wrap::<$class>
}};
($trait:ident, $class:ident :: $f:ident, $return:ty) => {
py_binary_func!($trait, $class::$f, $return, call_ref)
};
($trait:ident, $class:ident :: $f:ident) => {
py_binary_func!($trait, $class::$f, *mut $crate::ffi::PyObject)
($name:ident, $trait:ident, $class:ident :: $f:ident, $return:ty) => {
py_binary_func!($name, $trait, $class::$f, $return, call_ref);
};
($name:ident, $trait:ident, $class:ident :: $f:ident) => {
py_binary_func!($name, $trait, $class::$f, *mut $crate::ffi::PyObject);
};
}
macro_rules! py_binary_num_func {
($trait:ident, $class:ident :: $f:ident) => {{
unsafe extern "C" fn wrap<T>(
($name:ident, $trait:ident, $class:ident :: $f:ident) => {
#[doc(hidden)]
pub unsafe extern "C" fn $name<T>(
lhs: *mut ffi::PyObject,
rhs: *mut ffi::PyObject,
) -> *mut $crate::ffi::PyObject
@ -85,13 +97,13 @@ macro_rules! py_binary_num_func {
T::$f(lhs.extract()?, rhs).convert(py)
})
}
wrap::<$class>
}};
};
}
macro_rules! py_binary_reversed_num_func {
($trait:ident, $class:ident :: $f:ident) => {{
unsafe extern "C" fn wrap<T>(
($name:ident, $trait:ident, $class:ident :: $f:ident) => {
#[doc(hidden)]
pub unsafe extern "C" fn $name<T>(
lhs: *mut ffi::PyObject,
rhs: *mut ffi::PyObject,
) -> *mut $crate::ffi::PyObject
@ -105,13 +117,13 @@ macro_rules! py_binary_reversed_num_func {
T::$f(&*slf.try_borrow()?, arg).convert(py)
})
}
wrap::<$class>
}};
};
}
macro_rules! py_binary_fallback_num_func {
($class:ident, $lop_trait: ident :: $lop: ident, $rop_trait: ident :: $rop: ident) => {{
unsafe extern "C" fn wrap<T>(
($name:ident, $class:ident, $lop_trait: ident :: $lop: ident, $rop_trait: ident :: $rop: ident) => {
#[doc(hidden)]
pub unsafe extern "C" fn $name<T>(
lhs: *mut ffi::PyObject,
rhs: *mut ffi::PyObject,
) -> *mut $crate::ffi::PyObject
@ -133,14 +145,14 @@ macro_rules! py_binary_fallback_num_func {
}
})
}
wrap::<$class>
}};
};
}
// NOTE(kngwyu): This macro is used only for inplace operations, so I used call_mut here.
macro_rules! py_binary_self_func {
($trait:ident, $class:ident :: $f:ident) => {{
unsafe extern "C" fn wrap<T>(
($name:ident, $trait:ident, $class:ident :: $f:ident) => {
#[doc(hidden)]
pub unsafe extern "C" fn $name<T>(
slf: *mut ffi::PyObject,
arg: *mut ffi::PyObject,
) -> *mut $crate::ffi::PyObject
@ -155,17 +167,17 @@ macro_rules! py_binary_self_func {
Ok::<_, $crate::err::PyErr>(slf)
})
}
wrap::<$class>
}};
};
}
macro_rules! py_ssizearg_func {
// Use call_ref! by default
($trait:ident, $class:ident :: $f:ident) => {
py_ssizearg_func!($trait, $class::$f, call_ref)
($name:ident, $trait:ident, $class:ident :: $f:ident) => {
py_ssizearg_func!($name, $trait, $class::$f, call_ref);
};
($trait:ident, $class:ident :: $f:ident, $call:ident) => {{
unsafe extern "C" fn wrap<T>(
($name:ident, $trait:ident, $class:ident :: $f:ident, $call:ident) => {
#[doc(hidden)]
pub unsafe extern "C" fn $name<T>(
slf: *mut ffi::PyObject,
arg: $crate::ffi::Py_ssize_t,
) -> *mut $crate::ffi::PyObject
@ -177,13 +189,13 @@ macro_rules! py_ssizearg_func {
$call!(slf, $f; arg.into()).convert(py)
})
}
wrap::<$class>
}};
};
}
macro_rules! py_ternarys_func {
($trait:ident, $class:ident :: $f:ident, $return_type:ty) => {{
unsafe extern "C" fn wrap<T>(
($name:ident, $trait:ident, $class:ident :: $f:ident, $return_type:ty) => {
#[doc(hidden)]
pub unsafe extern "C" fn $name<T>(
slf: *mut $crate::ffi::PyObject,
arg1: *mut $crate::ffi::PyObject,
arg2: *mut $crate::ffi::PyObject,
@ -206,17 +218,16 @@ macro_rules! py_ternarys_func {
T::$f(slf, arg1, arg2).convert(py)
})
}
wrap::<$class>
}};
($trait:ident, $class:ident :: $f:ident) => {
py_ternarys_func!($trait, $class::$f, *mut $crate::ffi::PyObject);
};
($name:ident, $trait:ident, $class:ident :: $f:ident) => {
py_ternarys_func!($name, $trait, $class::$f, *mut $crate::ffi::PyObject);
};
}
macro_rules! py_func_set {
($trait_name:ident, $class:ident :: $fn_set:ident) => {{
unsafe extern "C" fn wrap<T>(
($name:ident, $trait_name:ident, $class:ident :: $fn_set:ident) => {
#[doc(hidden)]
pub unsafe extern "C" fn $name<T>(
slf: *mut $crate::ffi::PyObject,
name: *mut $crate::ffi::PyObject,
value: *mut $crate::ffi::PyObject,
@ -239,14 +250,13 @@ macro_rules! py_func_set {
}
})
}
wrap::<$class>
}};
};
}
macro_rules! py_func_del {
($trait_name:ident, $class:ident :: $fn_del:ident) => {{
unsafe extern "C" fn wrap<T>(
($name:ident, $trait_name:ident, $class:ident :: $fn_del:ident) => {
#[doc(hidden)]
pub unsafe extern "C" fn $name<T>(
slf: *mut $crate::ffi::PyObject,
name: *mut $crate::ffi::PyObject,
value: *mut $crate::ffi::PyObject,
@ -268,14 +278,13 @@ macro_rules! py_func_del {
}
})
}
wrap::<$class>
}};
};
}
macro_rules! py_func_set_del {
($trait1:ident, $trait2:ident, $class:ident, $fn_set:ident, $fn_del:ident) => {{
unsafe extern "C" fn wrap<T>(
($name:ident, $trait1:ident, $trait2:ident, $class:ident, $fn_set:ident, $fn_del:ident) => {
#[doc(hidden)]
pub unsafe extern "C" fn $name<T>(
slf: *mut $crate::ffi::PyObject,
name: *mut $crate::ffi::PyObject,
value: *mut $crate::ffi::PyObject,
@ -295,8 +304,7 @@ macro_rules! py_func_set_del {
}
})
}
wrap::<$class>
}};
};
}
macro_rules! extract_or_return_not_implemented {

View file

@ -3,7 +3,6 @@
//! Python Mapping Interface
//! Trait and support implementation for implementing mapping support
use super::proto_methods::TypedSlot;
use crate::callback::IntoPyCallbackOutput;
use crate::{exceptions, ffi, FromPyObject, PyClass, PyObject};
@ -73,64 +72,15 @@ pub trait PyMappingReversedProtocol<'p>: PyMappingProtocol<'p> {
type Result: IntoPyCallbackOutput<PyObject>;
}
/// Extension trait for proc-macro backend.
#[doc(hidden)]
pub trait PyMappingSlots {
fn get_len() -> TypedSlot<ffi::lenfunc>
where
Self: for<'p> PyMappingLenProtocol<'p>,
{
TypedSlot(
ffi::Py_mp_length,
py_len_func!(PyMappingLenProtocol, Self::__len__),
)
}
fn get_getitem() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyMappingGetItemProtocol<'p>,
{
TypedSlot(
ffi::Py_mp_subscript,
py_binary_func!(PyMappingGetItemProtocol, Self::__getitem__),
)
}
fn get_setitem() -> TypedSlot<ffi::objobjargproc>
where
Self: for<'p> PyMappingSetItemProtocol<'p>,
{
TypedSlot(
ffi::Py_mp_ass_subscript,
py_func_set!(PyMappingSetItemProtocol, Self::__setitem__),
)
}
fn get_delitem() -> TypedSlot<ffi::objobjargproc>
where
Self: for<'p> PyMappingDelItemProtocol<'p>,
{
TypedSlot(
ffi::Py_mp_ass_subscript,
py_func_del!(PyMappingDelItemProtocol, Self::__delitem__),
)
}
fn get_setdelitem() -> TypedSlot<ffi::objobjargproc>
where
Self: for<'p> PyMappingSetItemProtocol<'p> + for<'p> PyMappingDelItemProtocol<'p>,
{
TypedSlot(
ffi::Py_mp_ass_subscript,
py_len_func!(len, PyMappingLenProtocol, Self::__len__);
py_binary_func!(getitem, PyMappingGetItemProtocol, Self::__getitem__);
py_func_set!(setitem, PyMappingSetItemProtocol, Self::__setitem__);
py_func_del!(delitem, PyMappingDelItemProtocol, Self::__delitem__);
py_func_set_del!(
setdelitem,
PyMappingSetItemProtocol,
PyMappingDelItemProtocol,
Self,
__setitem__,
__delitem__
),
)
}
}
impl<'p, T> PyMappingSlots for T where T: PyMappingProtocol<'p> {}
);

View file

@ -16,6 +16,7 @@ pub mod mapping;
#[doc(hidden)]
pub mod methods;
pub mod number;
#[doc(hidden)]
pub mod proto_methods;
pub mod pyasync;
pub mod sequence;

View file

@ -2,7 +2,6 @@
//! Python Number Interface
//! Trait and support implementation for implementing number protocol
use super::proto_methods::TypedSlot;
use crate::callback::IntoPyCallbackOutput;
use crate::err::PyErr;
use crate::{ffi, FromPyObject, PyClass, PyObject};
@ -579,160 +578,42 @@ pub trait PyNumberIndexProtocol<'p>: PyNumberProtocol<'p> {
type Result: IntoPyCallbackOutput<PyObject>;
}
/// Extension trait for proc-macro backend.
#[doc(hidden)]
pub trait PyNumberSlots {
fn get_add_radd() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberAddProtocol<'p> + for<'p> PyNumberRAddProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_add,
py_binary_fallback_num_func!(
Self,
add_radd,
T,
PyNumberAddProtocol::__add__,
PyNumberRAddProtocol::__radd__
),
)
}
fn get_add() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberAddProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_add,
py_binary_num_func!(PyNumberAddProtocol, Self::__add__),
)
}
fn get_radd() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberRAddProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_add,
py_binary_reversed_num_func!(PyNumberRAddProtocol, Self::__radd__),
)
}
fn get_sub_rsub() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberSubProtocol<'p> + for<'p> PyNumberRSubProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_subtract,
);
py_binary_num_func!(add, PyNumberAddProtocol, T::__add__);
py_binary_reversed_num_func!(radd, PyNumberRAddProtocol, T::__radd__);
py_binary_fallback_num_func!(
Self,
sub_rsub,
T,
PyNumberSubProtocol::__sub__,
PyNumberRSubProtocol::__rsub__
),
)
}
fn get_sub() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberSubProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_subtract,
py_binary_num_func!(PyNumberSubProtocol, Self::__sub__),
)
}
fn get_rsub() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberRSubProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_subtract,
py_binary_reversed_num_func!(PyNumberRSubProtocol, Self::__rsub__),
)
}
fn get_mul_rmul() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberMulProtocol<'p> + for<'p> PyNumberRMulProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_multiply,
);
py_binary_num_func!(sub, PyNumberSubProtocol, T::__sub__);
py_binary_reversed_num_func!(rsub, PyNumberRSubProtocol, T::__rsub__);
py_binary_fallback_num_func!(
Self,
mul_rmul,
T,
PyNumberMulProtocol::__mul__,
PyNumberRMulProtocol::__rmul__
),
)
}
fn get_mul() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberMulProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_multiply,
py_binary_num_func!(PyNumberMulProtocol, Self::__mul__),
)
}
fn get_rmul() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberRMulProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_multiply,
py_binary_reversed_num_func!(PyNumberRMulProtocol, Self::__rmul__),
)
}
fn get_mod() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberModProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_remainder,
py_binary_num_func!(PyNumberModProtocol, Self::__mod__),
)
}
fn get_divmod_rdivmod() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberDivmodProtocol<'p> + for<'p> PyNumberRDivmodProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_divmod,
);
py_binary_num_func!(mul, PyNumberMulProtocol, T::__mul__);
py_binary_reversed_num_func!(rmul, PyNumberRMulProtocol, T::__rmul__);
py_binary_num_func!(mod_, PyNumberModProtocol, T::__mod__);
py_binary_fallback_num_func!(
Self,
divmod_rdivmod,
T,
PyNumberDivmodProtocol::__divmod__,
PyNumberRDivmodProtocol::__rdivmod__
),
)
}
);
py_binary_num_func!(divmod, PyNumberDivmodProtocol, T::__divmod__);
py_binary_reversed_num_func!(rdivmod, PyNumberRDivmodProtocol, T::__rdivmod__);
fn get_divmod() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberDivmodProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_divmod,
py_binary_num_func!(PyNumberDivmodProtocol, Self::__divmod__),
)
}
fn get_rdivmod() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberRDivmodProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_divmod,
py_binary_reversed_num_func!(PyNumberRDivmodProtocol, Self::__rdivmod__),
)
}
fn get_pow_rpow() -> TypedSlot<ffi::ternaryfunc>
where
Self: for<'p> PyNumberPowProtocol<'p> + for<'p> PyNumberRPowProtocol<'p>,
{
unsafe extern "C" fn wrap_pow_and_rpow<T>(
#[doc(hidden)]
pub unsafe extern "C" fn pow_rpow<T>(
lhs: *mut ffi::PyObject,
rhs: *mut ffi::PyObject,
modulo: *mut ffi::PyObject,
@ -758,14 +639,8 @@ pub trait PyNumberSlots {
})
}
TypedSlot(ffi::Py_nb_power, wrap_pow_and_rpow::<Self>)
}
fn get_pow() -> TypedSlot<ffi::ternaryfunc>
where
Self: for<'p> PyNumberPowProtocol<'p>,
{
unsafe extern "C" fn wrap_pow<T>(
#[doc(hidden)]
pub unsafe extern "C" fn pow<T>(
lhs: *mut ffi::PyObject,
rhs: *mut ffi::PyObject,
modulo: *mut ffi::PyObject,
@ -781,14 +656,8 @@ pub trait PyNumberSlots {
})
}
TypedSlot(ffi::Py_nb_power, wrap_pow::<Self>)
}
fn get_rpow() -> TypedSlot<ffi::ternaryfunc>
where
Self: for<'p> PyNumberRPowProtocol<'p>,
{
unsafe extern "C" fn wrap_rpow<T>(
#[doc(hidden)]
pub unsafe extern "C" fn rpow<T>(
arg: *mut ffi::PyObject,
slf: *mut ffi::PyObject,
modulo: *mut ffi::PyObject,
@ -804,286 +673,59 @@ pub trait PyNumberSlots {
})
}
TypedSlot(ffi::Py_nb_power, wrap_rpow::<Self>)
}
fn get_neg() -> TypedSlot<ffi::unaryfunc>
where
Self: for<'p> PyNumberNegProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_negative,
py_unary_func!(PyNumberNegProtocol, Self::__neg__),
)
}
fn get_pos() -> TypedSlot<ffi::unaryfunc>
where
Self: for<'p> PyNumberPosProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_positive,
py_unary_func!(PyNumberPosProtocol, Self::__pos__),
)
}
fn get_abs() -> TypedSlot<ffi::unaryfunc>
where
Self: for<'p> PyNumberAbsProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_absolute,
py_unary_func!(PyNumberAbsProtocol, Self::__abs__),
)
}
fn get_invert() -> TypedSlot<ffi::unaryfunc>
where
Self: for<'p> PyNumberInvertProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_invert,
py_unary_func!(PyNumberInvertProtocol, Self::__invert__),
)
}
fn get_lshift_rlshift() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberLShiftProtocol<'p> + for<'p> PyNumberRLShiftProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_lshift,
py_unary_func!(neg, PyNumberNegProtocol, T::__neg__);
py_unary_func!(pos, PyNumberPosProtocol, T::__pos__);
py_unary_func!(abs, PyNumberAbsProtocol, T::__abs__);
py_unary_func!(invert, PyNumberInvertProtocol, T::__invert__);
py_binary_fallback_num_func!(
Self,
lshift_rlshift,
T,
PyNumberLShiftProtocol::__lshift__,
PyNumberRLShiftProtocol::__rlshift__
),
)
}
fn get_lshift() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberLShiftProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_lshift,
py_binary_num_func!(PyNumberLShiftProtocol, Self::__lshift__),
)
}
fn get_rlshift() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberRLShiftProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_lshift,
py_binary_reversed_num_func!(PyNumberRLShiftProtocol, Self::__rlshift__),
)
}
fn get_rshift_rrshift() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberRShiftProtocol<'p> + for<'p> PyNumberRRShiftProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_rshift,
);
py_binary_num_func!(lshift, PyNumberLShiftProtocol, T::__lshift__);
py_binary_reversed_num_func!(rlshift, PyNumberRLShiftProtocol, T::__rlshift__);
py_binary_fallback_num_func!(
Self,
rshift_rrshift,
T,
PyNumberRShiftProtocol::__rshift__,
PyNumberRRShiftProtocol::__rrshift__
),
)
}
fn get_rshift() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberRShiftProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_rshift,
py_binary_num_func!(PyNumberRShiftProtocol, Self::__rshift__),
)
}
fn get_rrshift() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberRRShiftProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_rshift,
py_binary_reversed_num_func!(PyNumberRRShiftProtocol, Self::__rrshift__),
)
}
fn get_and_rand() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberAndProtocol<'p> + for<'p> PyNumberRAndProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_and,
);
py_binary_num_func!(rshift, PyNumberRShiftProtocol, T::__rshift__);
py_binary_reversed_num_func!(rrshift, PyNumberRRShiftProtocol, T::__rrshift__);
py_binary_fallback_num_func!(
Self,
and_rand,
T,
PyNumberAndProtocol::__and__,
PyNumberRAndProtocol::__rand__
),
)
}
fn get_and() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberAndProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_and,
py_binary_num_func!(PyNumberAndProtocol, Self::__and__),
)
}
fn get_rand() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberRAndProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_and,
py_binary_reversed_num_func!(PyNumberRAndProtocol, Self::__rand__),
)
}
fn get_xor_rxor() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberXorProtocol<'p> + for<'p> PyNumberRXorProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_xor,
);
py_binary_num_func!(and, PyNumberAndProtocol, T::__and__);
py_binary_reversed_num_func!(rand, PyNumberRAndProtocol, T::__rand__);
py_binary_fallback_num_func!(
Self,
xor_rxor,
T,
PyNumberXorProtocol::__xor__,
PyNumberRXorProtocol::__rxor__
),
)
}
fn get_xor() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberXorProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_xor,
py_binary_num_func!(PyNumberXorProtocol, Self::__xor__),
)
}
fn get_rxor() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberRXorProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_xor,
py_binary_reversed_num_func!(PyNumberRXorProtocol, Self::__rxor__),
)
}
fn get_or_ror() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberOrProtocol<'p> + for<'p> PyNumberROrProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_or,
);
py_binary_num_func!(xor, PyNumberXorProtocol, T::__xor__);
py_binary_reversed_num_func!(rxor, PyNumberRXorProtocol, T::__rxor__);
py_binary_fallback_num_func!(
Self,
or_ror,
T,
PyNumberOrProtocol::__or__,
PyNumberROrProtocol::__ror__
),
)
}
);
py_binary_num_func!(or, PyNumberOrProtocol, T::__or__);
py_binary_reversed_num_func!(ror, PyNumberROrProtocol, T::__ror__);
py_unary_func!(int, PyNumberIntProtocol, T::__int__);
py_unary_func!(float, PyNumberFloatProtocol, T::__float__);
py_binary_self_func!(iadd, PyNumberIAddProtocol, T::__iadd__);
py_binary_self_func!(isub, PyNumberISubProtocol, T::__isub__);
py_binary_self_func!(imul, PyNumberIMulProtocol, T::__imul__);
py_binary_self_func!(imod, PyNumberIModProtocol, T::__imod__);
fn get_or() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberOrProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_or,
py_binary_num_func!(PyNumberOrProtocol, Self::__or__),
)
}
fn get_ror() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberROrProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_or,
py_binary_reversed_num_func!(PyNumberROrProtocol, Self::__ror__),
)
}
fn get_int() -> TypedSlot<ffi::unaryfunc>
where
Self: for<'p> PyNumberIntProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_int,
py_unary_func!(PyNumberIntProtocol, Self::__int__),
)
}
fn get_float() -> TypedSlot<ffi::unaryfunc>
where
Self: for<'p> PyNumberFloatProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_float,
py_unary_func!(PyNumberFloatProtocol, Self::__float__),
)
}
fn get_iadd() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberIAddProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_inplace_add,
py_binary_self_func!(PyNumberIAddProtocol, Self::__iadd__),
)
}
fn get_isub() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberISubProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_inplace_subtract,
py_binary_self_func!(PyNumberISubProtocol, Self::__isub__),
)
}
fn get_imul() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberIMulProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_inplace_multiply,
py_binary_self_func!(PyNumberIMulProtocol, Self::__imul__),
)
}
fn get_imod() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberIModProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_inplace_remainder,
py_binary_self_func!(PyNumberIModProtocol, Self::__imod__),
)
}
fn get_ipow() -> TypedSlot<ffi::ternaryfunc>
where
Self: for<'p> PyNumberIPowProtocol<'p>,
{
// NOTE: Somehow __ipow__ causes SIGSEGV in Python < 3.8 when we extract,
// so we ignore it. It's the same as what CPython does.
unsafe extern "C" fn wrap_ipow<T>(
#[doc(hidden)]
pub unsafe extern "C" fn ipow<T>(
slf: *mut ffi::PyObject,
other: *mut ffi::PyObject,
_modulo: *mut ffi::PyObject,
@ -1091,6 +733,8 @@ pub trait PyNumberSlots {
where
T: for<'p> PyNumberIPowProtocol<'p>,
{
// NOTE: Somehow __ipow__ causes SIGSEGV in Python < 3.8 when we extract,
// so we ignore it. It's the same as what CPython does.
crate::callback_body!(py, {
let slf_cell = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
let other = py.from_borrowed_ptr::<crate::PyAny>(other);
@ -1100,200 +744,36 @@ pub trait PyNumberSlots {
})
}
TypedSlot(ffi::Py_nb_inplace_power, wrap_ipow::<Self>)
}
fn get_ilshift() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberILShiftProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_inplace_lshift,
py_binary_self_func!(PyNumberILShiftProtocol, Self::__ilshift__),
)
}
fn get_irshift() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberIRShiftProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_inplace_rshift,
py_binary_self_func!(PyNumberIRShiftProtocol, Self::__irshift__),
)
}
fn get_iand() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberIAndProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_inplace_and,
py_binary_self_func!(PyNumberIAndProtocol, Self::__iand__),
)
}
fn get_ixor() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberIXorProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_inplace_xor,
py_binary_self_func!(PyNumberIXorProtocol, Self::__ixor__),
)
}
fn get_ior() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberIOrProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_inplace_or,
py_binary_self_func!(PyNumberIOrProtocol, Self::__ior__),
)
}
fn get_floordiv_rfloordiv() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberFloordivProtocol<'p> + for<'p> PyNumberRFloordivProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_floor_divide,
py_binary_self_func!(ilshift, PyNumberILShiftProtocol, T::__ilshift__);
py_binary_self_func!(irshift, PyNumberIRShiftProtocol, T::__irshift__);
py_binary_self_func!(iand, PyNumberIAndProtocol, T::__iand__);
py_binary_self_func!(ixor, PyNumberIXorProtocol, T::__ixor__);
py_binary_self_func!(ior, PyNumberIOrProtocol, T::__ior__);
py_binary_fallback_num_func!(
Self,
floordiv_rfloordiv,
T,
PyNumberFloordivProtocol::__floordiv__,
PyNumberRFloordivProtocol::__rfloordiv__
),
)
}
fn get_floordiv() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberFloordivProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_floor_divide,
py_binary_num_func!(PyNumberFloordivProtocol, Self::__floordiv__),
)
}
fn get_rfloordiv() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberRFloordivProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_floor_divide,
py_binary_reversed_num_func!(PyNumberRFloordivProtocol, Self::__rfloordiv__),
)
}
fn get_truediv_rtruediv() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberTruedivProtocol<'p> + for<'p> PyNumberRTruedivProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_true_divide,
);
py_binary_num_func!(floordiv, PyNumberFloordivProtocol, T::__floordiv__);
py_binary_reversed_num_func!(rfloordiv, PyNumberRFloordivProtocol, T::__rfloordiv__);
py_binary_fallback_num_func!(
Self,
truediv_rtruediv,
T,
PyNumberTruedivProtocol::__truediv__,
PyNumberRTruedivProtocol::__rtruediv__
),
)
}
fn get_truediv() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberTruedivProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_true_divide,
py_binary_num_func!(PyNumberTruedivProtocol, Self::__truediv__),
)
}
fn get_rtruediv() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberRTruedivProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_true_divide,
py_binary_reversed_num_func!(PyNumberRTruedivProtocol, Self::__rtruediv__),
)
}
fn get_ifloordiv() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberIFloordivProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_inplace_floor_divide,
py_binary_self_func!(PyNumberIFloordivProtocol, Self::__ifloordiv__),
)
}
fn get_itruediv() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberITruedivProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_inplace_true_divide,
py_binary_self_func!(PyNumberITruedivProtocol, Self::__itruediv__),
)
}
fn get_index() -> TypedSlot<ffi::unaryfunc>
where
Self: for<'p> PyNumberIndexProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_index,
py_unary_func!(PyNumberIndexProtocol, Self::__index__),
)
}
fn get_matmul_rmatmul() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberMatmulProtocol<'p> + for<'p> PyNumberRMatmulProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_matrix_multiply,
);
py_binary_num_func!(truediv, PyNumberTruedivProtocol, T::__truediv__);
py_binary_reversed_num_func!(rtruediv, PyNumberRTruedivProtocol, T::__rtruediv__);
py_binary_self_func!(ifloordiv, PyNumberIFloordivProtocol, T::__ifloordiv__);
py_binary_self_func!(itruediv, PyNumberITruedivProtocol, T::__itruediv__);
py_unary_func!(index, PyNumberIndexProtocol, T::__index__);
py_binary_fallback_num_func!(
Self,
matmul_rmatmul,
T,
PyNumberMatmulProtocol::__matmul__,
PyNumberRMatmulProtocol::__rmatmul__
),
)
}
fn get_matmul() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberMatmulProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_matrix_multiply,
py_binary_num_func!(PyNumberMatmulProtocol, Self::__matmul__),
)
}
fn get_rmatmul() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberRMatmulProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_matrix_multiply,
py_binary_reversed_num_func!(PyNumberRMatmulProtocol, Self::__rmatmul__),
)
}
fn get_imatmul() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PyNumberIMatmulProtocol<'p>,
{
TypedSlot(
ffi::Py_nb_inplace_matrix_multiply,
py_binary_self_func!(PyNumberIMatmulProtocol, Self::__imatmul__),
)
}
}
impl<'p, T> PyNumberSlots for T where T: PyNumberProtocol<'p> {}
);
py_binary_num_func!(matmul, PyNumberMatmulProtocol, T::__matmul__);
py_binary_reversed_num_func!(rmatmul, PyNumberRMatmulProtocol, T::__rmatmul__);
py_binary_self_func!(imatmul, PyNumberIMatmulProtocol, T::__imatmul__);

View file

@ -1,78 +1,147 @@
use crate::ffi;
#[cfg(not(Py_LIMITED_API))]
use crate::ffi::PyBufferProcs;
/// ABI3 doesn't have buffer APIs, so here we define the empty one.
#[cfg(Py_LIMITED_API)]
#[doc(hidden)]
#[derive(Clone)]
pub struct PyBufferProcs;
use std::marker::PhantomData;
// Note(kngwyu): default implementations are for rust-numpy. Please don't remove them.
pub trait PyProtoMethods {
fn get_type_slots() -> Vec<ffi::PyType_Slot> {
vec![]
}
fn get_buffer() -> Option<PyBufferProcs> {
fn for_each_proto_slot<Visitor: FnMut(ffi::PyType_Slot)>(_visitor: Visitor) {}
fn get_buffer() -> Option<&'static PyBufferProcs> {
None
}
}
/// Typed version of `ffi::PyType_Slot`
#[doc(hidden)]
pub struct TypedSlot<T: Sized>(pub std::os::raw::c_int, pub T);
pub struct PyClassProtocols<T>(PhantomData<T>);
#[doc(hidden)]
pub enum PyProtoMethodDef {
Slots(Vec<ffi::PyType_Slot>),
Buffer(PyBufferProcs),
}
impl From<Vec<ffi::PyType_Slot>> for PyProtoMethodDef {
fn from(slots: Vec<ffi::PyType_Slot>) -> Self {
PyProtoMethodDef::Slots(slots)
impl<T> PyClassProtocols<T> {
pub fn new() -> Self {
Self(PhantomData)
}
}
impl From<PyBufferProcs> for PyProtoMethodDef {
fn from(buffer_procs: PyBufferProcs) -> Self {
PyProtoMethodDef::Buffer(buffer_procs)
impl<T> Default for PyClassProtocols<T> {
fn default() -> Self {
Self::new()
}
}
#[doc(hidden)]
#[cfg(feature = "macros")]
pub trait PyProtoInventory: inventory::Collect {
fn new(methods: PyProtoMethodDef) -> Self;
fn get(&'static self) -> &'static PyProtoMethodDef;
impl<T> Clone for PyClassProtocols<T> {
fn clone(&self) -> Self {
Self::new()
}
}
#[doc(hidden)]
#[cfg(feature = "macros")]
pub trait HasProtoInventory {
type ProtoMethods: PyProtoInventory;
impl<T> Copy for PyClassProtocols<T> {}
// All traits describing slots, as well as the fallback implementations for unimplemented protos
//
// Protos which are implented use dtolnay specialization to implement for PyClassProtocols<T>.
//
// See https://github.com/dtolnay/case-studies/blob/master/autoref-specialization/README.md
pub trait PyObjectProtocolSlots<T> {
fn object_protocol_slots(self) -> &'static [ffi::PyType_Slot];
}
#[cfg(feature = "macros")]
impl<T: HasProtoInventory> PyProtoMethods for T {
fn get_type_slots() -> Vec<ffi::PyType_Slot> {
inventory::iter::<T::ProtoMethods>
.into_iter()
.filter_map(|def| match def.get() {
PyProtoMethodDef::Slots(slots) => Some(slots),
PyProtoMethodDef::Buffer(_) => None,
})
.flatten()
.cloned()
.collect()
impl<T> PyObjectProtocolSlots<T> for &'_ PyClassProtocols<T> {
fn object_protocol_slots(self) -> &'static [ffi::PyType_Slot] {
&[]
}
}
fn get_buffer() -> Option<PyBufferProcs> {
inventory::iter::<T::ProtoMethods>
.into_iter()
.find_map(|def| match def.get() {
PyProtoMethodDef::Slots(_) => None,
PyProtoMethodDef::Buffer(buf) => Some(buf.clone()),
})
pub trait PyDescrProtocolSlots<T> {
fn descr_protocol_slots(self) -> &'static [ffi::PyType_Slot];
}
impl<T> PyDescrProtocolSlots<T> for &'_ PyClassProtocols<T> {
fn descr_protocol_slots(self) -> &'static [ffi::PyType_Slot] {
&[]
}
}
pub trait PyGCProtocolSlots<T> {
fn gc_protocol_slots(self) -> &'static [ffi::PyType_Slot];
}
impl<T> PyGCProtocolSlots<T> for &'_ PyClassProtocols<T> {
fn gc_protocol_slots(self) -> &'static [ffi::PyType_Slot] {
&[]
}
}
pub trait PyIterProtocolSlots<T> {
fn iter_protocol_slots(self) -> &'static [ffi::PyType_Slot];
}
impl<T> PyIterProtocolSlots<T> for &'_ PyClassProtocols<T> {
fn iter_protocol_slots(self) -> &'static [ffi::PyType_Slot] {
&[]
}
}
pub trait PyMappingProtocolSlots<T> {
fn mapping_protocol_slots(self) -> &'static [ffi::PyType_Slot];
}
impl<T> PyMappingProtocolSlots<T> for &'_ PyClassProtocols<T> {
fn mapping_protocol_slots(self) -> &'static [ffi::PyType_Slot] {
&[]
}
}
pub trait PyNumberProtocolSlots<T> {
fn number_protocol_slots(self) -> &'static [ffi::PyType_Slot];
}
impl<T> PyNumberProtocolSlots<T> for &'_ PyClassProtocols<T> {
fn number_protocol_slots(self) -> &'static [ffi::PyType_Slot] {
&[]
}
}
pub trait PyAsyncProtocolSlots<T> {
fn async_protocol_slots(self) -> &'static [ffi::PyType_Slot];
}
impl<T> PyAsyncProtocolSlots<T> for &'_ PyClassProtocols<T> {
fn async_protocol_slots(self) -> &'static [ffi::PyType_Slot] {
&[]
}
}
pub trait PySequenceProtocolSlots<T> {
fn sequence_protocol_slots(self) -> &'static [ffi::PyType_Slot];
}
impl<T> PySequenceProtocolSlots<T> for &'_ PyClassProtocols<T> {
fn sequence_protocol_slots(self) -> &'static [ffi::PyType_Slot] {
&[]
}
}
pub trait PyBufferProtocolSlots<T> {
fn buffer_protocol_slots(self) -> &'static [ffi::PyType_Slot];
}
impl<T> PyBufferProtocolSlots<T> for &'_ PyClassProtocols<T> {
fn buffer_protocol_slots(self) -> &'static [ffi::PyType_Slot] {
&[]
}
}
// On Python < 3.9 setting the buffer protocol using slots doesn't work, so these procs are used
// on those versions to set the slots manually (on the limited API).
#[cfg(not(Py_LIMITED_API))]
pub use ffi::PyBufferProcs;
#[cfg(Py_LIMITED_API)]
pub struct PyBufferProcs;
pub trait PyBufferProtocolProcs<T> {
fn buffer_procs(self) -> Option<&'static PyBufferProcs>;
}
impl<T> PyBufferProtocolProcs<T> for &'_ PyClassProtocols<T> {
fn buffer_procs(self) -> Option<&'static PyBufferProcs> {
None
}
}

View file

@ -8,7 +8,6 @@
//! [PEP-0492](https://www.python.org/dev/peps/pep-0492/)
//!
use super::proto_methods::TypedSlot;
use crate::callback::IntoPyCallbackOutput;
use crate::derive_utils::TryFromPyCell;
use crate::err::PyResult;
@ -86,41 +85,9 @@ pub trait PyAsyncAexitProtocol<'p>: PyAsyncProtocol<'p> {
type Result: IntoPyCallbackOutput<PyObject>;
}
/// Extension trait for proc-macro backend.
#[doc(hidden)]
pub trait PyAsyncSlots {
fn get_await() -> TypedSlot<ffi::unaryfunc>
where
Self: for<'p> PyAsyncAwaitProtocol<'p>,
{
TypedSlot(
ffi::Py_am_await,
py_unarys_func!(PyAsyncAwaitProtocol, Self::__await__),
)
}
fn get_aiter() -> TypedSlot<ffi::unaryfunc>
where
Self: for<'p> PyAsyncAiterProtocol<'p>,
{
TypedSlot(
ffi::Py_am_aiter,
py_unarys_func!(PyAsyncAiterProtocol, Self::__aiter__),
)
}
fn get_anext() -> TypedSlot<ffi::unaryfunc>
where
Self: for<'p> PyAsyncAnextProtocol<'p>,
{
TypedSlot(
ffi::Py_am_anext,
py_unarys_func!(PyAsyncAnextProtocol, Self::__anext__),
)
}
}
impl<'p, T> PyAsyncSlots for T where T: PyAsyncProtocol<'p> {}
py_unarys_func!(await_, PyAsyncAwaitProtocol, Self::__await__);
py_unarys_func!(aiter, PyAsyncAiterProtocol, Self::__aiter__);
py_unarys_func!(anext, PyAsyncAnextProtocol, Self::__anext__);
/// Output of `__anext__`.
pub enum IterANextOutput<T, U> {

View file

@ -3,7 +3,6 @@
//! Python Sequence Interface
//! Trait and support implementation for implementing sequence
use super::proto_methods::TypedSlot;
use crate::callback::IntoPyCallbackOutput;
use crate::conversion::{FromPyObject, IntoPy};
use crate::err::PyErr;
@ -129,54 +128,13 @@ pub trait PySequenceInplaceRepeatProtocol<'p>:
type Result: IntoPyCallbackOutput<Self>;
}
/// Extension trait for proc-macro backend.
py_len_func!(len, PySequenceLenProtocol, Self::__len__);
py_binary_func!(concat, PySequenceConcatProtocol, Self::__concat__);
py_ssizearg_func!(repeat, PySequenceRepeatProtocol, Self::__repeat__);
py_ssizearg_func!(getitem, PySequenceGetItemProtocol, Self::__getitem__);
#[doc(hidden)]
pub trait PySequenceSlots {
fn get_len() -> TypedSlot<ffi::lenfunc>
where
Self: for<'p> PySequenceLenProtocol<'p>,
{
TypedSlot(
ffi::Py_sq_length,
py_len_func!(PySequenceLenProtocol, Self::__len__),
)
}
fn get_concat() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PySequenceConcatProtocol<'p>,
{
TypedSlot(
ffi::Py_sq_concat,
py_binary_func!(PySequenceConcatProtocol, Self::__concat__),
)
}
fn get_repeat() -> TypedSlot<ffi::ssizeargfunc>
where
Self: for<'p> PySequenceRepeatProtocol<'p>,
{
TypedSlot(
ffi::Py_sq_repeat,
py_ssizearg_func!(PySequenceRepeatProtocol, Self::__repeat__),
)
}
fn get_getitem() -> TypedSlot<ffi::ssizeargfunc>
where
Self: for<'p> PySequenceGetItemProtocol<'p>,
{
TypedSlot(
ffi::Py_sq_item,
py_ssizearg_func!(PySequenceGetItemProtocol, Self::__getitem__),
)
}
fn get_setitem() -> TypedSlot<ffi::ssizeobjargproc>
where
Self: for<'p> PySequenceSetItemProtocol<'p>,
{
unsafe extern "C" fn wrap<T>(
pub unsafe extern "C" fn setitem<T>(
slf: *mut ffi::PyObject,
key: ffi::Py_ssize_t,
value: *mut ffi::PyObject,
@ -201,14 +159,8 @@ pub trait PySequenceSlots {
})
}
TypedSlot(ffi::Py_sq_ass_item, wrap::<Self>)
}
fn get_delitem() -> TypedSlot<ffi::ssizeobjargproc>
where
Self: for<'p> PySequenceDelItemProtocol<'p>,
{
unsafe extern "C" fn wrap<T>(
#[doc(hidden)]
pub unsafe extern "C" fn delitem<T>(
slf: *mut ffi::PyObject,
key: ffi::Py_ssize_t,
value: *mut ffi::PyObject,
@ -230,14 +182,8 @@ pub trait PySequenceSlots {
})
}
TypedSlot(ffi::Py_sq_ass_item, wrap::<Self>)
}
fn get_setdelitem() -> TypedSlot<ffi::ssizeobjargproc>
where
Self: for<'p> PySequenceDelItemProtocol<'p> + for<'p> PySequenceSetItemProtocol<'p>,
{
unsafe extern "C" fn wrap<T>(
#[doc(hidden)]
pub unsafe extern "C" fn setdelitem<T>(
slf: *mut ffi::PyObject,
key: ffi::Py_ssize_t,
value: *mut ffi::PyObject,
@ -259,47 +205,22 @@ pub trait PySequenceSlots {
})
}
TypedSlot(ffi::Py_sq_ass_item, wrap::<Self>)
}
fn get_contains() -> TypedSlot<ffi::objobjproc>
where
Self: for<'p> PySequenceContainsProtocol<'p>,
{
TypedSlot(
ffi::Py_sq_contains,
py_binary_func!(PySequenceContainsProtocol, Self::__contains__, c_int),
)
}
fn get_inplace_concat() -> TypedSlot<ffi::binaryfunc>
where
Self: for<'p> PySequenceInplaceConcatProtocol<'p>,
{
TypedSlot(
ffi::Py_sq_inplace_concat,
py_binary_func!(
contains,
PySequenceContainsProtocol,
Self::__contains__,
c_int
);
py_binary_func!(
inplace_concat,
PySequenceInplaceConcatProtocol,
Self::__inplace_concat__,
*mut ffi::PyObject,
call_mut
),
)
}
fn get_inplace_repeat() -> TypedSlot<ffi::ssizeargfunc>
where
Self: for<'p> PySequenceInplaceRepeatProtocol<'p>,
{
TypedSlot(
ffi::Py_sq_inplace_repeat,
);
py_ssizearg_func!(
inplace_repeat,
PySequenceInplaceRepeatProtocol,
Self::__inplace_repeat__,
call_mut
),
)
}
}
impl<'p, T> PySequenceSlots for T where T: PySequenceProtocol<'p> {}
);

View file

@ -1,5 +1,9 @@
use std::os::raw::c_int;
#[cfg(not(Py_LIMITED_API))]
pub const Py_bf_getbuffer: c_int = 1;
#[cfg(not(Py_LIMITED_API))]
pub const Py_bf_releasebuffer: c_int = 2;
pub const Py_mp_ass_subscript: c_int = 3;
pub const Py_mp_length: c_int = 4;
pub const Py_mp_subscript: c_int = 5;

View file

@ -339,16 +339,15 @@ macro_rules! py_run_impl {
use $crate::ToPyObject;
let d = [$((stringify!($val), $val.to_object($py)),)+].into_py_dict($py);
$py.run($code, None, Some(d))
.map_err(|e| {
if let Err(e) = $py.run($code, None, Some(d)) {
e.print($py);
// So when this c api function the last line called printed the error to stderr,
// the output is only written into a buffer which is never flushed because we
// panic before flushing. This is where this hack comes into place
$py.run("import sys; sys.stderr.flush()", None, None)
.unwrap();
})
.expect($code)
panic!($code.to_string())
}
}};
}

View file

@ -191,11 +191,11 @@ where
// protocol methods
let mut has_gc_methods = false;
for slot in T::get_type_slots() {
T::for_each_proto_slot(|slot| {
has_gc_methods |= slot.slot == ffi::Py_tp_clear;
has_gc_methods |= slot.slot == ffi::Py_tp_traverse;
slots.0.push(slot);
}
});
slots.push(0, ptr::null_mut());
let mut spec = ffi::PyType_Spec {
@ -238,6 +238,9 @@ fn tp_init_additional<T: PyClass>(type_object: *mut ffi::PyTypeObject) {
}
}
// Setting buffer protocols via slots doesn't work until Python 3.9, so on older versions we
// must manually fixup the type object.
#[cfg(not(Py_3_9))]
if let Some(buffer) = T::get_buffer() {
unsafe {
(*(*type_object).tp_as_buffer).bf_getbuffer = buffer.bf_getbuffer;