Remove specialization from gc/mapping/number protocols

This commit is contained in:
kngwyu 2020-06-06 16:33:15 +09:00
parent 7967874177
commit 0d082961aa
12 changed files with 585 additions and 1414 deletions

View file

@ -53,16 +53,16 @@ impl PyMethod {
pub struct SlotSetter {
pub proto_names: &'static [&'static str],
pub set_function: &'static str,
pub exclude_indices: &'static [usize],
pub skipped_setters: &'static [&'static str],
}
impl SlotSetter {
const EMPTY_INDICES: &'static [usize] = &[];
const EMPTY_SETTERS: &'static [&'static str] = &[];
const fn new(names: &'static [&'static str], set_function: &'static str) -> Self {
SlotSetter {
proto_names: names,
set_function,
exclude_indices: Self::EMPTY_INDICES,
skipped_setters: Self::EMPTY_SETTERS,
}
}
}
@ -138,11 +138,10 @@ pub const OBJECT: Proto = Proto {
SlotSetter {
proto_names: &["__setattr__", "__delattr__"],
set_function: "set_setdelattr",
// exclude set and del
exclude_indices: &[6, 7],
skipped_setters: &["set_setattr", "set_delattr"],
},
SlotSetter::new(&["__setattr__"], "set_setattr"),
SlotSetter::new(&["__delattr__"], "set_setattr"),
SlotSetter::new(&["__delattr__"], "set_delattr"),
],
};
@ -248,8 +247,8 @@ pub const CONTEXT: Proto = Proto {
pub const GC: Proto = Proto {
name: "GC",
slot_table: "",
set_slot_table: "",
slot_table: "pyo3::class::gc::PyGCMethods",
set_slot_table: "set_gc_methods",
methods: &[
MethodProto::Free {
name: "__traverse__",
@ -261,7 +260,10 @@ pub const GC: Proto = Proto {
},
],
py_methods: &[],
slot_setters: &[],
slot_setters: &[
SlotSetter::new(&["__traverse__"], "set_traverse"),
SlotSetter::new(&["__clear__"], "set_clear"),
],
};
pub const DESCR: Proto = Proto {
@ -329,23 +331,15 @@ pub const ITER: Proto = Proto {
},
],
slot_setters: &[
SlotSetter {
proto_names: &["__iter__"],
set_function: "set_iter",
exclude_indices: &[],
},
SlotSetter {
proto_names: &["__next__"],
set_function: "set_iternext",
exclude_indices: &[],
},
SlotSetter::new(&["__iter__"], "set_iter"),
SlotSetter::new(&["__next__"], "set_iternext"),
],
};
pub const MAPPING: Proto = Proto {
name: "Mapping",
slot_table: "",
set_slot_table: "",
slot_table: "pyo3::ffi::PyMappingMethods",
set_slot_table: "set_mapping_methods",
methods: &[
MethodProto::Unary {
name: "__len__",
@ -381,7 +375,17 @@ pub const MAPPING: Proto = Proto {
"__reversed__",
"pyo3::class::mapping::PyMappingReversedProtocolImpl",
)],
slot_setters: &[],
slot_setters: &[
SlotSetter::new(&["__len__"], "set_length"),
SlotSetter::new(&["__getitem__"], "set_getitem"),
SlotSetter {
proto_names: &["__setitem__", "__delitem__"],
set_function: "set_setdelitem",
skipped_setters: &["set_setitem", "set_delitem"],
},
SlotSetter::new(&["__setitem__"], "set_setitem"),
SlotSetter::new(&["__delitem__"], "set_delitem"),
],
};
pub const SEQ: Proto = Proto {
@ -450,8 +454,8 @@ pub const SEQ: Proto = Proto {
pub const NUM: Proto = Proto {
name: "Number",
slot_table: "",
set_slot_table: "",
slot_table: "pyo3::ffi::PyNumberMethods",
set_slot_table: "set_number_methods",
methods: &[
MethodProto::BinaryS {
name: "__add__",
@ -809,5 +813,107 @@ pub const NUM: Proto = Proto {
"pyo3::class::number::PyNumberRoundProtocolImpl",
),
],
slot_setters: &[],
slot_setters: &[
SlotSetter {
proto_names: &["__add__"],
set_function: "set_add",
skipped_setters: &["set_radd"],
},
SlotSetter::new(&["__radd__"], "set_radd"),
SlotSetter {
proto_names: &["__sub__"],
set_function: "set_sub",
skipped_setters: &["set_rsub"],
},
SlotSetter::new(&["__rsub__"], "set_rsub"),
SlotSetter {
proto_names: &["__mul__"],
set_function: "set_mul",
skipped_setters: &["set_rmul"],
},
SlotSetter::new(&["__rmul__"], "set_rmul"),
SlotSetter::new(&["__mod__"], "set_mod"),
SlotSetter {
proto_names: &["__divmod__"],
set_function: "set_divmod",
skipped_setters: &["set_rdivmod"],
},
SlotSetter::new(&["__rdivmod__"], "set_rdivmod"),
SlotSetter {
proto_names: &["__pow__"],
set_function: "set_pow",
skipped_setters: &["set_rpow"],
},
SlotSetter::new(&["__rpow__"], "set_rpow"),
SlotSetter::new(&["__neg__"], "set_neg"),
SlotSetter::new(&["__pos__"], "set_pos"),
SlotSetter::new(&["__abs__"], "set_abs"),
SlotSetter::new(&["__bool__"], "set_bool"),
SlotSetter::new(&["__invert__"], "set_invert"),
SlotSetter::new(&["__rdivmod__"], "set_rdivmod"),
SlotSetter {
proto_names: &["__lshift__"],
set_function: "set_lshift",
skipped_setters: &["set_rlshift"],
},
SlotSetter::new(&["__rlshift__"], "set_rlshift"),
SlotSetter {
proto_names: &["__rshift__"],
set_function: "set_rshift",
skipped_setters: &["set_rrshift"],
},
SlotSetter::new(&["__rrshift__"], "set_rrshift"),
SlotSetter {
proto_names: &["__and__"],
set_function: "set_and",
skipped_setters: &["set_rand"],
},
SlotSetter::new(&["__rand__"], "set_rand"),
SlotSetter {
proto_names: &["__xor__"],
set_function: "set_xor",
skipped_setters: &["set_rxor"],
},
SlotSetter::new(&["__rxor__"], "set_rxor"),
SlotSetter {
proto_names: &["__or__"],
set_function: "set_or",
skipped_setters: &["set_ror"],
},
SlotSetter::new(&["__ror__"], "set_ror"),
SlotSetter::new(&["__int__"], "set_int"),
SlotSetter::new(&["__float__"], "set_float"),
SlotSetter::new(&["__iadd__"], "set_iadd"),
SlotSetter::new(&["__isub__"], "set_isub"),
SlotSetter::new(&["__imul__"], "set_imul"),
SlotSetter::new(&["__imod__"], "set_imod"),
SlotSetter::new(&["__ipow__"], "set_ipow"),
SlotSetter::new(&["__ilshift__"], "set_ilshift"),
SlotSetter::new(&["__irshift__"], "set_irshift"),
SlotSetter::new(&["__iand__"], "set_iand"),
SlotSetter::new(&["__ixor__"], "set_ixor"),
SlotSetter::new(&["__ior__"], "set_ior"),
SlotSetter {
proto_names: &["__floordiv__"],
set_function: "set_floordiv",
skipped_setters: &["set_rfloordiv"],
},
SlotSetter::new(&["__rfloordiv__"], "set_rfloordiv"),
SlotSetter {
proto_names: &["__truediv__"],
set_function: "set_truediv",
skipped_setters: &["set_rtruediv"],
},
SlotSetter::new(&["__rtruediv__"], "set_rtruediv"),
SlotSetter::new(&["__ifloordiv__"], "set_ifloordiv"),
SlotSetter::new(&["__itruediv__"], "set_itruediv"),
SlotSetter::new(&["__index__"], "set_index"),
SlotSetter {
proto_names: &["__matmul__"],
set_function: "set_matmul",
skipped_setters: &["set_rmatmul"],
},
SlotSetter::new(&["__rmatmul__"], "set_rmatmul"),
SlotSetter::new(&["__imatmul__"], "set_imatmul"),
],
};

View file

@ -239,7 +239,7 @@ 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 {
impl pyo3::class::proto_methods::HasProtoRegistry for #cls {
fn registory() -> &'static pyo3::class::proto_methods::PyProtoRegistry {
static REGISTRY: pyo3::class::proto_methods::PyProtoRegistry
= pyo3::class::proto_methods::PyProtoRegistry::new();

View file

@ -126,21 +126,23 @@ fn slot_initialization(
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) {
// Some setters cannot coexist.
// E.g., if we have `__add__`, we need to skip `set_radd`.
let mut skipped_setters = HashSet::new();
'setter_loop: for m in proto.slot_setters {
if skipped_setters.contains(m.set_function) {
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.
// If this `#[pyproto]` block doesn't provide all required methods,
// let's skip implementing this method.
continue 'setter_loop;
}
}
skip_indices.extend_from_slice(m.exclude_indices);
for s in m.skipped_setters {
skipped_setters.insert(s.to_string());
}
// Add slot methods to PyProtoRegistry
let set = syn::Ident::new(m.set_function, Span::call_site());
initializers.push(quote! { table.#set::<#ty>(); });
@ -160,7 +162,7 @@ fn slot_initialization(
fn #init() {
let mut table = #table::default();
#(#initializers)*
<#ty as pyo3::class::proto_methods::HasPyProtoRegistry>::registory().#set(table);
<#ty as pyo3::class::proto_methods::HasProtoRegistry>::registory().#set(table);
}
})
}

View file

@ -135,7 +135,7 @@ pub trait PyObjectRichcmpProtocol<'p>: PyObjectProtocol<'p> {
type Result: Into<PyResult<Self::Success>>;
}
/// All functions necessary for basic protocols.
/// All FFI functions for basic protocols.
#[derive(Default)]
pub struct PyObjectMethods {
pub tp_str: Option<ffi::reprfunc>,
@ -147,7 +147,7 @@ pub struct PyObjectMethods {
}
impl PyObjectMethods {
pub(crate) fn prepare_type_obj(&self, type_object: &mut ffi::PyTypeObject) {
pub(crate) fn update_typeobj(&self, type_object: &mut ffi::PyTypeObject) {
type_object.tp_str = self.tp_str;
type_object.tp_repr = self.tp_repr;
type_object.tp_hash = self.tp_hash;

View file

@ -72,7 +72,7 @@ pub struct PyDescrMethods {
}
impl PyDescrMethods {
pub(crate) fn prepare_type_obj(&self, type_object: &mut ffi::PyTypeObject) {
pub(crate) fn update_typeobj(&self, type_object: &mut ffi::PyTypeObject) {
type_object.tp_descr_get = self.tp_descr_get;
type_object.tp_descr_set = self.tp_descr_set;
}

View file

@ -18,69 +18,23 @@ pub trait PyGCProtocol<'p>: PyClass {
pub trait PyGCTraverseProtocol<'p>: PyGCProtocol<'p> {}
pub trait PyGCClearProtocol<'p>: PyGCProtocol<'p> {}
#[doc(hidden)]
pub trait PyGCProtocolImpl {
fn update_type_object(_type_object: &mut ffi::PyTypeObject);
/// All FFI functions for gc protocols.
#[derive(Default)]
pub struct PyGCMethods {
pub tp_traverse: Option<ffi::traverseproc>,
pub tp_clear: Option<ffi::inquiry>,
}
impl<'p, T> PyGCProtocolImpl for T {
default fn update_type_object(_type_object: &mut ffi::PyTypeObject) {}
}
impl<'p, T> PyGCProtocolImpl for T
where
T: PyGCProtocol<'p>,
{
fn update_type_object(type_object: &mut ffi::PyTypeObject) {
type_object.tp_traverse = Self::tp_traverse();
type_object.tp_clear = Self::tp_clear();
impl PyGCMethods {
pub(crate) fn update_typeobj(&self, type_object: &mut ffi::PyTypeObject) {
type_object.tp_traverse = self.tp_traverse;
type_object.tp_clear = self.tp_clear;
}
}
#[derive(Copy, Clone)]
pub struct PyVisit<'p> {
visit: ffi::visitproc,
arg: *mut c_void,
/// VisitProc contains a Python instance to ensure that
/// 1) it is cannot be moved out of the traverse() call
/// 2) it cannot be sent to other threads
_py: Python<'p>,
}
impl<'p> PyVisit<'p> {
pub fn call<T>(&self, obj: &T) -> Result<(), PyTraverseError>
pub fn set_traverse<T>(&mut self)
where
T: AsPyPointer,
T: for<'p> PyGCTraverseProtocol<'p>,
{
let r = unsafe { (self.visit)(obj.as_ptr(), self.arg) };
if r == 0 {
Ok(())
} else {
Err(PyTraverseError(r))
}
}
}
trait PyGCTraverseProtocolImpl {
fn tp_traverse() -> Option<ffi::traverseproc>;
}
impl<'p, T> PyGCTraverseProtocolImpl for T
where
T: PyGCProtocol<'p>,
{
default fn tp_traverse() -> Option<ffi::traverseproc> {
None
}
}
#[doc(hidden)]
impl<T> PyGCTraverseProtocolImpl for T
where
T: for<'p> PyGCTraverseProtocol<'p>,
{
#[inline]
fn tp_traverse() -> Option<ffi::traverseproc> {
unsafe extern "C" fn tp_traverse<T>(
slf: *mut ffi::PyObject,
visit: ffi::visitproc,
@ -108,30 +62,13 @@ where
0
}
}
Some(tp_traverse::<T>)
self.tp_traverse = Some(tp_traverse::<T>);
}
}
trait PyGCClearProtocolImpl {
fn tp_clear() -> Option<ffi::inquiry>;
}
impl<'p, T> PyGCClearProtocolImpl for T
where
T: PyGCProtocol<'p>,
{
default fn tp_clear() -> Option<ffi::inquiry> {
None
}
}
impl<T> PyGCClearProtocolImpl for T
where
T: for<'p> PyGCClearProtocol<'p>,
{
#[inline]
fn tp_clear() -> Option<ffi::inquiry> {
pub fn set_clear<T>(&mut self)
where
T: for<'p> PyGCClearProtocol<'p>,
{
unsafe extern "C" fn tp_clear<T>(slf: *mut ffi::PyObject) -> c_int
where
T: for<'p> PyGCClearProtocol<'p>,
@ -143,6 +80,32 @@ where
slf.borrow_mut().__clear__();
0
}
Some(tp_clear::<T>)
self.tp_clear = Some(tp_clear::<T>);
}
}
/// Object visitor for GC.
#[derive(Copy, Clone)]
pub struct PyVisit<'p> {
visit: ffi::visitproc,
arg: *mut c_void,
/// VisitProc contains a Python instance to ensure that
/// 1) it is cannot be moved out of the traverse() call
/// 2) it cannot be sent to other threads
_py: Python<'p>,
}
impl<'p> PyVisit<'p> {
/// Visit `obj`.
pub fn call<T>(&self, obj: &T) -> Result<(), PyTraverseError>
where
T: AsPyPointer,
{
let r = unsafe { (self.visit)(obj.as_ptr(), self.arg) };
if r == 0 {
Ok(())
} else {
Err(PyTraverseError(r))
}
}
}

View file

@ -47,7 +47,7 @@ pub struct PyIterMethods {
}
impl PyIterMethods {
pub(crate) fn prepare_type_obj(&self, type_object: &mut ffi::PyTypeObject) {
pub(crate) fn update_typeobj(&self, type_object: &mut ffi::PyTypeObject) {
type_object.tp_iter = self.tp_iter;
type_object.tp_iternext = self.tp_iternext;
}

View file

@ -106,7 +106,7 @@ macro_rules! py_binary_num_func {
#[macro_export]
#[doc(hidden)]
macro_rules! py_binary_reverse_num_func {
macro_rules! py_binary_reversed_num_func {
($trait:ident, $class:ident :: $f:ident) => {{
unsafe extern "C" fn wrap<T>(
lhs: *mut ffi::PyObject,
@ -240,7 +240,7 @@ macro_rules! py_ternary_num_func {
#[macro_export]
#[doc(hidden)]
macro_rules! py_ternary_reverse_num_func {
macro_rules! py_ternary_reversed_num_func {
($trait:ident, $class:ident :: $f:ident) => {{
unsafe extern "C" fn wrap<T>(
arg1: *mut $crate::ffi::PyObject,

View file

@ -74,155 +74,41 @@ pub trait PyMappingReversedProtocol<'p>: PyMappingProtocol<'p> {
type Result: Into<PyResult<Self::Success>>;
}
#[doc(hidden)]
pub trait PyMappingProtocolImpl {
fn tp_as_mapping() -> Option<ffi::PyMappingMethods>;
}
impl<T> PyMappingProtocolImpl for T {
default fn tp_as_mapping() -> Option<ffi::PyMappingMethods> {
None
impl ffi::PyMappingMethods {
pub fn set_length<T>(&mut self)
where
T: for<'p> PyMappingLenProtocol<'p>,
{
self.mp_length = py_len_func!(PyMappingLenProtocol, T::__len__);
}
}
impl<'p, T> PyMappingProtocolImpl for T
where
T: PyMappingProtocol<'p>,
{
#[inline]
fn tp_as_mapping() -> Option<ffi::PyMappingMethods> {
let f = if let Some(df) = Self::mp_del_subscript() {
Some(df)
} else {
Self::mp_ass_subscript()
};
Some(ffi::PyMappingMethods {
mp_length: Self::mp_length(),
mp_subscript: Self::mp_subscript(),
mp_ass_subscript: f,
})
pub fn set_getitem<T>(&mut self)
where
T: for<'p> PyMappingGetItemProtocol<'p>,
{
self.mp_subscript = py_binary_func!(PyMappingGetItemProtocol, T::__getitem__);
}
}
trait PyMappingLenProtocolImpl {
fn mp_length() -> Option<ffi::lenfunc>;
}
impl<'p, T> PyMappingLenProtocolImpl for T
where
T: PyMappingProtocol<'p>,
{
default fn mp_length() -> Option<ffi::lenfunc> {
None
pub fn set_setitem<T>(&mut self)
where
T: for<'p> PyMappingSetItemProtocol<'p>,
{
self.mp_ass_subscript = py_func_set!(PyMappingSetItemProtocol, T, __setitem__);
}
}
impl<T> PyMappingLenProtocolImpl for T
where
T: for<'p> PyMappingLenProtocol<'p>,
{
#[inline]
fn mp_length() -> Option<ffi::lenfunc> {
py_len_func!(PyMappingLenProtocol, T::__len__)
pub fn set_delitem<T>(&mut self)
where
T: for<'p> PyMappingDelItemProtocol<'p>,
{
self.mp_ass_subscript = py_func_del!(PyMappingDelItemProtocol, T, __delitem__);
}
}
trait PyMappingGetItemProtocolImpl {
fn mp_subscript() -> Option<ffi::binaryfunc>;
}
impl<'p, T> PyMappingGetItemProtocolImpl for T
where
T: PyMappingProtocol<'p>,
{
default fn mp_subscript() -> Option<ffi::binaryfunc> {
None
}
}
impl<T> PyMappingGetItemProtocolImpl for T
where
T: for<'p> PyMappingGetItemProtocol<'p>,
{
#[inline]
fn mp_subscript() -> Option<ffi::binaryfunc> {
py_binary_func!(PyMappingGetItemProtocol, T::__getitem__)
}
}
trait PyMappingSetItemProtocolImpl {
fn mp_ass_subscript() -> Option<ffi::objobjargproc>;
}
impl<'p, T> PyMappingSetItemProtocolImpl for T
where
T: PyMappingProtocol<'p>,
{
default fn mp_ass_subscript() -> Option<ffi::objobjargproc> {
None
}
}
impl<T> PyMappingSetItemProtocolImpl for T
where
T: for<'p> PyMappingSetItemProtocol<'p>,
{
#[inline]
fn mp_ass_subscript() -> Option<ffi::objobjargproc> {
py_func_set!(PyMappingSetItemProtocol, T, __setitem__)
}
}
/// Returns `None` if PyMappingDelItemProtocol isn't implemented, otherwise dispatches to
/// `DelSetItemDispatch`
trait DeplItemDipatch {
fn mp_del_subscript() -> Option<ffi::objobjargproc>;
}
impl<'p, T> DeplItemDipatch for T
where
T: PyMappingProtocol<'p>,
{
default fn mp_del_subscript() -> Option<ffi::objobjargproc> {
None
}
}
/// Returns `py_func_set_del` if PyMappingSetItemProtocol is implemented, otherwise `py_func_del`
trait DelSetItemDispatch: Sized + for<'p> PyMappingDelItemProtocol<'p> {
fn det_set_dispatch() -> Option<ffi::objobjargproc>;
}
impl<T> DelSetItemDispatch for T
where
T: Sized + for<'p> PyMappingDelItemProtocol<'p>,
{
default fn det_set_dispatch() -> Option<ffi::objobjargproc> {
py_func_del!(PyMappingDelItemProtocol, Self, __delitem__)
}
}
impl<T> DelSetItemDispatch for T
where
T: for<'p> PyMappingSetItemProtocol<'p> + for<'p> PyMappingDelItemProtocol<'p>,
{
fn det_set_dispatch() -> Option<ffi::objobjargproc> {
py_func_set_del!(
pub fn set_setdelitem<T>(&mut self)
where
T: for<'p> PyMappingSetItemProtocol<'p> + for<'p> PyMappingDelItemProtocol<'p>,
{
self.mp_ass_subscript = py_func_set_del!(
PyMappingSetItemProtocol,
PyMappingDelItemProtocol,
T,
__setitem__,
__delitem__
)
}
}
impl<T> DeplItemDipatch for T
where
T: Sized + for<'p> PyMappingDelItemProtocol<'p>,
{
fn mp_del_subscript() -> Option<ffi::objobjargproc> {
<T as DelSetItemDispatch>::det_set_dispatch()
);
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,24 +1,45 @@
use crate::class::{basic::PyObjectMethods, descr::PyDescrMethods, iter::PyIterMethods};
use crate::ffi::PyBufferProcs;
use crate::class::{
basic::PyObjectMethods, descr::PyDescrMethods, gc::PyGCMethods, iter::PyIterMethods,
};
use crate::ffi::{PyBufferProcs, PyMappingMethods, PyNumberMethods};
use std::{
ptr::{self, NonNull},
sync::atomic::{AtomicPtr, Ordering},
};
/// For rust-numpy, we need a stub implementation.
/// Defines what we need for method protocols.
/// Stub implementations are for rust-numpy.
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>>;
fn basic_methods() -> Option<NonNull<PyObjectMethods>> {
None
}
fn buffer_methods() -> Option<NonNull<PyBufferProcs>> {
None
}
fn descr_methods() -> Option<NonNull<PyDescrMethods>> {
None
}
fn gc_methods() -> Option<NonNull<PyGCMethods>> {
None
}
fn mapping_methods() -> Option<NonNull<PyMappingMethods>> {
None
}
fn number_methods() -> Option<NonNull<PyNumberMethods>> {
None
}
fn iter_methods() -> Option<NonNull<PyIterMethods>> {
None
}
}
/// Indicates that a type has a protocol registory.
#[doc(hidden)]
pub trait HasPyProtoRegistry: Sized + 'static {
pub trait HasProtoRegistry: Sized + 'static {
fn registory() -> &'static PyProtoRegistry;
}
impl<T: HasPyProtoRegistry> PyProtoMethods for T {
impl<T: HasProtoRegistry> PyProtoMethods for T {
fn basic_methods() -> Option<NonNull<PyObjectMethods>> {
NonNull::new(Self::registory().basic_methods.load(Ordering::SeqCst))
}
@ -28,6 +49,15 @@ impl<T: HasPyProtoRegistry> PyProtoMethods for T {
fn descr_methods() -> Option<NonNull<PyDescrMethods>> {
NonNull::new(Self::registory().descr_methods.load(Ordering::SeqCst))
}
fn gc_methods() -> Option<NonNull<PyGCMethods>> {
NonNull::new(Self::registory().gc_methods.load(Ordering::SeqCst))
}
fn mapping_methods() -> Option<NonNull<PyMappingMethods>> {
NonNull::new(Self::registory().mapping_methods.load(Ordering::SeqCst))
}
fn number_methods() -> Option<NonNull<PyNumberMethods>> {
NonNull::new(Self::registory().number_methods.load(Ordering::SeqCst))
}
fn iter_methods() -> Option<NonNull<PyIterMethods>> {
NonNull::new(Self::registory().iter_methods.load(Ordering::SeqCst))
}
@ -35,13 +65,19 @@ impl<T: HasPyProtoRegistry> PyProtoMethods for T {
#[doc(hidden)]
pub struct PyProtoRegistry {
// Basic Protocols
/// Basic protocols.
basic_methods: AtomicPtr<PyObjectMethods>,
// Buffer Protocols
/// Buffer protocols.
buffer_methods: AtomicPtr<PyBufferProcs>,
// Descr Protocols
/// Descr pProtocols.
descr_methods: AtomicPtr<PyDescrMethods>,
// Iterator Protocols
/// GC protocols.
gc_methods: AtomicPtr<PyGCMethods>,
/// Mapping protocols.
mapping_methods: AtomicPtr<PyMappingMethods>,
/// Number protocols.
number_methods: AtomicPtr<PyNumberMethods>,
/// Iterator protocols.
iter_methods: AtomicPtr<PyIterMethods>,
}
@ -51,6 +87,9 @@ impl PyProtoRegistry {
basic_methods: AtomicPtr::new(ptr::null_mut()),
buffer_methods: AtomicPtr::new(ptr::null_mut()),
descr_methods: AtomicPtr::new(ptr::null_mut()),
gc_methods: AtomicPtr::new(ptr::null_mut()),
mapping_methods: AtomicPtr::new(ptr::null_mut()),
number_methods: AtomicPtr::new(ptr::null_mut()),
iter_methods: AtomicPtr::new(ptr::null_mut()),
}
}
@ -66,6 +105,18 @@ impl PyProtoRegistry {
self.descr_methods
.store(Box::into_raw(Box::new(methods)), Ordering::SeqCst)
}
pub fn set_gc_methods(&self, methods: PyGCMethods) {
self.gc_methods
.store(Box::into_raw(Box::new(methods)), Ordering::SeqCst)
}
pub fn set_mapping_methods(&self, methods: PyMappingMethods) {
self.mapping_methods
.store(Box::into_raw(Box::new(methods)), Ordering::SeqCst)
}
pub fn set_number_methods(&self, methods: PyNumberMethods) {
self.number_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)

View file

@ -138,21 +138,23 @@ where
}
// GC support
<T as class::gc::PyGCProtocolImpl>::update_type_object(type_object);
if let Some(gc) = T::gc_methods() {
unsafe { gc.as_ref() }.update_typeobj(type_object);
}
// descriptor protocol
if let Some(descr) = T::descr_methods() {
unsafe { descr.as_ref() }.prepare_type_obj(type_object);
unsafe { descr.as_ref() }.update_typeobj(type_object);
}
// iterator methods
if let Some(iter) = T::iter_methods() {
unsafe { iter.as_ref() }.prepare_type_obj(type_object);
unsafe { iter.as_ref() }.update_typeobj(type_object);
}
// basic methods
if let Some(basic) = T::basic_methods() {
unsafe { basic.as_ref() }.prepare_type_obj(type_object);
unsafe { basic.as_ref() }.update_typeobj(type_object);
}
fn to_ptr<T>(value: Option<T>) -> *mut T {
@ -162,10 +164,9 @@ where
}
// number methods
type_object.tp_as_number = to_ptr(<T as class::number::PyNumberProtocolImpl>::tp_as_number());
type_object.tp_as_number = T::number_methods().map_or_else(ptr::null_mut, |p| p.as_ptr());
// mapping methods
type_object.tp_as_mapping =
to_ptr(<T as class::mapping::PyMappingProtocolImpl>::tp_as_mapping());
type_object.tp_as_mapping = T::mapping_methods().map_or_else(ptr::null_mut, |p| p.as_ptr());
// sequence methods
type_object.tp_as_sequence =
to_ptr(<T as class::sequence::PySequenceProtocolImpl>::tp_as_sequence());