Remove specialization from basic/buffer/descr/iter protocols
This commit is contained in:
parent
7a7271319c
commit
7967874177
|
@ -19,6 +19,7 @@ travis-ci = { repository = "PyO3/pyo3", branch = "master" }
|
|||
appveyor = { repository = "fafhrd91/pyo3" }
|
||||
|
||||
[dependencies]
|
||||
ctor = { version = "0.1", optional = true }
|
||||
indoc = { version = "0.3.4", optional = true }
|
||||
inventory = { version = "0.1.4", optional = true }
|
||||
libc = "0.2.62"
|
||||
|
@ -38,7 +39,7 @@ version_check = "0.9.1"
|
|||
|
||||
[features]
|
||||
default = ["macros"]
|
||||
macros = ["indoc", "inventory", "paste", "pyo3cls", "unindent"]
|
||||
macros = ["ctor", "indoc", "inventory", "paste", "pyo3cls", "unindent"]
|
||||
|
||||
# this is no longer needed internally, but setuptools-rust assumes this feature
|
||||
python3 = []
|
||||
|
|
|
@ -3,8 +3,11 @@ use crate::func::MethodProto;
|
|||
|
||||
pub struct Proto {
|
||||
pub name: &'static str,
|
||||
pub slot_table: &'static str,
|
||||
pub set_slot_table: &'static str,
|
||||
pub methods: &'static [MethodProto],
|
||||
pub py_methods: &'static [PyMethod],
|
||||
pub slot_setters: &'static [SlotSetter],
|
||||
}
|
||||
|
||||
impl Proto {
|
||||
|
@ -47,8 +50,27 @@ impl PyMethod {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct SlotSetter {
|
||||
pub proto_names: &'static [&'static str],
|
||||
pub set_function: &'static str,
|
||||
pub exclude_indices: &'static [usize],
|
||||
}
|
||||
|
||||
impl SlotSetter {
|
||||
const EMPTY_INDICES: &'static [usize] = &[];
|
||||
const fn new(names: &'static [&'static str], set_function: &'static str) -> Self {
|
||||
SlotSetter {
|
||||
proto_names: names,
|
||||
set_function,
|
||||
exclude_indices: Self::EMPTY_INDICES,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const OBJECT: Proto = Proto {
|
||||
name: "Object",
|
||||
slot_table: "pyo3::class::basic::PyObjectMethods",
|
||||
set_slot_table: "set_basic_methods",
|
||||
methods: &[
|
||||
MethodProto::Binary {
|
||||
name: "__getattr__",
|
||||
|
@ -95,11 +117,6 @@ pub const OBJECT: Proto = Proto {
|
|||
pyres: true,
|
||||
proto: "pyo3::class::basic::PyObjectBytesProtocol",
|
||||
},
|
||||
MethodProto::Unary {
|
||||
name: "__bool__",
|
||||
pyres: false,
|
||||
proto: "pyo3::class::basic::PyObjectBoolProtocol",
|
||||
},
|
||||
MethodProto::Binary {
|
||||
name: "__richcmp__",
|
||||
arg: "Other",
|
||||
|
@ -112,10 +129,27 @@ pub const OBJECT: Proto = Proto {
|
|||
PyMethod::new("__bytes__", "pyo3::class::basic::BytesProtocolImpl"),
|
||||
PyMethod::new("__unicode__", "pyo3::class::basic::UnicodeProtocolImpl"),
|
||||
],
|
||||
slot_setters: &[
|
||||
SlotSetter::new(&["__str__"], "set_str"),
|
||||
SlotSetter::new(&["__repr__"], "set_repr"),
|
||||
SlotSetter::new(&["__hash__"], "set_hash"),
|
||||
SlotSetter::new(&["__getattr__"], "set_getattr"),
|
||||
SlotSetter::new(&["__richcmp__"], "set_richcompare"),
|
||||
SlotSetter {
|
||||
proto_names: &["__setattr__", "__delattr__"],
|
||||
set_function: "set_setdelattr",
|
||||
// exclude set and del
|
||||
exclude_indices: &[6, 7],
|
||||
},
|
||||
SlotSetter::new(&["__setattr__"], "set_setattr"),
|
||||
SlotSetter::new(&["__delattr__"], "set_setattr"),
|
||||
],
|
||||
};
|
||||
|
||||
pub const ASYNC: Proto = Proto {
|
||||
name: "Async",
|
||||
slot_table: "",
|
||||
set_slot_table: "",
|
||||
methods: &[
|
||||
MethodProto::Unary {
|
||||
name: "__await__",
|
||||
|
@ -155,10 +189,13 @@ pub const ASYNC: Proto = Proto {
|
|||
"pyo3::class::pyasync::PyAsyncAexitProtocolImpl",
|
||||
),
|
||||
],
|
||||
slot_setters: &[],
|
||||
};
|
||||
|
||||
pub const BUFFER: Proto = Proto {
|
||||
name: "Buffer",
|
||||
slot_table: "pyo3::ffi::PyBufferProcs",
|
||||
set_slot_table: "set_buffer_methods",
|
||||
methods: &[
|
||||
MethodProto::Unary {
|
||||
name: "bf_getbuffer",
|
||||
|
@ -172,10 +209,16 @@ pub const BUFFER: Proto = Proto {
|
|||
},
|
||||
],
|
||||
py_methods: &[],
|
||||
slot_setters: &[
|
||||
SlotSetter::new(&["bf_getbuffer"], "set_getbuffer"),
|
||||
SlotSetter::new(&["bf_releasebuffer"], "set_releasebuffer"),
|
||||
],
|
||||
};
|
||||
|
||||
pub const CONTEXT: Proto = Proto {
|
||||
name: "Context",
|
||||
slot_table: "",
|
||||
set_slot_table: "",
|
||||
methods: &[
|
||||
MethodProto::Unary {
|
||||
name: "__enter__",
|
||||
|
@ -200,10 +243,13 @@ pub const CONTEXT: Proto = Proto {
|
|||
"pyo3::class::context::PyContextExitProtocolImpl",
|
||||
),
|
||||
],
|
||||
slot_setters: &[],
|
||||
};
|
||||
|
||||
pub const GC: Proto = Proto {
|
||||
name: "GC",
|
||||
slot_table: "",
|
||||
set_slot_table: "",
|
||||
methods: &[
|
||||
MethodProto::Free {
|
||||
name: "__traverse__",
|
||||
|
@ -215,10 +261,13 @@ pub const GC: Proto = Proto {
|
|||
},
|
||||
],
|
||||
py_methods: &[],
|
||||
slot_setters: &[],
|
||||
};
|
||||
|
||||
pub const DESCR: Proto = Proto {
|
||||
name: "Descriptor",
|
||||
slot_table: "pyo3::class::descr::PyDescrMethods",
|
||||
set_slot_table: "set_descr_methods",
|
||||
methods: &[
|
||||
MethodProto::Ternary {
|
||||
name: "__get__",
|
||||
|
@ -254,10 +303,16 @@ pub const DESCR: Proto = Proto {
|
|||
"pyo3::class::context::PyDescrNameProtocolImpl",
|
||||
),
|
||||
],
|
||||
slot_setters: &[
|
||||
SlotSetter::new(&["__get__"], "set_descr_get"),
|
||||
SlotSetter::new(&["__set__"], "set_descr_set"),
|
||||
],
|
||||
};
|
||||
|
||||
pub const ITER: Proto = Proto {
|
||||
name: "Iter",
|
||||
slot_table: "pyo3::class::iter::PyIterMethods",
|
||||
set_slot_table: "set_iter_methods",
|
||||
py_methods: &[],
|
||||
methods: &[
|
||||
MethodProto::UnaryS {
|
||||
|
@ -273,10 +328,24 @@ pub const ITER: Proto = Proto {
|
|||
proto: "pyo3::class::iter::PyIterNextProtocol",
|
||||
},
|
||||
],
|
||||
slot_setters: &[
|
||||
SlotSetter {
|
||||
proto_names: &["__iter__"],
|
||||
set_function: "set_iter",
|
||||
exclude_indices: &[],
|
||||
},
|
||||
SlotSetter {
|
||||
proto_names: &["__next__"],
|
||||
set_function: "set_iternext",
|
||||
exclude_indices: &[],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
pub const MAPPING: Proto = Proto {
|
||||
name: "Mapping",
|
||||
slot_table: "",
|
||||
set_slot_table: "",
|
||||
methods: &[
|
||||
MethodProto::Unary {
|
||||
name: "__len__",
|
||||
|
@ -312,10 +381,13 @@ pub const MAPPING: Proto = Proto {
|
|||
"__reversed__",
|
||||
"pyo3::class::mapping::PyMappingReversedProtocolImpl",
|
||||
)],
|
||||
slot_setters: &[],
|
||||
};
|
||||
|
||||
pub const SEQ: Proto = Proto {
|
||||
name: "Sequence",
|
||||
slot_table: "",
|
||||
set_slot_table: "",
|
||||
methods: &[
|
||||
MethodProto::Unary {
|
||||
name: "__len__",
|
||||
|
@ -373,10 +445,13 @@ pub const SEQ: Proto = Proto {
|
|||
},
|
||||
],
|
||||
py_methods: &[],
|
||||
slot_setters: &[],
|
||||
};
|
||||
|
||||
pub const NUM: Proto = Proto {
|
||||
name: "Number",
|
||||
slot_table: "",
|
||||
set_slot_table: "",
|
||||
methods: &[
|
||||
MethodProto::BinaryS {
|
||||
name: "__add__",
|
||||
|
@ -686,6 +761,11 @@ pub const NUM: Proto = Proto {
|
|||
pyres: true,
|
||||
proto: "pyo3::class::number::PyNumberRoundProtocol",
|
||||
},
|
||||
MethodProto::Unary {
|
||||
name: "__bool__",
|
||||
pyres: false,
|
||||
proto: "pyo3::class::number::PyNumberBoolProtocol",
|
||||
},
|
||||
],
|
||||
py_methods: &[
|
||||
PyMethod::coexist("__radd__", "pyo3::class::number::PyNumberRAddProtocolImpl"),
|
||||
|
@ -729,4 +809,5 @@ pub const NUM: Proto = Proto {
|
|||
"pyo3::class::number::PyNumberRoundProtocolImpl",
|
||||
),
|
||||
],
|
||||
slot_setters: &[],
|
||||
};
|
||||
|
|
|
@ -236,6 +236,19 @@ fn impl_methods_inventory(cls: &syn::Ident) -> TokenStream {
|
|||
}
|
||||
}
|
||||
|
||||
/// TODO(kngwyu): doc
|
||||
fn impl_proto_registory(cls: &syn::Ident) -> TokenStream {
|
||||
quote! {
|
||||
impl pyo3::class::proto_methods::HasPyProtoRegistry for #cls {
|
||||
fn registory() -> &'static pyo3::class::proto_methods::PyProtoRegistry {
|
||||
static REGISTRY: pyo3::class::proto_methods::PyProtoRegistry
|
||||
= pyo3::class::proto_methods::PyProtoRegistry::new();
|
||||
®ISTRY
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_class_python_name(cls: &syn::Ident, attr: &PyClassArgs) -> TokenStream {
|
||||
match &attr.name {
|
||||
Some(name) => quote! { #name },
|
||||
|
@ -340,6 +353,7 @@ fn impl_class(
|
|||
};
|
||||
|
||||
let impl_inventory = impl_methods_inventory(&cls);
|
||||
let impl_proto_registory = impl_proto_registory(&cls);
|
||||
|
||||
let base = &attr.base;
|
||||
let flags = &attr.flags;
|
||||
|
@ -414,6 +428,8 @@ fn impl_class(
|
|||
|
||||
#impl_inventory
|
||||
|
||||
#impl_proto_registory
|
||||
|
||||
#extra
|
||||
|
||||
#gc_impl
|
||||
|
|
|
@ -4,9 +4,10 @@ use crate::defs;
|
|||
use crate::func::impl_method_proto;
|
||||
use crate::method::FnSpec;
|
||||
use crate::pymethod;
|
||||
use proc_macro2::TokenStream;
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::quote;
|
||||
use quote::ToTokens;
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub fn build_py_proto(ast: &mut syn::ItemImpl) -> syn::Result<TokenStream> {
|
||||
if let Some((_, ref mut path, _)) = ast.trait_ {
|
||||
|
@ -60,12 +61,17 @@ fn impl_proto_impl(
|
|||
) -> syn::Result<TokenStream> {
|
||||
let mut trait_impls = TokenStream::new();
|
||||
let mut py_methods = Vec::new();
|
||||
let mut method_names = HashSet::new();
|
||||
|
||||
for iimpl in impls.iter_mut() {
|
||||
if let syn::ImplItem::Method(ref mut met) = iimpl {
|
||||
// impl Py~Protocol<'p> { type = ... }
|
||||
if let Some(m) = proto.get_proto(&met.sig.ident) {
|
||||
impl_method_proto(ty, &mut met.sig, m).to_tokens(&mut trait_impls);
|
||||
// Insert the method to the HashSet
|
||||
method_names.insert(met.sig.ident.to_string());
|
||||
}
|
||||
// Add non-slot methods to inventory slots
|
||||
if let Some(m) = proto.get_method(&met.sig.ident) {
|
||||
let name = &met.sig.ident;
|
||||
let fn_spec = FnSpec::parse(&met.sig, &mut met.attrs, false)?;
|
||||
|
@ -76,7 +82,7 @@ fn impl_proto_impl(
|
|||
} else {
|
||||
quote!(0)
|
||||
};
|
||||
// TODO(kngwyu): doc
|
||||
// TODO(kngwyu): ml_doc
|
||||
py_methods.push(quote! {
|
||||
pyo3::class::PyMethodDefType::Method({
|
||||
#method
|
||||
|
@ -91,20 +97,77 @@ fn impl_proto_impl(
|
|||
}
|
||||
}
|
||||
}
|
||||
let inventory_submission = inventory_submission(py_methods, ty);
|
||||
let slot_initialization = slot_initialization(method_names, ty, proto)?;
|
||||
Ok(quote! {
|
||||
#trait_impls
|
||||
#inventory_submission
|
||||
#slot_initialization
|
||||
})
|
||||
}
|
||||
|
||||
fn inventory_submission(py_methods: Vec<TokenStream>, ty: &syn::Type) -> TokenStream {
|
||||
if py_methods.is_empty() {
|
||||
return Ok(quote! { #trait_impls });
|
||||
return quote! {};
|
||||
}
|
||||
let inventory_submission = quote! {
|
||||
quote! {
|
||||
pyo3::inventory::submit! {
|
||||
#![crate = pyo3] {
|
||||
type Inventory = <#ty as pyo3::class::methods::HasMethodsInventory>::Methods;
|
||||
<Inventory as pyo3::class::methods::PyMethodsInventory>::new(&[#(#py_methods),*])
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn slot_initialization(
|
||||
method_names: HashSet<String>,
|
||||
ty: &syn::Type,
|
||||
proto: &defs::Proto,
|
||||
) -> syn::Result<TokenStream> {
|
||||
let mut initializers: Vec<TokenStream> = vec![];
|
||||
// This is for setters.
|
||||
// If we can use set_setdelattr, skip set_setattr and set_setdelattr.
|
||||
let mut skip_indices = vec![];
|
||||
'setter_loop: for (i, m) in proto.slot_setters.iter().enumerate() {
|
||||
if skip_indices.contains(&i) {
|
||||
continue;
|
||||
}
|
||||
for name in m.proto_names {
|
||||
if !method_names.contains(*name) {
|
||||
// This `#[pyproto] impl` doesn't have all required methods,
|
||||
// let's skip implementation.
|
||||
continue 'setter_loop;
|
||||
}
|
||||
}
|
||||
skip_indices.extend_from_slice(m.exclude_indices);
|
||||
// Add slot methods to PyProtoRegistry
|
||||
let set = syn::Ident::new(m.set_function, Span::call_site());
|
||||
initializers.push(quote! { table.#set::<#ty>(); });
|
||||
}
|
||||
if initializers.is_empty() {
|
||||
return Ok(quote! {});
|
||||
}
|
||||
let table: syn::Path = syn::parse_str(proto.slot_table)?;
|
||||
let set = syn::Ident::new(proto.set_slot_table, Span::call_site());
|
||||
let ty_hash = typename_hash(ty);
|
||||
let init = syn::Ident::new(
|
||||
&format!("__init_{}_{}", proto.name, ty_hash),
|
||||
Span::call_site(),
|
||||
);
|
||||
Ok(quote! {
|
||||
#trait_impls
|
||||
#inventory_submission
|
||||
#[pyo3::ctor::ctor]
|
||||
fn #init() {
|
||||
let mut table = #table::default();
|
||||
#(#initializers)*
|
||||
<#ty as pyo3::class::proto_methods::HasPyProtoRegistry>::registory().#set(table);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn typename_hash(ty: &syn::Type) -> u64 {
|
||||
use std::hash::{Hash, Hasher};
|
||||
let mut hasher = std::collections::hash_map::DefaultHasher::new();
|
||||
ty.hash(&mut hasher);
|
||||
hasher.finish()
|
||||
}
|
||||
|
|
|
@ -77,13 +77,6 @@ pub trait PyObjectProtocol<'p>: PyClass {
|
|||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __bool__(&'p self) -> Self::Result
|
||||
where
|
||||
Self: PyObjectBoolProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __bytes__(&'p self) -> Self::Result
|
||||
where
|
||||
Self: PyObjectBytesProtocol<'p>,
|
||||
|
@ -142,55 +135,54 @@ pub trait PyObjectRichcmpProtocol<'p>: PyObjectProtocol<'p> {
|
|||
type Result: Into<PyResult<Self::Success>>;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait PyObjectProtocolImpl {
|
||||
fn tp_as_object(_type_object: &mut ffi::PyTypeObject);
|
||||
fn nb_bool_fn() -> Option<ffi::inquiry>;
|
||||
/// All functions necessary for basic protocols.
|
||||
#[derive(Default)]
|
||||
pub struct PyObjectMethods {
|
||||
pub tp_str: Option<ffi::reprfunc>,
|
||||
pub tp_repr: Option<ffi::reprfunc>,
|
||||
pub tp_hash: Option<ffi::hashfunc>,
|
||||
pub tp_getattro: Option<ffi::getattrofunc>,
|
||||
pub tp_richcompare: Option<ffi::richcmpfunc>,
|
||||
pub tp_setattro: Option<ffi::setattrofunc>,
|
||||
}
|
||||
|
||||
impl<T> PyObjectProtocolImpl for T {
|
||||
default fn tp_as_object(_type_object: &mut ffi::PyTypeObject) {}
|
||||
default fn nb_bool_fn() -> Option<ffi::inquiry> {
|
||||
None
|
||||
impl PyObjectMethods {
|
||||
pub(crate) fn prepare_type_obj(&self, type_object: &mut ffi::PyTypeObject) {
|
||||
type_object.tp_str = self.tp_str;
|
||||
type_object.tp_repr = self.tp_repr;
|
||||
type_object.tp_hash = self.tp_hash;
|
||||
type_object.tp_getattro = self.tp_getattro;
|
||||
type_object.tp_richcompare = self.tp_richcompare;
|
||||
type_object.tp_setattro = self.tp_setattro;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, T> PyObjectProtocolImpl for T
|
||||
where
|
||||
T: PyObjectProtocol<'p>,
|
||||
{
|
||||
fn tp_as_object(type_object: &mut ffi::PyTypeObject) {
|
||||
type_object.tp_str = Self::tp_str();
|
||||
type_object.tp_repr = Self::tp_repr();
|
||||
type_object.tp_hash = Self::tp_hash();
|
||||
type_object.tp_getattro = Self::tp_getattro();
|
||||
type_object.tp_richcompare = Self::tp_richcompare();
|
||||
type_object.tp_setattro = tp_setattro_impl::tp_setattro::<Self>();
|
||||
pub fn set_str<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectStrProtocol<'p>,
|
||||
{
|
||||
self.tp_str = py_unary_func!(PyObjectStrProtocol, T::__str__);
|
||||
}
|
||||
fn nb_bool_fn() -> Option<ffi::inquiry> {
|
||||
Self::nb_bool()
|
||||
pub fn set_repr<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectReprProtocol<'p>,
|
||||
{
|
||||
self.tp_repr = py_unary_func!(PyObjectReprProtocol, T::__repr__);
|
||||
}
|
||||
}
|
||||
|
||||
trait GetAttrProtocolImpl {
|
||||
fn tp_getattro() -> Option<ffi::binaryfunc>;
|
||||
}
|
||||
|
||||
impl<'p, T> GetAttrProtocolImpl for T
|
||||
where
|
||||
T: PyObjectProtocol<'p>,
|
||||
{
|
||||
default fn tp_getattro() -> Option<ffi::binaryfunc> {
|
||||
None
|
||||
pub fn set_hash<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectHashProtocol<'p>,
|
||||
{
|
||||
self.tp_hash = py_unary_func!(
|
||||
PyObjectHashProtocol,
|
||||
T::__hash__,
|
||||
ffi::Py_hash_t,
|
||||
HashCallbackOutput
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> GetAttrProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PyObjectGetAttrProtocol<'p>,
|
||||
{
|
||||
fn tp_getattro() -> Option<ffi::binaryfunc> {
|
||||
#[allow(unused_mut)]
|
||||
pub fn set_getattr<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectGetAttrProtocol<'p>,
|
||||
{
|
||||
unsafe extern "C" fn wrap<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
arg: *mut ffi::PyObject,
|
||||
|
@ -214,207 +206,12 @@ where
|
|||
call_ref!(slf, __getattr__, arg)
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
self.tp_getattro = Some(wrap::<T>);
|
||||
}
|
||||
}
|
||||
|
||||
/// An object may support setting attributes (by implementing PyObjectSetAttrProtocol)
|
||||
/// and may support deleting attributes (by implementing PyObjectDelAttrProtocol).
|
||||
/// We need to generate a single "extern C" function that supports only setting, only deleting
|
||||
/// or both, and return None in case none of the two is supported.
|
||||
mod tp_setattro_impl {
|
||||
use super::*;
|
||||
|
||||
/// setattrofunc PyTypeObject.tp_setattro
|
||||
///
|
||||
/// An optional pointer to the function for setting and deleting attributes.
|
||||
///
|
||||
/// The signature is the same as for PyObject_SetAttr(), but setting v to NULL to delete an
|
||||
/// attribute must be supported. It is usually convenient to set this field to
|
||||
/// PyObject_GenericSetAttr(), which implements the normal way of setting object attributes.
|
||||
pub(super) fn tp_setattro<'p, T: PyObjectProtocol<'p>>() -> Option<ffi::setattrofunc> {
|
||||
if let Some(set_del) = T::set_del_attr() {
|
||||
Some(set_del)
|
||||
} else if let Some(set) = T::set_attr() {
|
||||
Some(set)
|
||||
} else if let Some(del) = T::del_attr() {
|
||||
Some(del)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
trait SetAttr {
|
||||
fn set_attr() -> Option<ffi::setattrofunc>;
|
||||
}
|
||||
|
||||
impl<'p, T: PyObjectProtocol<'p>> SetAttr for T {
|
||||
default fn set_attr() -> Option<ffi::setattrofunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SetAttr for T
|
||||
pub fn set_richcompare<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectSetAttrProtocol<'p>,
|
||||
T: for<'p> PyObjectRichcmpProtocol<'p>,
|
||||
{
|
||||
fn set_attr() -> Option<ffi::setattrofunc> {
|
||||
py_func_set!(PyObjectSetAttrProtocol, T, __setattr__)
|
||||
}
|
||||
}
|
||||
|
||||
trait DelAttr {
|
||||
fn del_attr() -> Option<ffi::setattrofunc>;
|
||||
}
|
||||
|
||||
impl<'p, T> DelAttr for T
|
||||
where
|
||||
T: PyObjectProtocol<'p>,
|
||||
{
|
||||
default fn del_attr() -> Option<ffi::setattrofunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DelAttr for T
|
||||
where
|
||||
T: for<'p> PyObjectDelAttrProtocol<'p>,
|
||||
{
|
||||
fn del_attr() -> Option<ffi::setattrofunc> {
|
||||
py_func_del!(PyObjectDelAttrProtocol, T, __delattr__)
|
||||
}
|
||||
}
|
||||
|
||||
trait SetDelAttr {
|
||||
fn set_del_attr() -> Option<ffi::setattrofunc>;
|
||||
}
|
||||
|
||||
impl<'p, T> SetDelAttr for T
|
||||
where
|
||||
T: PyObjectProtocol<'p>,
|
||||
{
|
||||
default fn set_del_attr() -> Option<ffi::setattrofunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SetDelAttr for T
|
||||
where
|
||||
T: for<'p> PyObjectSetAttrProtocol<'p> + for<'p> PyObjectDelAttrProtocol<'p>,
|
||||
{
|
||||
fn set_del_attr() -> Option<ffi::setattrofunc> {
|
||||
py_func_set_del!(
|
||||
PyObjectSetAttrProtocol,
|
||||
PyObjectDelAttrProtocol,
|
||||
T,
|
||||
__setattr__,
|
||||
__delattr__
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait StrProtocolImpl {
|
||||
fn tp_str() -> Option<ffi::unaryfunc>;
|
||||
}
|
||||
impl<'p, T> StrProtocolImpl for T
|
||||
where
|
||||
T: PyObjectProtocol<'p>,
|
||||
{
|
||||
default fn tp_str() -> Option<ffi::unaryfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
impl<T> StrProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PyObjectStrProtocol<'p>,
|
||||
{
|
||||
fn tp_str() -> Option<ffi::unaryfunc> {
|
||||
py_unary_func!(PyObjectStrProtocol, T::__str__)
|
||||
}
|
||||
}
|
||||
|
||||
trait ReprProtocolImpl {
|
||||
fn tp_repr() -> Option<ffi::unaryfunc>;
|
||||
}
|
||||
impl<'p, T> ReprProtocolImpl for T
|
||||
where
|
||||
T: PyObjectProtocol<'p>,
|
||||
{
|
||||
default fn tp_repr() -> Option<ffi::unaryfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
impl<T> ReprProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PyObjectReprProtocol<'p>,
|
||||
{
|
||||
fn tp_repr() -> Option<ffi::unaryfunc> {
|
||||
py_unary_func!(PyObjectReprProtocol, T::__repr__)
|
||||
}
|
||||
}
|
||||
|
||||
trait HashProtocolImpl {
|
||||
fn tp_hash() -> Option<ffi::hashfunc>;
|
||||
}
|
||||
impl<'p, T> HashProtocolImpl for T
|
||||
where
|
||||
T: PyObjectProtocol<'p>,
|
||||
{
|
||||
default fn tp_hash() -> Option<ffi::hashfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
impl<T> HashProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PyObjectHashProtocol<'p>,
|
||||
{
|
||||
fn tp_hash() -> Option<ffi::hashfunc> {
|
||||
py_unary_func!(
|
||||
PyObjectHashProtocol,
|
||||
T::__hash__,
|
||||
ffi::Py_hash_t,
|
||||
HashCallbackOutput
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
trait BoolProtocolImpl {
|
||||
fn nb_bool() -> Option<ffi::inquiry>;
|
||||
}
|
||||
impl<'p, T> BoolProtocolImpl for T
|
||||
where
|
||||
T: PyObjectProtocol<'p>,
|
||||
{
|
||||
default fn nb_bool() -> Option<ffi::inquiry> {
|
||||
None
|
||||
}
|
||||
}
|
||||
impl<T> BoolProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PyObjectBoolProtocol<'p>,
|
||||
{
|
||||
fn nb_bool() -> Option<ffi::inquiry> {
|
||||
py_unary_func!(PyObjectBoolProtocol, T::__bool__, c_int)
|
||||
}
|
||||
}
|
||||
|
||||
trait RichcmpProtocolImpl {
|
||||
fn tp_richcompare() -> Option<ffi::richcmpfunc>;
|
||||
}
|
||||
impl<'p, T> RichcmpProtocolImpl for T
|
||||
where
|
||||
T: PyObjectProtocol<'p>,
|
||||
{
|
||||
default fn tp_richcompare() -> Option<ffi::richcmpfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
impl<T> RichcmpProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PyObjectRichcmpProtocol<'p>,
|
||||
{
|
||||
fn tp_richcompare() -> Option<ffi::richcmpfunc> {
|
||||
unsafe extern "C" fn wrap<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
arg: *mut ffi::PyObject,
|
||||
|
@ -433,7 +230,31 @@ where
|
|||
slf.try_borrow()?.__richcmp__(arg, op).into()
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
self.tp_richcompare = Some(wrap::<T>);
|
||||
}
|
||||
pub fn set_setattr<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectSetAttrProtocol<'p>,
|
||||
{
|
||||
self.tp_setattro = py_func_set!(PyObjectSetAttrProtocol, T, __setattr__);
|
||||
}
|
||||
pub fn set_delattr<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectDelAttrProtocol<'p>,
|
||||
{
|
||||
self.tp_setattro = py_func_del!(PyObjectDelAttrProtocol, T, __delattr__);
|
||||
}
|
||||
pub fn set_setdelattr<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectSetAttrProtocol<'p> + for<'p> PyObjectDelAttrProtocol<'p>,
|
||||
{
|
||||
self.tp_setattro = py_func_set_del!(
|
||||
PyObjectSetAttrProtocol,
|
||||
PyObjectDelAttrProtocol,
|
||||
T,
|
||||
__setattr__,
|
||||
__delattr__
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,10 @@
|
|||
//! For more information check [buffer protocol](https://docs.python.org/3/c-api/buffer.html)
|
||||
//! c-api
|
||||
use crate::err::PyResult;
|
||||
use crate::{ffi, PyCell, PyClass, PyRefMut};
|
||||
use crate::{
|
||||
ffi::{self, PyBufferProcs},
|
||||
PyCell, PyClass, PyRefMut,
|
||||
};
|
||||
use std::os::raw::c_int;
|
||||
|
||||
/// Buffer protocol interface
|
||||
|
@ -37,51 +40,11 @@ pub trait PyBufferReleaseBufferProtocol<'p>: PyBufferProtocol<'p> {
|
|||
type Result: Into<PyResult<()>>;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait PyBufferProtocolImpl {
|
||||
fn tp_as_buffer() -> Option<ffi::PyBufferProcs>;
|
||||
}
|
||||
|
||||
impl<T> PyBufferProtocolImpl for T {
|
||||
default fn tp_as_buffer() -> Option<ffi::PyBufferProcs> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, T> PyBufferProtocolImpl for T
|
||||
where
|
||||
T: PyBufferProtocol<'p>,
|
||||
{
|
||||
#[inline]
|
||||
#[allow(clippy::needless_update)] // For python 2 it's not useless
|
||||
fn tp_as_buffer() -> Option<ffi::PyBufferProcs> {
|
||||
Some(ffi::PyBufferProcs {
|
||||
bf_getbuffer: Self::cb_bf_getbuffer(),
|
||||
bf_releasebuffer: Self::cb_bf_releasebuffer(),
|
||||
..ffi::PyBufferProcs_INIT
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
trait PyBufferGetBufferProtocolImpl {
|
||||
fn cb_bf_getbuffer() -> Option<ffi::getbufferproc>;
|
||||
}
|
||||
|
||||
impl<'p, T> PyBufferGetBufferProtocolImpl for T
|
||||
where
|
||||
T: PyBufferProtocol<'p>,
|
||||
{
|
||||
default fn cb_bf_getbuffer() -> Option<ffi::getbufferproc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PyBufferGetBufferProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PyBufferGetBufferProtocol<'p>,
|
||||
{
|
||||
#[inline]
|
||||
fn cb_bf_getbuffer() -> Option<ffi::getbufferproc> {
|
||||
impl PyBufferProcs {
|
||||
pub fn set_getbuffer<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyBufferGetBufferProtocol<'p>,
|
||||
{
|
||||
unsafe extern "C" fn wrap<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
arg1: *mut ffi::Py_buffer,
|
||||
|
@ -95,29 +58,12 @@ where
|
|||
T::bf_getbuffer(slf.try_borrow_mut()?, arg1, arg2).into()
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
self.bf_getbuffer = Some(wrap::<T>);
|
||||
}
|
||||
}
|
||||
|
||||
trait PyBufferReleaseBufferProtocolImpl {
|
||||
fn cb_bf_releasebuffer() -> Option<ffi::releasebufferproc>;
|
||||
}
|
||||
|
||||
impl<'p, T> PyBufferReleaseBufferProtocolImpl for T
|
||||
where
|
||||
T: PyBufferProtocol<'p>,
|
||||
{
|
||||
default fn cb_bf_releasebuffer() -> Option<ffi::releasebufferproc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PyBufferReleaseBufferProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PyBufferReleaseBufferProtocol<'p>,
|
||||
{
|
||||
#[inline]
|
||||
fn cb_bf_releasebuffer() -> Option<ffi::releasebufferproc> {
|
||||
pub fn set_releasebuffer<T>(&mut self)
|
||||
where
|
||||
T: 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>,
|
||||
|
@ -127,6 +73,6 @@ where
|
|||
T::bf_releasebuffer(slf.try_borrow_mut()?, arg1).into()
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
self.bf_releasebuffer = Some(wrap::<T>);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
//! [Python information](
|
||||
//! https://docs.python.org/3/reference/datamodel.html#implementing-descriptors)
|
||||
|
||||
use crate::class::methods::PyMethodDef;
|
||||
use crate::err::PyResult;
|
||||
use crate::types::{PyAny, PyType};
|
||||
use crate::{ffi, FromPyObject, IntoPy, PyClass, PyObject};
|
||||
|
@ -66,76 +65,27 @@ pub trait PyDescrSetNameProtocol<'p>: PyDescrProtocol<'p> {
|
|||
type Result: Into<PyResult<()>>;
|
||||
}
|
||||
|
||||
trait PyDescrGetProtocolImpl {
|
||||
fn tp_descr_get() -> Option<ffi::descrgetfunc>;
|
||||
}
|
||||
impl<'p, T> PyDescrGetProtocolImpl for T
|
||||
where
|
||||
T: PyDescrProtocol<'p>,
|
||||
{
|
||||
default fn tp_descr_get() -> Option<ffi::descrgetfunc> {
|
||||
None
|
||||
}
|
||||
#[derive(Default)]
|
||||
pub struct PyDescrMethods {
|
||||
pub tp_descr_get: Option<ffi::descrgetfunc>,
|
||||
pub tp_descr_set: Option<ffi::descrsetfunc>,
|
||||
}
|
||||
|
||||
impl<T> PyDescrGetProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PyDescrGetProtocol<'p>,
|
||||
{
|
||||
fn tp_descr_get() -> Option<ffi::descrgetfunc> {
|
||||
py_ternary_func!(PyDescrGetProtocol, T::__get__)
|
||||
}
|
||||
}
|
||||
|
||||
trait PyDescrSetProtocolImpl {
|
||||
fn tp_descr_set() -> Option<ffi::descrsetfunc>;
|
||||
}
|
||||
impl<'p, T> PyDescrSetProtocolImpl for T
|
||||
where
|
||||
T: PyDescrProtocol<'p>,
|
||||
{
|
||||
default fn tp_descr_set() -> Option<ffi::descrsetfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
impl<T> PyDescrSetProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PyDescrSetProtocol<'p>,
|
||||
{
|
||||
fn tp_descr_set() -> Option<ffi::descrsetfunc> {
|
||||
py_ternary_func!(PyDescrSetProtocol, T::__set__, c_int)
|
||||
}
|
||||
}
|
||||
|
||||
trait PyDescrDelProtocolImpl {
|
||||
fn __del__() -> Option<PyMethodDef> {
|
||||
None
|
||||
}
|
||||
}
|
||||
impl<'p, T> PyDescrDelProtocolImpl for T where T: PyDescrProtocol<'p> {}
|
||||
|
||||
trait PyDescrSetNameProtocolImpl {
|
||||
fn __set_name__() -> Option<PyMethodDef> {
|
||||
None
|
||||
}
|
||||
}
|
||||
impl<'p, T> PyDescrSetNameProtocolImpl for T where T: PyDescrProtocol<'p> {}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait PyDescrProtocolImpl {
|
||||
fn tp_as_descr(_type_object: &mut ffi::PyTypeObject);
|
||||
}
|
||||
|
||||
impl<T> PyDescrProtocolImpl for T {
|
||||
default fn tp_as_descr(_type_object: &mut ffi::PyTypeObject) {}
|
||||
}
|
||||
|
||||
impl<'p, T> PyDescrProtocolImpl for T
|
||||
where
|
||||
T: PyDescrProtocol<'p>,
|
||||
{
|
||||
fn tp_as_descr(type_object: &mut ffi::PyTypeObject) {
|
||||
type_object.tp_descr_get = Self::tp_descr_get();
|
||||
type_object.tp_descr_set = Self::tp_descr_set();
|
||||
impl PyDescrMethods {
|
||||
pub(crate) fn prepare_type_obj(&self, type_object: &mut ffi::PyTypeObject) {
|
||||
type_object.tp_descr_get = self.tp_descr_get;
|
||||
type_object.tp_descr_set = self.tp_descr_set;
|
||||
}
|
||||
pub fn set_descr_get<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyDescrGetProtocol<'p>,
|
||||
{
|
||||
self.tp_descr_get = py_ternary_func!(PyDescrGetProtocol, T::__get__);
|
||||
}
|
||||
pub fn set_descr_set<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyDescrSetProtocol<'p>,
|
||||
{
|
||||
self.tp_descr_set = py_ternary_func!(PyDescrSetProtocol, T::__set__, c_int);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,69 +40,28 @@ pub trait PyIterNextProtocol<'p>: PyIterProtocol<'p> {
|
|||
type Result: Into<PyResult<Option<Self::Success>>>;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait PyIterProtocolImpl {
|
||||
fn tp_as_iter(_typeob: &mut ffi::PyTypeObject);
|
||||
#[derive(Default)]
|
||||
pub struct PyIterMethods {
|
||||
pub tp_iter: Option<ffi::getiterfunc>,
|
||||
pub tp_iternext: Option<ffi::iternextfunc>,
|
||||
}
|
||||
|
||||
impl<T> PyIterProtocolImpl for T {
|
||||
default fn tp_as_iter(_typeob: &mut ffi::PyTypeObject) {}
|
||||
}
|
||||
|
||||
impl<'p, T> PyIterProtocolImpl for T
|
||||
where
|
||||
T: PyIterProtocol<'p>,
|
||||
{
|
||||
#[inline]
|
||||
fn tp_as_iter(typeob: &mut ffi::PyTypeObject) {
|
||||
typeob.tp_iter = Self::tp_iter();
|
||||
typeob.tp_iternext = Self::tp_iternext();
|
||||
impl PyIterMethods {
|
||||
pub(crate) fn prepare_type_obj(&self, type_object: &mut ffi::PyTypeObject) {
|
||||
type_object.tp_iter = self.tp_iter;
|
||||
type_object.tp_iternext = self.tp_iternext;
|
||||
}
|
||||
}
|
||||
|
||||
trait PyIterIterProtocolImpl {
|
||||
fn tp_iter() -> Option<ffi::getiterfunc>;
|
||||
}
|
||||
|
||||
impl<'p, T> PyIterIterProtocolImpl for T
|
||||
where
|
||||
T: PyIterProtocol<'p>,
|
||||
{
|
||||
default fn tp_iter() -> Option<ffi::getiterfunc> {
|
||||
None
|
||||
pub fn set_iter<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyIterIterProtocol<'p>,
|
||||
{
|
||||
self.tp_iter = py_unarys_func!(PyIterIterProtocol, T::__iter__);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PyIterIterProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PyIterIterProtocol<'p>,
|
||||
{
|
||||
#[inline]
|
||||
fn tp_iter() -> Option<ffi::getiterfunc> {
|
||||
py_unarys_func!(PyIterIterProtocol, T::__iter__)
|
||||
}
|
||||
}
|
||||
|
||||
trait PyIterNextProtocolImpl {
|
||||
fn tp_iternext() -> Option<ffi::iternextfunc>;
|
||||
}
|
||||
|
||||
impl<'p, T> PyIterNextProtocolImpl for T
|
||||
where
|
||||
T: PyIterProtocol<'p>,
|
||||
{
|
||||
default fn tp_iternext() -> Option<ffi::iternextfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PyIterNextProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PyIterNextProtocol<'p>,
|
||||
{
|
||||
#[inline]
|
||||
fn tp_iternext() -> Option<ffi::iternextfunc> {
|
||||
py_unarys_func!(PyIterNextProtocol, T::__next__, IterNextConverter)
|
||||
pub fn set_iternext<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyIterNextProtocol<'p>,
|
||||
{
|
||||
self.tp_iternext = py_unarys_func!(PyIterNextProtocol, T::__next__, IterNextConverter);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ pub mod iter;
|
|||
pub mod mapping;
|
||||
pub mod methods;
|
||||
pub mod number;
|
||||
pub mod proto_methods;
|
||||
pub mod pyasync;
|
||||
pub mod sequence;
|
||||
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
//! Python Number Interface
|
||||
//! Trait and support implementation for implementing number protocol
|
||||
|
||||
use crate::class::basic::PyObjectProtocolImpl;
|
||||
use crate::err::PyResult;
|
||||
use crate::{ffi, FromPyObject, IntoPy, PyClass, PyObject};
|
||||
use std::os::raw::c_int;
|
||||
|
||||
/// Number interface
|
||||
#[allow(unused_variables)]
|
||||
|
@ -314,6 +314,12 @@ pub trait PyNumberProtocol<'p>: PyClass {
|
|||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __bool__(&'p self) -> Self::Result
|
||||
where
|
||||
Self: PyNumberBoolProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PyNumberAddProtocol<'p>: PyNumberProtocol<'p> {
|
||||
|
@ -616,22 +622,18 @@ pub trait PyNumberIndexProtocol<'p>: PyNumberProtocol<'p> {
|
|||
type Result: Into<PyResult<Self::Success>>;
|
||||
}
|
||||
|
||||
pub trait PyNumberBoolProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Result: Into<PyResult<bool>>;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait PyNumberProtocolImpl: PyObjectProtocolImpl {
|
||||
pub trait PyNumberProtocolImpl {
|
||||
fn tp_as_number() -> Option<ffi::PyNumberMethods>;
|
||||
}
|
||||
|
||||
impl<'p, T> PyNumberProtocolImpl for T {
|
||||
default fn tp_as_number() -> Option<ffi::PyNumberMethods> {
|
||||
if let Some(nb_bool) = <Self as PyObjectProtocolImpl>::nb_bool_fn() {
|
||||
let meth = ffi::PyNumberMethods {
|
||||
nb_bool: Some(nb_bool),
|
||||
..ffi::PyNumberMethods_INIT
|
||||
};
|
||||
Some(meth)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -650,7 +652,7 @@ where
|
|||
nb_negative: Self::nb_negative(),
|
||||
nb_positive: Self::nb_positive(),
|
||||
nb_absolute: Self::nb_absolute(),
|
||||
nb_bool: <Self as PyObjectProtocolImpl>::nb_bool_fn(),
|
||||
nb_bool: Self::nb_bool(),
|
||||
nb_invert: Self::nb_invert(),
|
||||
nb_lshift: Self::nb_lshift().or_else(Self::nb_lshift_fallback),
|
||||
nb_rshift: Self::nb_rshift().or_else(Self::nb_rshift_fallback),
|
||||
|
@ -1738,3 +1740,23 @@ where
|
|||
py_unary_func!(PyNumberIndexProtocol, T::__index__)
|
||||
}
|
||||
}
|
||||
|
||||
trait PyNumberBoolProtocolImpl {
|
||||
fn nb_bool() -> Option<ffi::inquiry>;
|
||||
}
|
||||
impl<'p, T> PyNumberBoolProtocolImpl for T
|
||||
where
|
||||
T: PyNumberProtocol<'p>,
|
||||
{
|
||||
default fn nb_bool() -> Option<ffi::inquiry> {
|
||||
None
|
||||
}
|
||||
}
|
||||
impl<T> PyNumberBoolProtocolImpl for T
|
||||
where
|
||||
T: for<'p> PyNumberBoolProtocol<'p>,
|
||||
{
|
||||
fn nb_bool() -> Option<ffi::inquiry> {
|
||||
py_unary_func!(PyNumberBoolProtocol, T::__bool__, c_int)
|
||||
}
|
||||
}
|
||||
|
|
73
src/class/proto_methods.rs
Normal file
73
src/class/proto_methods.rs
Normal file
|
@ -0,0 +1,73 @@
|
|||
use crate::class::{basic::PyObjectMethods, descr::PyDescrMethods, iter::PyIterMethods};
|
||||
use crate::ffi::PyBufferProcs;
|
||||
use std::{
|
||||
ptr::{self, NonNull},
|
||||
sync::atomic::{AtomicPtr, Ordering},
|
||||
};
|
||||
|
||||
/// For rust-numpy, we need a stub implementation.
|
||||
pub trait PyProtoMethods {
|
||||
fn basic_methods() -> Option<NonNull<PyObjectMethods>>;
|
||||
fn buffer_methods() -> Option<NonNull<PyBufferProcs>>;
|
||||
fn descr_methods() -> Option<NonNull<PyDescrMethods>>;
|
||||
fn iter_methods() -> Option<NonNull<PyIterMethods>>;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait HasPyProtoRegistry: Sized + 'static {
|
||||
fn registory() -> &'static PyProtoRegistry;
|
||||
}
|
||||
|
||||
impl<T: HasPyProtoRegistry> PyProtoMethods for T {
|
||||
fn basic_methods() -> Option<NonNull<PyObjectMethods>> {
|
||||
NonNull::new(Self::registory().basic_methods.load(Ordering::SeqCst))
|
||||
}
|
||||
fn buffer_methods() -> Option<NonNull<PyBufferProcs>> {
|
||||
NonNull::new(Self::registory().buffer_methods.load(Ordering::SeqCst))
|
||||
}
|
||||
fn descr_methods() -> Option<NonNull<PyDescrMethods>> {
|
||||
NonNull::new(Self::registory().descr_methods.load(Ordering::SeqCst))
|
||||
}
|
||||
fn iter_methods() -> Option<NonNull<PyIterMethods>> {
|
||||
NonNull::new(Self::registory().iter_methods.load(Ordering::SeqCst))
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct PyProtoRegistry {
|
||||
// Basic Protocols
|
||||
basic_methods: AtomicPtr<PyObjectMethods>,
|
||||
// Buffer Protocols
|
||||
buffer_methods: AtomicPtr<PyBufferProcs>,
|
||||
// Descr Protocols
|
||||
descr_methods: AtomicPtr<PyDescrMethods>,
|
||||
// Iterator Protocols
|
||||
iter_methods: AtomicPtr<PyIterMethods>,
|
||||
}
|
||||
|
||||
impl PyProtoRegistry {
|
||||
pub const fn new() -> Self {
|
||||
PyProtoRegistry {
|
||||
basic_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
buffer_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
descr_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
iter_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
}
|
||||
}
|
||||
pub fn set_basic_methods(&self, methods: PyObjectMethods) {
|
||||
self.basic_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::SeqCst)
|
||||
}
|
||||
pub fn set_buffer_methods(&self, methods: PyBufferProcs) {
|
||||
self.buffer_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::SeqCst)
|
||||
}
|
||||
pub fn set_descr_methods(&self, methods: PyDescrMethods) {
|
||||
self.descr_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::SeqCst)
|
||||
}
|
||||
pub fn set_iter_methods(&self, methods: PyIterMethods) {
|
||||
self.iter_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::SeqCst)
|
||||
}
|
||||
}
|
|
@ -438,14 +438,16 @@ mod typeobject {
|
|||
impl Default for PyAsyncMethods {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
unsafe { mem::zeroed() }
|
||||
PyAsyncMethods_INIT
|
||||
}
|
||||
}
|
||||
|
||||
pub const PyAsyncMethods_INIT: PyAsyncMethods = PyAsyncMethods {
|
||||
am_await: None,
|
||||
am_aiter: None,
|
||||
am_anext: None,
|
||||
};
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct PyBufferProcs {
|
||||
|
@ -456,9 +458,10 @@ mod typeobject {
|
|||
impl Default for PyBufferProcs {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
unsafe { mem::zeroed() }
|
||||
PyBufferProcs_INIT
|
||||
}
|
||||
}
|
||||
|
||||
pub const PyBufferProcs_INIT: PyBufferProcs = PyBufferProcs {
|
||||
bf_getbuffer: None,
|
||||
bf_releasebuffer: None,
|
||||
|
|
|
@ -45,9 +45,8 @@ pub unsafe trait PyNativeType: Sized {
|
|||
#[repr(transparent)]
|
||||
pub struct Py<T>(NonNull<ffi::PyObject>, PhantomData<T>);
|
||||
|
||||
unsafe impl<T> Send for Py<T> {}
|
||||
|
||||
unsafe impl<T> Sync for Py<T> {}
|
||||
unsafe impl<T: Send> Send for Py<T> {}
|
||||
unsafe impl<T: Sync> Sync for Py<T> {}
|
||||
|
||||
impl<T> Py<T> {
|
||||
/// Create a new instance `Py<T>`.
|
||||
|
|
|
@ -153,6 +153,7 @@ pub use crate::types::PyAny;
|
|||
#[cfg(feature = "macros")]
|
||||
#[doc(hidden)]
|
||||
pub use {
|
||||
ctor, // Re-exported for pyproto
|
||||
indoc, // Re-exported for py_run
|
||||
inventory, // Re-exported for pymethods
|
||||
paste, // Re-exported for wrap_function
|
||||
|
|
|
@ -372,7 +372,7 @@ impl<T: PyClass> AsPyPointer for PyCell<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: PyClass> ToPyObject for &PyCell<T> {
|
||||
impl<T: PyClass + Send + Sync> ToPyObject for &PyCell<T> {
|
||||
fn to_object(&self, py: Python<'_>) -> PyObject {
|
||||
unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) }
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
//! `PyClass` trait
|
||||
use crate::class::methods::{PyClassAttributeDef, PyMethodDefType, PyMethods};
|
||||
use crate::class::proto_methods::PyProtoMethods;
|
||||
use crate::conversion::{IntoPyPointer, ToPyObject};
|
||||
use crate::pyclass_slots::{PyClassDict, PyClassWeakRef};
|
||||
use crate::type_object::{type_flags, PyLayout};
|
||||
|
@ -73,7 +74,7 @@ pub unsafe fn tp_free_fallback(obj: *mut ffi::PyObject) {
|
|||
/// The `#[pyclass]` attribute automatically implements this trait for your Rust struct,
|
||||
/// so you don't have to use this trait directly.
|
||||
pub trait PyClass:
|
||||
PyTypeInfo<Layout = PyCell<Self>> + Sized + PyClassAlloc + PyMethods + Send
|
||||
PyTypeInfo<Layout = PyCell<Self>> + Sized + PyClassAlloc + PyMethods + PyProtoMethods + Send
|
||||
{
|
||||
/// Specify this class has `#[pyclass(dict)]` or not.
|
||||
type Dict: PyClassDict;
|
||||
|
@ -140,13 +141,19 @@ where
|
|||
<T as class::gc::PyGCProtocolImpl>::update_type_object(type_object);
|
||||
|
||||
// descriptor protocol
|
||||
<T as class::descr::PyDescrProtocolImpl>::tp_as_descr(type_object);
|
||||
if let Some(descr) = T::descr_methods() {
|
||||
unsafe { descr.as_ref() }.prepare_type_obj(type_object);
|
||||
}
|
||||
|
||||
// iterator methods
|
||||
<T as class::iter::PyIterProtocolImpl>::tp_as_iter(type_object);
|
||||
if let Some(iter) = T::iter_methods() {
|
||||
unsafe { iter.as_ref() }.prepare_type_obj(type_object);
|
||||
}
|
||||
|
||||
// basic methods
|
||||
<T as class::basic::PyObjectProtocolImpl>::tp_as_object(type_object);
|
||||
if let Some(basic) = T::basic_methods() {
|
||||
unsafe { basic.as_ref() }.prepare_type_obj(type_object);
|
||||
}
|
||||
|
||||
fn to_ptr<T>(value: Option<T>) -> *mut T {
|
||||
value
|
||||
|
@ -165,7 +172,7 @@ where
|
|||
// async methods
|
||||
type_object.tp_as_async = to_ptr(<T as class::pyasync::PyAsyncProtocolImpl>::tp_as_async());
|
||||
// buffer protocol
|
||||
type_object.tp_as_buffer = to_ptr(<T as class::buffer::PyBufferProtocolImpl>::tp_as_buffer());
|
||||
type_object.tp_as_buffer = T::buffer_methods().map_or_else(ptr::null_mut, |p| p.as_ptr());
|
||||
|
||||
let (new, call, mut methods, attrs) = py_class_method_defs::<T>();
|
||||
|
||||
|
|
|
@ -121,6 +121,10 @@ impl PyObjectProtocol for Comparisons {
|
|||
fn __hash__(&self) -> PyResult<isize> {
|
||||
Ok(self.val as isize)
|
||||
}
|
||||
}
|
||||
|
||||
#[pyproto]
|
||||
impl pyo3::class::PyNumberProtocol for Comparisons {
|
||||
fn __bool__(&self) -> PyResult<bool> {
|
||||
Ok(self.val != 0)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue