Remove specialization from gc/mapping/number protocols
This commit is contained in:
parent
7967874177
commit
0d082961aa
|
@ -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"),
|
||||
],
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
123
src/class/gc.rs
123
src/class/gc.rs
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
1426
src/class/number.rs
1426
src/class/number.rs
File diff suppressed because it is too large
Load diff
|
@ -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)
|
||||
|
|
|
@ -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());
|
||||
|
|
Loading…
Reference in a new issue