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); pyo3::inventory::collect!(Pyo3MethodsInventoryForMyClass);
impl pyo3::class::proto_methods::PyProtoMethods for MyClass {
pub struct Pyo3ProtoInventoryForMyClass { fn for_each_proto_slot<Visitor: FnMut(pyo3::ffi::PyType_Slot)>(visitor: Visitor) {
def: pyo3::class::proto_methods::PyProtoMethodDef, // Implementation which uses dtolnay specialization to load all slots.
} use pyo3::class::proto_methods::*;
impl pyo3::class::proto_methods::PyProtoInventory for Pyo3ProtoInventoryForMyClass { let protocols = PyClassProtocols::<MyClass>::new();
fn new(def: pyo3::class::proto_methods::PyProtoMethodDef) -> Self { protocols.object_protocol_slots()
Self { def } .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(&'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 { impl pyo3::pyclass::PyClassSend for MyClass {
type ThreadChecker = pyo3::pyclass::ThreadCheckerStub<MyClass>; type ThreadChecker = pyo3::pyclass::ThreadCheckerStub<MyClass>;

View File

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

View File

@ -62,12 +62,13 @@ fn impl_proto_impl(
let mut trait_impls = TokenStream::new(); let mut trait_impls = TokenStream::new();
let mut py_methods = Vec::new(); let mut py_methods = Vec::new();
let mut method_names = HashSet::new(); let mut method_names = HashSet::new();
let module = proto.module();
for iimpl in impls.iter_mut() { for iimpl in impls.iter_mut() {
if let syn::ImplItem::Method(met) = iimpl { if let syn::ImplItem::Method(met) = iimpl {
// impl Py~Protocol<'p> { type = ... } // impl Py~Protocol<'p> { type = ... }
if let Some(m) = proto.get_proto(&met.sig.ident) { if let Some(m) = proto.get_proto(&met.sig.ident) {
impl_method_proto(ty, &mut met.sig, m)?.to_tokens(&mut trait_impls); impl_method_proto(ty, &mut met.sig, &module, m)?.to_tokens(&mut trait_impls);
// Insert the method to the HashSet // Insert the method to the HashSet
method_names.insert(met.sig.ident.to_string()); 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 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! { Ok(quote! {
#trait_impls #trait_impls
#normal_methods #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>, method_names: HashSet<String>,
ty: &syn::Type, ty: &syn::Type,
proto: &defs::Proto, proto: &defs::Proto,
) -> syn::Result<TokenStream> { ) -> TokenStream {
if proto.extension_trait == "" { if proto.slots_trait.is_empty() {
return Ok(quote! {}); 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" { if proto.name == "Buffer" {
// For buffer, we construct `PyProtoMethods` from PyBufferProcs // On Python 3.9 we have to use PyBufferProcs to set buffer slots.
tokens.push(quote! { // For now we emit this always for buffer methods, even on 3.9+.
let mut proto_methods = pyo3::ffi::PyBufferProcs::default(); // Maybe in the future we can access Py_3_9 here and define it.
}); maybe_buffer_methods = Some(quote! {
for getter in proto.slot_getters(method_names) { impl pyo3::class::proto_methods::PyBufferProtocolProcs<#ty>
let get = syn::Ident::new(getter, Span::call_site()); for pyo3::class::proto_methods::PyClassProtocols<#ty>
let field = syn::Ident::new(&format!("bf_{}", &getter[4..]), Span::call_site()); {
tokens.push(quote! { proto_methods.#field = Some(<#ty as #ext_trait>::#get()); }); fn buffer_procs(
} self
} else { ) -> Option<&'static pyo3::class::proto_methods::PyBufferProcs> {
// For other protocols, we construct `PyProtoMethods` from Vec<ffi::PyType_Slot> static PROCS: pyo3::class::proto_methods::PyBufferProcs
tokens.push(quote! { let mut proto_methods = vec![]; }); = pyo3::class::proto_methods::PyBufferProcs {
for getter in proto.slot_getters(method_names) { bf_getbuffer: Some(pyo3::class::buffer::getbuffer::<#ty>),
let get = syn::Ident::new(getter, Span::call_site()); bf_releasebuffer: Some(pyo3::class::buffer::releasebuffer::<#ty>),
tokens.push(quote! {
let slot = <#ty as #ext_trait>::#get();
proto_methods.push(pyo3::ffi::PyType_Slot { slot: slot.0, pfunc: slot.1 as _ });
});
}
}; };
if tokens.len() <= 1 { Some(&PROCS)
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() }
)
} }
} }
});
}
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 //! Parts of the documentation are copied from the respective methods from the
//! [typeobj docs](https://docs.python.org/3/c-api/typeobj.html) //! [typeobj docs](https://docs.python.org/3/c-api/typeobj.html)
use super::proto_methods::TypedSlot;
use crate::callback::{HashCallbackOutput, IntoPyCallbackOutput}; 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; use std::os::raw::c_int;
/// Operators for the __richcmp__ method /// Operators for the __richcmp__ method
@ -134,50 +133,18 @@ pub trait PyObjectRichcmpProtocol<'p>: PyObjectProtocol<'p> {
type Result: IntoPyCallbackOutput<PyObject>; 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)] #[doc(hidden)]
pub trait PyBasicSlots { pub unsafe extern "C" fn getattr<T>(
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>(
slf: *mut ffi::PyObject, slf: *mut ffi::PyObject,
arg: *mut ffi::PyObject, arg: *mut ffi::PyObject,
) -> *mut ffi::PyObject ) -> *mut ffi::PyObject
where where
T: for<'p> PyObjectGetAttrProtocol<'p>, T: for<'p> PyObjectGetAttrProtocol<'p>,
{ {
crate::callback_body!(py, { crate::callback_body!(py, {
// Behave like python's __getattr__ (as opposed to __getattribute__) and check // Behave like python's __getattr__ (as opposed to __getattribute__) and check
// for existing fields and methods first // for existing fields and methods first
@ -193,91 +160,46 @@ pub trait PyBasicSlots {
let arg = py.from_borrowed_ptr::<PyAny>(arg); let arg = py.from_borrowed_ptr::<PyAny>(arg);
call_ref!(slf, __getattr__, arg).convert(py) call_ref!(slf, __getattr__, arg).convert(py)
}) })
} }
TypedSlot(ffi::Py_tp_getattro, wrap::<Self>)
}
fn get_richcmp() -> TypedSlot<ffi::richcmpfunc> #[doc(hidden)]
where pub unsafe extern "C" fn richcmp<T>(
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>(
slf: *mut ffi::PyObject, slf: *mut ffi::PyObject,
arg: *mut ffi::PyObject, arg: *mut ffi::PyObject,
op: c_int, op: c_int,
) -> *mut ffi::PyObject ) -> *mut ffi::PyObject
where where
T: for<'p> PyObjectRichcmpProtocol<'p>, T: for<'p> PyObjectRichcmpProtocol<'p>,
{ {
crate::callback_body!(py, { crate::callback_body!(py, {
let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf); let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
let arg = extract_or_return_not_implemented!(py, arg); 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) slf.try_borrow()?.__richcmp__(arg, op).convert(py)
}) })
} }
TypedSlot(ffi::Py_tp_richcompare, wrap::<Self>)
}
fn get_setattr() -> TypedSlot<ffi::setattrofunc> py_func_set!(setattr, PyObjectSetAttrProtocol, T::__setattr__);
where py_func_del!(delattr, PyObjectDelAttrProtocol, T::__delattr__);
Self: for<'p> PyObjectSetAttrProtocol<'p>, py_func_set_del!(
{ setdelattr,
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_del!(
PyObjectSetAttrProtocol, PyObjectSetAttrProtocol,
PyObjectDelAttrProtocol, PyObjectDelAttrProtocol,
Self, Self,
__setattr__, __setattr__,
__delattr__ __delattr__
), );
) py_unary_func!(bool, PyObjectBoolProtocol, T::__bool__, c_int);
}
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> {}

View File

@ -11,22 +11,18 @@ use std::os::raw::c_int;
/// Buffer protocol interface /// Buffer protocol interface
/// ///
/// For more information check [buffer protocol](https://docs.python.org/3/c-api/buffer.html) /// For more information check [buffer protocol](https://docs.python.org/3/c-api/buffer.html)
/// c-api /// c-api.
#[allow(unused_variables)] #[allow(unused_variables)]
pub trait PyBufferProtocol<'p>: PyClass { 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 fn bf_getbuffer(slf: PyRefMut<Self>, view: *mut ffi::Py_buffer, flags: c_int) -> Self::Result
where where
Self: PyBufferGetBufferProtocol<'p>, Self: PyBufferGetBufferProtocol<'p>;
{
unimplemented!()
}
fn bf_releasebuffer(slf: PyRefMut<Self>, view: *mut ffi::Py_buffer) -> Self::Result fn bf_releasebuffer(slf: PyRefMut<Self>, view: *mut ffi::Py_buffer) -> Self::Result
where where
Self: PyBufferReleaseBufferProtocol<'p>, Self: PyBufferReleaseBufferProtocol<'p>;
{
unimplemented!()
}
} }
pub trait PyBufferGetBufferProtocol<'p>: PyBufferProtocol<'p> { pub trait PyBufferGetBufferProtocol<'p>: PyBufferProtocol<'p> {
@ -37,46 +33,28 @@ pub trait PyBufferReleaseBufferProtocol<'p>: PyBufferProtocol<'p> {
type Result: IntoPyCallbackOutput<()>; type Result: IntoPyCallbackOutput<()>;
} }
/// Extension trait for proc-macro backend.
#[doc(hidden)] #[doc(hidden)]
pub trait PyBufferSlots { pub unsafe extern "C" fn getbuffer<T>(
fn get_getbuffer() -> ffi::getbufferproc
where
Self: for<'p> PyBufferGetBufferProtocol<'p>,
{
unsafe extern "C" fn wrap<T>(
slf: *mut ffi::PyObject, slf: *mut ffi::PyObject,
arg1: *mut ffi::Py_buffer, arg1: *mut ffi::Py_buffer,
arg2: c_int, arg2: c_int,
) -> c_int ) -> c_int
where where
T: for<'p> PyBufferGetBufferProtocol<'p>, T: for<'p> PyBufferGetBufferProtocol<'p>,
{ {
crate::callback_body!(py, { crate::callback_body!(py, {
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf); let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
T::bf_getbuffer(slf.try_borrow_mut()?, arg1, arg2).convert(py) T::bf_getbuffer(slf.try_borrow_mut()?, arg1, arg2).convert(py)
}) })
} }
wrap::<Self> #[doc(hidden)]
} pub unsafe extern "C" fn releasebuffer<T>(slf: *mut ffi::PyObject, arg1: *mut ffi::Py_buffer)
where
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)
where
T: for<'p> PyBufferReleaseBufferProtocol<'p>, T: for<'p> PyBufferReleaseBufferProtocol<'p>,
{ {
crate::callback_body!(py, { crate::callback_body!(py, {
let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf); let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
T::bf_releasebuffer(slf.try_borrow_mut()?, arg1).convert(py) 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]( //! [Python information](
//! https://docs.python.org/3/reference/datamodel.html#implementing-descriptors) //! https://docs.python.org/3/reference/datamodel.html#implementing-descriptors)
use super::proto_methods::TypedSlot;
use crate::callback::IntoPyCallbackOutput; use crate::callback::IntoPyCallbackOutput;
use crate::types::PyAny; use crate::types::PyAny;
use crate::{ffi, FromPyObject, PyClass, PyObject}; use crate::{FromPyObject, PyClass, PyObject};
use std::os::raw::c_int; use std::os::raw::c_int;
/// Descriptor interface /// Descriptor interface
@ -71,28 +70,5 @@ pub trait PyDescrSetNameProtocol<'p>: PyDescrProtocol<'p> {
type Result: IntoPyCallbackOutput<()>; type Result: IntoPyCallbackOutput<()>;
} }
/// Extension trait for our proc-macro backend. py_ternarys_func!(descr_get, PyDescrGetProtocol, Self::__get__);
#[doc(hidden)] py_ternarys_func!(descr_set, PyDescrSetProtocol, Self::__set__, c_int);
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> {}

View File

@ -3,7 +3,6 @@
//! Python GC support //! Python GC support
//! //!
use super::proto_methods::TypedSlot;
use crate::{ffi, AsPyPointer, PyCell, PyClass, Python}; use crate::{ffi, AsPyPointer, PyCell, PyClass, Python};
use std::os::raw::{c_int, c_void}; use std::os::raw::{c_int, c_void};
@ -19,21 +18,15 @@ pub trait PyGCProtocol<'p>: PyClass {
pub trait PyGCTraverseProtocol<'p>: PyGCProtocol<'p> {} pub trait PyGCTraverseProtocol<'p>: PyGCProtocol<'p> {}
pub trait PyGCClearProtocol<'p>: PyGCProtocol<'p> {} pub trait PyGCClearProtocol<'p>: PyGCProtocol<'p> {}
/// Extension trait for proc-macro backend.
#[doc(hidden)] #[doc(hidden)]
pub trait PyGCSlots { pub unsafe extern "C" fn traverse<T>(
fn get_traverse() -> TypedSlot<ffi::traverseproc>
where
Self: for<'p> PyGCTraverseProtocol<'p>,
{
unsafe extern "C" fn wrap<T>(
slf: *mut ffi::PyObject, slf: *mut ffi::PyObject,
visit: ffi::visitproc, visit: ffi::visitproc,
arg: *mut c_void, arg: *mut c_void,
) -> c_int ) -> c_int
where where
T: for<'p> PyGCTraverseProtocol<'p>, T: for<'p> PyGCTraverseProtocol<'p>,
{ {
let pool = crate::GILPool::new(); let pool = crate::GILPool::new();
let py = pool.python(); let py = pool.python();
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf); let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
@ -52,32 +45,20 @@ pub trait PyGCSlots {
} else { } else {
0 0
} }
} }
TypedSlot(ffi::Py_tp_traverse, wrap::<Self>) #[doc(hidden)]
} pub unsafe extern "C" fn clear<T>(slf: *mut ffi::PyObject) -> c_int
where
fn get_clear() -> TypedSlot<ffi::inquiry>
where
Self: for<'p> PyGCClearProtocol<'p>,
{
unsafe extern "C" fn wrap<T>(slf: *mut ffi::PyObject) -> c_int
where
T: for<'p> PyGCClearProtocol<'p>, T: for<'p> PyGCClearProtocol<'p>,
{ {
let pool = crate::GILPool::new(); let pool = crate::GILPool::new();
let slf = pool.python().from_borrowed_ptr::<PyCell<T>>(slf); let slf = pool.python().from_borrowed_ptr::<PyCell<T>>(slf);
slf.borrow_mut().__clear__(); slf.borrow_mut().__clear__();
0 0
}
TypedSlot(ffi::Py_tp_clear, wrap::<Self>)
}
} }
impl<'p, T> PyGCSlots for T where T: PyGCProtocol<'p> {}
/// Object visitor for GC. /// Object visitor for GC.
#[derive(Clone)] #[derive(Clone)]
pub struct PyVisit<'p> { pub struct PyVisit<'p> {

View File

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

View File

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

View File

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

View File

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

View File

@ -2,7 +2,6 @@
//! Python Number Interface //! Python Number Interface
//! Trait and support implementation for implementing number protocol //! Trait and support implementation for implementing number protocol
use super::proto_methods::TypedSlot;
use crate::callback::IntoPyCallbackOutput; use crate::callback::IntoPyCallbackOutput;
use crate::err::PyErr; use crate::err::PyErr;
use crate::{ffi, FromPyObject, PyClass, PyObject}; use crate::{ffi, FromPyObject, PyClass, PyObject};
@ -579,167 +578,49 @@ pub trait PyNumberIndexProtocol<'p>: PyNumberProtocol<'p> {
type Result: IntoPyCallbackOutput<PyObject>; type Result: IntoPyCallbackOutput<PyObject>;
} }
/// Extension trait for proc-macro backend. py_binary_fallback_num_func!(
#[doc(hidden)] add_radd,
pub trait PyNumberSlots { T,
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,
PyNumberAddProtocol::__add__, PyNumberAddProtocol::__add__,
PyNumberRAddProtocol::__radd__ PyNumberRAddProtocol::__radd__
), );
) py_binary_num_func!(add, PyNumberAddProtocol, T::__add__);
} py_binary_reversed_num_func!(radd, PyNumberRAddProtocol, T::__radd__);
py_binary_fallback_num_func!(
fn get_add() -> TypedSlot<ffi::binaryfunc> sub_rsub,
where T,
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_fallback_num_func!(
Self,
PyNumberSubProtocol::__sub__, PyNumberSubProtocol::__sub__,
PyNumberRSubProtocol::__rsub__ PyNumberRSubProtocol::__rsub__
), );
) py_binary_num_func!(sub, PyNumberSubProtocol, T::__sub__);
} py_binary_reversed_num_func!(rsub, PyNumberRSubProtocol, T::__rsub__);
py_binary_fallback_num_func!(
fn get_sub() -> TypedSlot<ffi::binaryfunc> mul_rmul,
where T,
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_fallback_num_func!(
Self,
PyNumberMulProtocol::__mul__, PyNumberMulProtocol::__mul__,
PyNumberRMulProtocol::__rmul__ PyNumberRMulProtocol::__rmul__
), );
) 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__);
fn get_mul() -> TypedSlot<ffi::binaryfunc> py_binary_fallback_num_func!(
where divmod_rdivmod,
Self: for<'p> PyNumberMulProtocol<'p>, T,
{
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_fallback_num_func!(
Self,
PyNumberDivmodProtocol::__divmod__, PyNumberDivmodProtocol::__divmod__,
PyNumberRDivmodProtocol::__rdivmod__ 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> #[doc(hidden)]
where pub unsafe extern "C" fn pow_rpow<T>(
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>(
lhs: *mut ffi::PyObject, lhs: *mut ffi::PyObject,
rhs: *mut ffi::PyObject, rhs: *mut ffi::PyObject,
modulo: *mut ffi::PyObject, modulo: *mut ffi::PyObject,
) -> *mut ffi::PyObject ) -> *mut ffi::PyObject
where where
T: for<'p> PyNumberPowProtocol<'p> + for<'p> PyNumberRPowProtocol<'p>, T: for<'p> PyNumberPowProtocol<'p> + for<'p> PyNumberRPowProtocol<'p>,
{ {
crate::callback_body!(py, { crate::callback_body!(py, {
let lhs = py.from_borrowed_ptr::<crate::PyAny>(lhs); let lhs = py.from_borrowed_ptr::<crate::PyAny>(lhs);
let rhs = py.from_borrowed_ptr::<crate::PyAny>(rhs); let rhs = py.from_borrowed_ptr::<crate::PyAny>(rhs);
@ -756,341 +637,104 @@ pub trait PyNumberSlots {
} }
} }
}) })
} }
TypedSlot(ffi::Py_nb_power, wrap_pow_and_rpow::<Self>) #[doc(hidden)]
} pub unsafe extern "C" fn pow<T>(
fn get_pow() -> TypedSlot<ffi::ternaryfunc>
where
Self: for<'p> PyNumberPowProtocol<'p>,
{
unsafe extern "C" fn wrap_pow<T>(
lhs: *mut ffi::PyObject, lhs: *mut ffi::PyObject,
rhs: *mut ffi::PyObject, rhs: *mut ffi::PyObject,
modulo: *mut ffi::PyObject, modulo: *mut ffi::PyObject,
) -> *mut ffi::PyObject ) -> *mut ffi::PyObject
where where
T: for<'p> PyNumberPowProtocol<'p>, T: for<'p> PyNumberPowProtocol<'p>,
{ {
crate::callback_body!(py, { crate::callback_body!(py, {
let lhs = extract_or_return_not_implemented!(py, lhs); let lhs = extract_or_return_not_implemented!(py, lhs);
let rhs = extract_or_return_not_implemented!(py, rhs); let rhs = extract_or_return_not_implemented!(py, rhs);
let modulo = extract_or_return_not_implemented!(py, modulo); let modulo = extract_or_return_not_implemented!(py, modulo);
T::__pow__(lhs, rhs, modulo).convert(py) T::__pow__(lhs, rhs, modulo).convert(py)
}) })
} }
TypedSlot(ffi::Py_nb_power, wrap_pow::<Self>) #[doc(hidden)]
} pub unsafe extern "C" fn rpow<T>(
fn get_rpow() -> TypedSlot<ffi::ternaryfunc>
where
Self: for<'p> PyNumberRPowProtocol<'p>,
{
unsafe extern "C" fn wrap_rpow<T>(
arg: *mut ffi::PyObject, arg: *mut ffi::PyObject,
slf: *mut ffi::PyObject, slf: *mut ffi::PyObject,
modulo: *mut ffi::PyObject, modulo: *mut ffi::PyObject,
) -> *mut ffi::PyObject ) -> *mut ffi::PyObject
where where
T: for<'p> PyNumberRPowProtocol<'p>, T: for<'p> PyNumberRPowProtocol<'p>,
{ {
crate::callback_body!(py, { crate::callback_body!(py, {
let slf: &crate::PyCell<T> = extract_or_return_not_implemented!(py, slf); let slf: &crate::PyCell<T> = extract_or_return_not_implemented!(py, slf);
let arg = extract_or_return_not_implemented!(py, arg); let arg = extract_or_return_not_implemented!(py, arg);
let modulo = extract_or_return_not_implemented!(py, modulo); let modulo = extract_or_return_not_implemented!(py, modulo);
slf.try_borrow()?.__rpow__(arg, modulo).convert(py) slf.try_borrow()?.__rpow__(arg, modulo).convert(py)
}) })
} }
TypedSlot(ffi::Py_nb_power, wrap_rpow::<Self>) py_unary_func!(neg, PyNumberNegProtocol, T::__neg__);
} py_unary_func!(pos, PyNumberPosProtocol, T::__pos__);
py_unary_func!(abs, PyNumberAbsProtocol, T::__abs__);
fn get_neg() -> TypedSlot<ffi::unaryfunc> py_unary_func!(invert, PyNumberInvertProtocol, T::__invert__);
where py_binary_fallback_num_func!(
Self: for<'p> PyNumberNegProtocol<'p>, lshift_rlshift,
{ T,
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_binary_fallback_num_func!(
Self,
PyNumberLShiftProtocol::__lshift__, PyNumberLShiftProtocol::__lshift__,
PyNumberRLShiftProtocol::__rlshift__ PyNumberRLShiftProtocol::__rlshift__
), );
) py_binary_num_func!(lshift, PyNumberLShiftProtocol, T::__lshift__);
} py_binary_reversed_num_func!(rlshift, PyNumberRLShiftProtocol, T::__rlshift__);
py_binary_fallback_num_func!(
fn get_lshift() -> TypedSlot<ffi::binaryfunc> rshift_rrshift,
where T,
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_fallback_num_func!(
Self,
PyNumberRShiftProtocol::__rshift__, PyNumberRShiftProtocol::__rshift__,
PyNumberRRShiftProtocol::__rrshift__ PyNumberRRShiftProtocol::__rrshift__
), );
) py_binary_num_func!(rshift, PyNumberRShiftProtocol, T::__rshift__);
} py_binary_reversed_num_func!(rrshift, PyNumberRRShiftProtocol, T::__rrshift__);
py_binary_fallback_num_func!(
fn get_rshift() -> TypedSlot<ffi::binaryfunc> and_rand,
where T,
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_fallback_num_func!(
Self,
PyNumberAndProtocol::__and__, PyNumberAndProtocol::__and__,
PyNumberRAndProtocol::__rand__ PyNumberRAndProtocol::__rand__
), );
) py_binary_num_func!(and, PyNumberAndProtocol, T::__and__);
} py_binary_reversed_num_func!(rand, PyNumberRAndProtocol, T::__rand__);
py_binary_fallback_num_func!(
fn get_and() -> TypedSlot<ffi::binaryfunc> xor_rxor,
where T,
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_fallback_num_func!(
Self,
PyNumberXorProtocol::__xor__, PyNumberXorProtocol::__xor__,
PyNumberRXorProtocol::__rxor__ PyNumberRXorProtocol::__rxor__
), );
) py_binary_num_func!(xor, PyNumberXorProtocol, T::__xor__);
} py_binary_reversed_num_func!(rxor, PyNumberRXorProtocol, T::__rxor__);
py_binary_fallback_num_func!(
fn get_xor() -> TypedSlot<ffi::binaryfunc> or_ror,
where T,
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_fallback_num_func!(
Self,
PyNumberOrProtocol::__or__, PyNumberOrProtocol::__or__,
PyNumberROrProtocol::__ror__ 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> #[doc(hidden)]
where pub unsafe extern "C" fn ipow<T>(
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>(
slf: *mut ffi::PyObject, slf: *mut ffi::PyObject,
other: *mut ffi::PyObject, other: *mut ffi::PyObject,
_modulo: *mut ffi::PyObject, _modulo: *mut ffi::PyObject,
) -> *mut ffi::PyObject ) -> *mut ffi::PyObject
where where
T: for<'p> PyNumberIPowProtocol<'p>, 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, { crate::callback_body!(py, {
let slf_cell = py.from_borrowed_ptr::<crate::PyCell<T>>(slf); let slf_cell = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
let other = py.from_borrowed_ptr::<crate::PyAny>(other); let other = py.from_borrowed_ptr::<crate::PyAny>(other);
@ -1098,202 +742,38 @@ pub trait PyNumberSlots {
ffi::Py_INCREF(slf); ffi::Py_INCREF(slf);
Ok::<_, PyErr>(slf) Ok::<_, PyErr>(slf)
}) })
}
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_fallback_num_func!(
Self,
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_fallback_num_func!(
Self,
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_fallback_num_func!(
Self,
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_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!(
floordiv_rfloordiv,
T,
PyNumberFloordivProtocol::__floordiv__,
PyNumberRFloordivProtocol::__rfloordiv__
);
py_binary_num_func!(floordiv, PyNumberFloordivProtocol, T::__floordiv__);
py_binary_reversed_num_func!(rfloordiv, PyNumberRFloordivProtocol, T::__rfloordiv__);
py_binary_fallback_num_func!(
truediv_rtruediv,
T,
PyNumberTruedivProtocol::__truediv__,
PyNumberRTruedivProtocol::__rtruediv__
);
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!(
matmul_rmatmul,
T,
PyNumberMatmulProtocol::__matmul__,
PyNumberRMatmulProtocol::__rmatmul__
);
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; use crate::ffi;
#[cfg(not(Py_LIMITED_API))] use std::marker::PhantomData;
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;
// Note(kngwyu): default implementations are for rust-numpy. Please don't remove them. // Note(kngwyu): default implementations are for rust-numpy. Please don't remove them.
pub trait PyProtoMethods { pub trait PyProtoMethods {
fn get_type_slots() -> Vec<ffi::PyType_Slot> { fn for_each_proto_slot<Visitor: FnMut(ffi::PyType_Slot)>(_visitor: Visitor) {}
vec![] fn get_buffer() -> Option<&'static PyBufferProcs> {
}
fn get_buffer() -> Option<PyBufferProcs> {
None None
} }
} }
/// Typed version of `ffi::PyType_Slot` pub struct PyClassProtocols<T>(PhantomData<T>);
#[doc(hidden)]
pub struct TypedSlot<T: Sized>(pub std::os::raw::c_int, pub T);
#[doc(hidden)] impl<T> PyClassProtocols<T> {
pub enum PyProtoMethodDef { pub fn new() -> Self {
Slots(Vec<ffi::PyType_Slot>), Self(PhantomData)
Buffer(PyBufferProcs),
}
impl From<Vec<ffi::PyType_Slot>> for PyProtoMethodDef {
fn from(slots: Vec<ffi::PyType_Slot>) -> Self {
PyProtoMethodDef::Slots(slots)
} }
} }
impl From<PyBufferProcs> for PyProtoMethodDef { impl<T> Default for PyClassProtocols<T> {
fn from(buffer_procs: PyBufferProcs) -> Self { fn default() -> Self {
PyProtoMethodDef::Buffer(buffer_procs) Self::new()
} }
} }
#[doc(hidden)] impl<T> Clone for PyClassProtocols<T> {
#[cfg(feature = "macros")] fn clone(&self) -> Self {
pub trait PyProtoInventory: inventory::Collect { Self::new()
fn new(methods: PyProtoMethodDef) -> Self; }
fn get(&'static self) -> &'static PyProtoMethodDef; }
}
impl<T> Copy for PyClassProtocols<T> {}
#[doc(hidden)]
#[cfg(feature = "macros")] // All traits describing slots, as well as the fallback implementations for unimplemented protos
pub trait HasProtoInventory { //
type ProtoMethods: PyProtoInventory; // 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
#[cfg(feature = "macros")]
impl<T: HasProtoInventory> PyProtoMethods for T { pub trait PyObjectProtocolSlots<T> {
fn get_type_slots() -> Vec<ffi::PyType_Slot> { fn object_protocol_slots(self) -> &'static [ffi::PyType_Slot];
inventory::iter::<T::ProtoMethods> }
.into_iter()
.filter_map(|def| match def.get() { impl<T> PyObjectProtocolSlots<T> for &'_ PyClassProtocols<T> {
PyProtoMethodDef::Slots(slots) => Some(slots), fn object_protocol_slots(self) -> &'static [ffi::PyType_Slot] {
PyProtoMethodDef::Buffer(_) => None, &[]
}) }
.flatten() }
.cloned()
.collect() pub trait PyDescrProtocolSlots<T> {
} fn descr_protocol_slots(self) -> &'static [ffi::PyType_Slot];
}
fn get_buffer() -> Option<PyBufferProcs> {
inventory::iter::<T::ProtoMethods> impl<T> PyDescrProtocolSlots<T> for &'_ PyClassProtocols<T> {
.into_iter() fn descr_protocol_slots(self) -> &'static [ffi::PyType_Slot] {
.find_map(|def| match def.get() { &[]
PyProtoMethodDef::Slots(_) => None, }
PyProtoMethodDef::Buffer(buf) => Some(buf.clone()), }
})
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/) //! [PEP-0492](https://www.python.org/dev/peps/pep-0492/)
//! //!
use super::proto_methods::TypedSlot;
use crate::callback::IntoPyCallbackOutput; use crate::callback::IntoPyCallbackOutput;
use crate::derive_utils::TryFromPyCell; use crate::derive_utils::TryFromPyCell;
use crate::err::PyResult; use crate::err::PyResult;
@ -86,41 +85,9 @@ pub trait PyAsyncAexitProtocol<'p>: PyAsyncProtocol<'p> {
type Result: IntoPyCallbackOutput<PyObject>; type Result: IntoPyCallbackOutput<PyObject>;
} }
/// Extension trait for proc-macro backend. py_unarys_func!(await_, PyAsyncAwaitProtocol, Self::__await__);
#[doc(hidden)] py_unarys_func!(aiter, PyAsyncAiterProtocol, Self::__aiter__);
pub trait PyAsyncSlots { py_unarys_func!(anext, PyAsyncAnextProtocol, Self::__anext__);
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> {}
/// Output of `__anext__`. /// Output of `__anext__`.
pub enum IterANextOutput<T, U> { pub enum IterANextOutput<T, U> {

View File

@ -3,7 +3,6 @@
//! Python Sequence Interface //! Python Sequence Interface
//! Trait and support implementation for implementing sequence //! Trait and support implementation for implementing sequence
use super::proto_methods::TypedSlot;
use crate::callback::IntoPyCallbackOutput; use crate::callback::IntoPyCallbackOutput;
use crate::conversion::{FromPyObject, IntoPy}; use crate::conversion::{FromPyObject, IntoPy};
use crate::err::PyErr; use crate::err::PyErr;
@ -129,61 +128,20 @@ pub trait PySequenceInplaceRepeatProtocol<'p>:
type Result: IntoPyCallbackOutput<Self>; 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)] #[doc(hidden)]
pub trait PySequenceSlots { pub unsafe extern "C" fn setitem<T>(
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>(
slf: *mut ffi::PyObject, slf: *mut ffi::PyObject,
key: ffi::Py_ssize_t, key: ffi::Py_ssize_t,
value: *mut ffi::PyObject, value: *mut ffi::PyObject,
) -> c_int ) -> c_int
where where
T: for<'p> PySequenceSetItemProtocol<'p>, T: for<'p> PySequenceSetItemProtocol<'p>,
{ {
crate::callback_body!(py, { crate::callback_body!(py, {
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf); let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
@ -199,23 +157,17 @@ pub trait PySequenceSlots {
let value = value.extract()?; let value = value.extract()?;
crate::callback::convert(py, slf.__setitem__(key.into(), value)) crate::callback::convert(py, slf.__setitem__(key.into(), value))
}) })
} }
TypedSlot(ffi::Py_sq_ass_item, wrap::<Self>) #[doc(hidden)]
} pub unsafe extern "C" fn delitem<T>(
fn get_delitem() -> TypedSlot<ffi::ssizeobjargproc>
where
Self: for<'p> PySequenceDelItemProtocol<'p>,
{
unsafe extern "C" fn wrap<T>(
slf: *mut ffi::PyObject, slf: *mut ffi::PyObject,
key: ffi::Py_ssize_t, key: ffi::Py_ssize_t,
value: *mut ffi::PyObject, value: *mut ffi::PyObject,
) -> c_int ) -> c_int
where where
T: for<'p> PySequenceDelItemProtocol<'p>, T: for<'p> PySequenceDelItemProtocol<'p>,
{ {
crate::callback_body!(py, { crate::callback_body!(py, {
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf); let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
@ -228,23 +180,17 @@ pub trait PySequenceSlots {
))) )))
} }
}) })
} }
TypedSlot(ffi::Py_sq_ass_item, wrap::<Self>) #[doc(hidden)]
} pub unsafe extern "C" fn setdelitem<T>(
fn get_setdelitem() -> TypedSlot<ffi::ssizeobjargproc>
where
Self: for<'p> PySequenceDelItemProtocol<'p> + for<'p> PySequenceSetItemProtocol<'p>,
{
unsafe extern "C" fn wrap<T>(
slf: *mut ffi::PyObject, slf: *mut ffi::PyObject,
key: ffi::Py_ssize_t, key: ffi::Py_ssize_t,
value: *mut ffi::PyObject, value: *mut ffi::PyObject,
) -> c_int ) -> c_int
where where
T: for<'p> PySequenceSetItemProtocol<'p> + for<'p> PySequenceDelItemProtocol<'p>, T: for<'p> PySequenceSetItemProtocol<'p> + for<'p> PySequenceDelItemProtocol<'p>,
{ {
crate::callback_body!(py, { crate::callback_body!(py, {
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf); let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
@ -257,49 +203,24 @@ pub trait PySequenceSlots {
slf_.__setitem__(key.into(), value).convert(py) slf_.__setitem__(key.into(), value).convert(py)
} }
}) })
} }
TypedSlot(ffi::Py_sq_ass_item, wrap::<Self>) py_binary_func!(
} contains,
PySequenceContainsProtocol,
fn get_contains() -> TypedSlot<ffi::objobjproc> Self::__contains__,
where c_int
Self: for<'p> PySequenceContainsProtocol<'p>, );
{ py_binary_func!(
TypedSlot( inplace_concat,
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!(
PySequenceInplaceConcatProtocol, PySequenceInplaceConcatProtocol,
Self::__inplace_concat__, Self::__inplace_concat__,
*mut ffi::PyObject, *mut ffi::PyObject,
call_mut call_mut
), );
) py_ssizearg_func!(
} inplace_repeat,
fn get_inplace_repeat() -> TypedSlot<ffi::ssizeargfunc>
where
Self: for<'p> PySequenceInplaceRepeatProtocol<'p>,
{
TypedSlot(
ffi::Py_sq_inplace_repeat,
py_ssizearg_func!(
PySequenceInplaceRepeatProtocol, PySequenceInplaceRepeatProtocol,
Self::__inplace_repeat__, Self::__inplace_repeat__,
call_mut call_mut
), );
)
}
}
impl<'p, T> PySequenceSlots for T where T: PySequenceProtocol<'p> {}

View File

@ -1,5 +1,9 @@
use std::os::raw::c_int; 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_ass_subscript: c_int = 3;
pub const Py_mp_length: c_int = 4; pub const Py_mp_length: c_int = 4;
pub const Py_mp_subscript: c_int = 5; pub const Py_mp_subscript: c_int = 5;

View File

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

View File

@ -191,11 +191,11 @@ where
// protocol methods // protocol methods
let mut has_gc_methods = false; 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_clear;
has_gc_methods |= slot.slot == ffi::Py_tp_traverse; has_gc_methods |= slot.slot == ffi::Py_tp_traverse;
slots.0.push(slot); slots.0.push(slot);
} });
slots.push(0, ptr::null_mut()); slots.push(0, ptr::null_mut());
let mut spec = ffi::PyType_Spec { 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() { if let Some(buffer) = T::get_buffer() {
unsafe { unsafe {
(*(*type_object).tp_as_buffer).bf_getbuffer = buffer.bf_getbuffer; (*(*type_object).tp_as_buffer).bf_getbuffer = buffer.bf_getbuffer;