PyWrapperDescrObject and rewrite toggle_slot (#6536)

* SlotFunc

* slotdef

* unify slots

* remove unsed slots
This commit is contained in:
Jeong, YunWon
2025-12-28 11:44:36 +09:00
committed by GitHub
parent 7edc3bba5d
commit 527111bc98
18 changed files with 2561 additions and 1152 deletions

View File

@@ -1,6 +1,7 @@
argtypes
asdl
asname
attro
augassign
badcert
badsyntax
@@ -50,6 +51,7 @@ prec
preinitialized
pythonw
PYTHREAD_NAME
releasebuffer
SA_ONSTACK
SOABI
stackdepth

View File

@@ -1399,7 +1399,6 @@ class ClassPropertiesAndMethods(unittest.TestCase, ExtraAssertions):
__qualname__ = object()
__slots__ = ["__qualname__"]
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_slots_descriptor(self):
# Issue2115: slot descriptors did not correctly check
# the type of the given object

View File

@@ -2126,8 +2126,6 @@ class TestIsMethodDescriptor(unittest.TestCase):
self.assertFalse(inspect.ismethoddescriptor(MethodDescriptorSub))
self.assertFalse(inspect.ismethoddescriptor(DataDescriptorSub))
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_builtin_descriptors(self):
builtin_slot_wrapper = int.__add__ # This one is mentioned in docs.
class Owner:
@@ -2217,8 +2215,6 @@ class TestIsDataDescriptor(unittest.TestCase):
self.assertTrue(inspect.isdatadescriptor(DataDescriptor2()),
'class with __set__ = None is a data descriptor')
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_slot(self):
class Slotted:
__slots__ = 'foo',

View File

@@ -241,8 +241,6 @@ class RowFactoryTests(unittest.TestCase):
self.assertEqual(hash(row_1), hash(row_2))
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_sqlite_row_as_sequence(self):
""" Checks if the row object can act like a sequence """
self.con.row_factory = sqlite.Row

View File

@@ -884,8 +884,6 @@ class SpecSignatureTest(unittest.TestCase):
a.f.assert_called_with(self=10)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_autospec_data_descriptor(self):
class Descriptor(object):
def __init__(self, value):

View File

@@ -126,10 +126,10 @@ impl PyBool {
.and_then(|format_spec| format_spec.format_bool(new_bool))
.map_err(|err| err.into_pyexception(vm))
}
}
#[pymethod(name = "__ror__")]
#[pymethod]
fn __or__(lhs: PyObjectRef, rhs: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef {
impl PyBool {
pub(crate) fn __or__(lhs: PyObjectRef, rhs: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef {
if lhs.fast_isinstance(vm.ctx.types.bool_type)
&& rhs.fast_isinstance(vm.ctx.types.bool_type)
{
@@ -143,9 +143,7 @@ impl PyBool {
}
}
#[pymethod(name = "__rand__")]
#[pymethod]
fn __and__(lhs: PyObjectRef, rhs: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef {
pub(crate) fn __and__(lhs: PyObjectRef, rhs: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef {
if lhs.fast_isinstance(vm.ctx.types.bool_type)
&& rhs.fast_isinstance(vm.ctx.types.bool_type)
{
@@ -159,9 +157,7 @@ impl PyBool {
}
}
#[pymethod(name = "__rxor__")]
#[pymethod]
fn __xor__(lhs: PyObjectRef, rhs: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef {
pub(crate) fn __xor__(lhs: PyObjectRef, rhs: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef {
if lhs.fast_isinstance(vm.ctx.types.bool_type)
&& rhs.fast_isinstance(vm.ctx.types.bool_type)
{

View File

@@ -5,11 +5,7 @@ use crate::{
class::PyClassImpl,
common::format::FormatSpec,
convert::{IntoPyException, ToPyObject, ToPyResult},
function::{
FuncArgs, OptionalArg, OptionalOption,
PyArithmeticValue::{self, *},
PyComparisonValue,
},
function::{FuncArgs, OptionalArg, PyComparisonValue},
protocol::PyNumberMethods,
stdlib::warnings,
types::{AsNumber, Comparable, Constructor, Hashable, PyComparisonOp, Representable},
@@ -268,133 +264,11 @@ impl PyComplex {
self.value.im
}
#[pymethod]
fn __abs__(&self, vm: &VirtualMachine) -> PyResult<f64> {
let Complex64 { im, re } = self.value;
let is_finite = im.is_finite() && re.is_finite();
let abs_result = re.hypot(im);
if is_finite && abs_result.is_infinite() {
Err(vm.new_overflow_error("absolute value too large"))
} else {
Ok(abs_result)
}
}
#[inline]
fn op<F>(
&self,
other: PyObjectRef,
op: F,
vm: &VirtualMachine,
) -> PyResult<PyArithmeticValue<Complex64>>
where
F: Fn(Complex64, Complex64) -> PyResult<Complex64>,
{
to_op_complex(&other, vm)?.map_or_else(
|| Ok(NotImplemented),
|other| Ok(Implemented(op(self.value, other)?)),
)
}
#[pymethod(name = "__radd__")]
#[pymethod]
fn __add__(
&self,
other: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<PyArithmeticValue<Complex64>> {
self.op(other, |a, b| Ok(a + b), vm)
}
#[pymethod]
fn __sub__(
&self,
other: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<PyArithmeticValue<Complex64>> {
self.op(other, |a, b| Ok(a - b), vm)
}
#[pymethod]
fn __rsub__(
&self,
other: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<PyArithmeticValue<Complex64>> {
self.op(other, |a, b| Ok(b - a), vm)
}
#[pymethod]
fn conjugate(&self) -> Complex64 {
self.value.conj()
}
#[pymethod(name = "__rmul__")]
#[pymethod]
fn __mul__(
&self,
other: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<PyArithmeticValue<Complex64>> {
self.op(other, |a, b| Ok(a * b), vm)
}
#[pymethod]
fn __truediv__(
&self,
other: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<PyArithmeticValue<Complex64>> {
self.op(other, |a, b| inner_div(a, b, vm), vm)
}
#[pymethod]
fn __rtruediv__(
&self,
other: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<PyArithmeticValue<Complex64>> {
self.op(other, |a, b| inner_div(b, a, vm), vm)
}
#[pymethod]
const fn __pos__(&self) -> Complex64 {
self.value
}
#[pymethod]
fn __neg__(&self) -> Complex64 {
-self.value
}
#[pymethod]
fn __pow__(
&self,
other: PyObjectRef,
mod_val: OptionalOption<PyObjectRef>,
vm: &VirtualMachine,
) -> PyResult<PyArithmeticValue<Complex64>> {
if mod_val.flatten().is_some() {
Err(vm.new_value_error("complex modulo not allowed"))
} else {
self.op(other, |a, b| inner_pow(a, b, vm), vm)
}
}
#[pymethod]
fn __rpow__(
&self,
other: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<PyArithmeticValue<Complex64>> {
self.op(other, |a, b| inner_pow(b, a, vm), vm)
}
#[pymethod]
fn __bool__(&self) -> bool {
!Complex64::is_zero(&self.value)
}
#[pymethod]
const fn __getnewargs__(&self) -> (f64, f64) {
let Complex64 { re, im } = self.value;
@@ -489,7 +363,12 @@ impl AsNumber for PyComplex {
}),
absolute: Some(|number, vm| {
let value = PyComplex::number_downcast(number).value;
value.norm().to_pyresult(vm)
let result = value.norm();
// Check for overflow: hypot returns inf for finite inputs that overflow
if result.is_infinite() && value.re.is_finite() && value.im.is_finite() {
return Err(vm.new_overflow_error("absolute value too large".to_owned()));
}
result.to_pyresult(vm)
}),
boolean: Some(|number, _vm| Ok(!PyComplex::number_downcast(number).value.is_zero())),
true_divide: Some(|a, b, vm| PyComplex::number_op(a, b, inner_div, vm)),

View File

@@ -4,11 +4,15 @@ use crate::{
builtins::{PyTypeRef, builtin_func::PyNativeMethod, type_},
class::PyClassImpl,
common::hash::PyHash,
convert::ToPyResult,
convert::{ToPyObject, ToPyResult},
function::{FuncArgs, PyMethodDef, PyMethodFlags, PySetterValue},
protocol::{PyNumberBinaryFunc, PyNumberTernaryFunc, PyNumberUnaryFunc},
types::{
Callable, Comparable, GetDescriptor, HashFunc, Hashable, InitFunc, IterFunc, IterNextFunc,
PyComparisonOp, Representable, StringifyFunc,
Callable, Comparable, DelFunc, DescrGetFunc, DescrSetFunc, GenericMethod, GetDescriptor,
GetattroFunc, HashFunc, Hashable, InitFunc, IterFunc, IterNextFunc, MapAssSubscriptFunc,
MapLenFunc, MapSubscriptFunc, PyComparisonOp, Representable, RichCompareFunc,
SeqAssItemFunc, SeqConcatFunc, SeqContainsFunc, SeqItemFunc, SeqLenFunc, SeqRepeatFunc,
SetattroFunc, StringifyFunc,
},
};
use rustpython_common::lock::PyRwLock;
@@ -387,22 +391,58 @@ impl GetDescriptor for PyMemberDescriptor {
pub fn init(ctx: &Context) {
PyMemberDescriptor::extend_class(ctx, ctx.types.member_descriptor_type);
PyMethodDescriptor::extend_class(ctx, ctx.types.method_descriptor_type);
PySlotWrapper::extend_class(ctx, ctx.types.wrapper_descriptor_type);
PyWrapper::extend_class(ctx, ctx.types.wrapper_descriptor_type);
PyMethodWrapper::extend_class(ctx, ctx.types.method_wrapper_type);
}
// PySlotWrapper - wrapper_descriptor
// PyWrapper - wrapper_descriptor
/// Type-erased slot function - mirrors CPython's void* d_wrapped
/// Each variant knows how to call the wrapped function with proper types
#[derive(Clone, Copy)]
pub enum SlotFunc {
// Basic slots
Init(InitFunc),
Hash(HashFunc),
Str(StringifyFunc),
Repr(StringifyFunc),
Iter(IterFunc),
IterNext(IterNextFunc),
Call(GenericMethod),
Del(DelFunc),
// Attribute access slots
GetAttro(GetattroFunc),
SetAttro(SetattroFunc), // __setattr__
DelAttro(SetattroFunc), // __delattr__ (same func type, different PySetterValue)
// Rich comparison slots (with comparison op)
RichCompare(RichCompareFunc, PyComparisonOp),
// Descriptor slots
DescrGet(DescrGetFunc),
DescrSet(DescrSetFunc), // __set__
DescrDel(DescrSetFunc), // __delete__ (same func type, different PySetterValue)
// Sequence sub-slots (sq_*)
SeqLength(SeqLenFunc),
SeqConcat(SeqConcatFunc),
SeqRepeat(SeqRepeatFunc),
SeqItem(SeqItemFunc),
SeqAssItem(SeqAssItemFunc),
SeqContains(SeqContainsFunc),
// Mapping sub-slots (mp_*)
MapLength(MapLenFunc),
MapSubscript(MapSubscriptFunc),
MapAssSubscript(MapAssSubscriptFunc),
// Number sub-slots (nb_*) - grouped by signature
NumBoolean(PyNumberUnaryFunc<bool>), // __bool__
NumUnary(PyNumberUnaryFunc), // __int__, __float__, __index__
NumBinary(PyNumberBinaryFunc), // __add__, __sub__, __mul__, etc.
NumBinaryRight(PyNumberBinaryFunc), // __radd__, __rsub__, etc. (swapped args)
NumTernary(PyNumberTernaryFunc), // __pow__
NumTernaryRight(PyNumberTernaryFunc), // __rpow__ (swapped first two args)
}
impl std::fmt::Debug for SlotFunc {
@@ -414,6 +454,33 @@ impl std::fmt::Debug for SlotFunc {
SlotFunc::Repr(_) => write!(f, "SlotFunc::Repr(...)"),
SlotFunc::Iter(_) => write!(f, "SlotFunc::Iter(...)"),
SlotFunc::IterNext(_) => write!(f, "SlotFunc::IterNext(...)"),
SlotFunc::Call(_) => write!(f, "SlotFunc::Call(...)"),
SlotFunc::Del(_) => write!(f, "SlotFunc::Del(...)"),
SlotFunc::GetAttro(_) => write!(f, "SlotFunc::GetAttro(...)"),
SlotFunc::SetAttro(_) => write!(f, "SlotFunc::SetAttro(...)"),
SlotFunc::DelAttro(_) => write!(f, "SlotFunc::DelAttro(...)"),
SlotFunc::RichCompare(_, op) => write!(f, "SlotFunc::RichCompare(..., {:?})", op),
SlotFunc::DescrGet(_) => write!(f, "SlotFunc::DescrGet(...)"),
SlotFunc::DescrSet(_) => write!(f, "SlotFunc::DescrSet(...)"),
SlotFunc::DescrDel(_) => write!(f, "SlotFunc::DescrDel(...)"),
// Sequence sub-slots
SlotFunc::SeqLength(_) => write!(f, "SlotFunc::SeqLength(...)"),
SlotFunc::SeqConcat(_) => write!(f, "SlotFunc::SeqConcat(...)"),
SlotFunc::SeqRepeat(_) => write!(f, "SlotFunc::SeqRepeat(...)"),
SlotFunc::SeqItem(_) => write!(f, "SlotFunc::SeqItem(...)"),
SlotFunc::SeqAssItem(_) => write!(f, "SlotFunc::SeqAssItem(...)"),
SlotFunc::SeqContains(_) => write!(f, "SlotFunc::SeqContains(...)"),
// Mapping sub-slots
SlotFunc::MapLength(_) => write!(f, "SlotFunc::MapLength(...)"),
SlotFunc::MapSubscript(_) => write!(f, "SlotFunc::MapSubscript(...)"),
SlotFunc::MapAssSubscript(_) => write!(f, "SlotFunc::MapAssSubscript(...)"),
// Number sub-slots
SlotFunc::NumBoolean(_) => write!(f, "SlotFunc::NumBoolean(...)"),
SlotFunc::NumUnary(_) => write!(f, "SlotFunc::NumUnary(...)"),
SlotFunc::NumBinary(_) => write!(f, "SlotFunc::NumBinary(...)"),
SlotFunc::NumBinaryRight(_) => write!(f, "SlotFunc::NumBinaryRight(...)"),
SlotFunc::NumTernary(_) => write!(f, "SlotFunc::NumTernary(...)"),
SlotFunc::NumTernaryRight(_) => write!(f, "SlotFunc::NumTernaryRight(...)"),
}
}
}
@@ -463,6 +530,133 @@ impl SlotFunc {
}
func(&obj, vm).to_pyresult(vm)
}
SlotFunc::Call(func) => func(&obj, args, vm),
SlotFunc::Del(func) => {
if !args.args.is_empty() || !args.kwargs.is_empty() {
return Err(
vm.new_type_error("__del__() takes no arguments (1 given)".to_owned())
);
}
func(&obj, vm)?;
Ok(vm.ctx.none())
}
SlotFunc::GetAttro(func) => {
let (name,): (PyRef<PyStr>,) = args.bind(vm)?;
func(&obj, &name, vm)
}
SlotFunc::SetAttro(func) => {
let (name, value): (PyRef<PyStr>, PyObjectRef) = args.bind(vm)?;
func(&obj, &name, PySetterValue::Assign(value), vm)?;
Ok(vm.ctx.none())
}
SlotFunc::DelAttro(func) => {
let (name,): (PyRef<PyStr>,) = args.bind(vm)?;
func(&obj, &name, PySetterValue::Delete, vm)?;
Ok(vm.ctx.none())
}
SlotFunc::RichCompare(func, op) => {
let (other,): (PyObjectRef,) = args.bind(vm)?;
func(&obj, &other, *op, vm).map(|r| match r {
crate::function::Either::A(obj) => obj,
crate::function::Either::B(cmp_val) => cmp_val.to_pyobject(vm),
})
}
SlotFunc::DescrGet(func) => {
let (instance, owner): (PyObjectRef, crate::function::OptionalArg<PyObjectRef>) =
args.bind(vm)?;
let owner = owner.into_option();
let instance_opt = if vm.is_none(&instance) {
None
} else {
Some(instance)
};
func(obj, instance_opt, owner, vm)
}
SlotFunc::DescrSet(func) => {
let (instance, value): (PyObjectRef, PyObjectRef) = args.bind(vm)?;
func(&obj, instance, PySetterValue::Assign(value), vm)?;
Ok(vm.ctx.none())
}
SlotFunc::DescrDel(func) => {
let (instance,): (PyObjectRef,) = args.bind(vm)?;
func(&obj, instance, PySetterValue::Delete, vm)?;
Ok(vm.ctx.none())
}
// Sequence sub-slots
SlotFunc::SeqLength(func) => {
args.bind::<()>(vm)?;
let len = func(obj.sequence_unchecked(), vm)?;
Ok(vm.ctx.new_int(len).into())
}
SlotFunc::SeqConcat(func) => {
let (other,): (PyObjectRef,) = args.bind(vm)?;
func(obj.sequence_unchecked(), &other, vm)
}
SlotFunc::SeqRepeat(func) => {
let (n,): (isize,) = args.bind(vm)?;
func(obj.sequence_unchecked(), n, vm)
}
SlotFunc::SeqItem(func) => {
let (index,): (isize,) = args.bind(vm)?;
func(obj.sequence_unchecked(), index, vm)
}
SlotFunc::SeqAssItem(func) => {
let (index, value): (isize, crate::function::OptionalArg<PyObjectRef>) =
args.bind(vm)?;
func(obj.sequence_unchecked(), index, value.into_option(), vm)?;
Ok(vm.ctx.none())
}
SlotFunc::SeqContains(func) => {
let (item,): (PyObjectRef,) = args.bind(vm)?;
let result = func(obj.sequence_unchecked(), &item, vm)?;
Ok(vm.ctx.new_bool(result).into())
}
// Mapping sub-slots
SlotFunc::MapLength(func) => {
args.bind::<()>(vm)?;
let len = func(obj.mapping_unchecked(), vm)?;
Ok(vm.ctx.new_int(len).into())
}
SlotFunc::MapSubscript(func) => {
let (key,): (PyObjectRef,) = args.bind(vm)?;
func(obj.mapping_unchecked(), &key, vm)
}
SlotFunc::MapAssSubscript(func) => {
let (key, value): (PyObjectRef, crate::function::OptionalArg<PyObjectRef>) =
args.bind(vm)?;
func(obj.mapping_unchecked(), &key, value.into_option(), vm)?;
Ok(vm.ctx.none())
}
// Number sub-slots
SlotFunc::NumBoolean(func) => {
args.bind::<()>(vm)?;
let result = func(obj.number(), vm)?;
Ok(vm.ctx.new_bool(result).into())
}
SlotFunc::NumUnary(func) => {
args.bind::<()>(vm)?;
func(obj.number(), vm)
}
SlotFunc::NumBinary(func) => {
let (other,): (PyObjectRef,) = args.bind(vm)?;
func(&obj, &other, vm)
}
SlotFunc::NumBinaryRight(func) => {
let (other,): (PyObjectRef,) = args.bind(vm)?;
func(&other, &obj, vm) // Swapped: other op obj
}
SlotFunc::NumTernary(func) => {
let (y, z): (PyObjectRef, crate::function::OptionalArg<PyObjectRef>) =
args.bind(vm)?;
let z = z.unwrap_or_else(|| vm.ctx.none());
func(&obj, &y, &z, vm)
}
SlotFunc::NumTernaryRight(func) => {
let (y, z): (PyObjectRef, crate::function::OptionalArg<PyObjectRef>) =
args.bind(vm)?;
let z = z.unwrap_or_else(|| vm.ctx.none());
func(&y, &obj, &z, vm) // Swapped: y ** obj % z
}
}
}
}
@@ -471,20 +665,20 @@ impl SlotFunc {
// = PyWrapperDescrObject
#[pyclass(name = "wrapper_descriptor", module = false)]
#[derive(Debug)]
pub struct PySlotWrapper {
pub struct PyWrapper {
pub typ: &'static Py<PyType>,
pub name: &'static PyStrInterned,
pub wrapped: SlotFunc,
pub doc: Option<&'static str>,
}
impl PyPayload for PySlotWrapper {
impl PyPayload for PyWrapper {
fn class(ctx: &Context) -> &'static Py<PyType> {
ctx.types.wrapper_descriptor_type
}
}
impl GetDescriptor for PySlotWrapper {
impl GetDescriptor for PyWrapper {
fn descr_get(
zelf: PyObjectRef,
obj: Option<PyObjectRef>,
@@ -501,7 +695,7 @@ impl GetDescriptor for PySlotWrapper {
}
}
impl Callable for PySlotWrapper {
impl Callable for PyWrapper {
type Args = FuncArgs;
fn call(zelf: &Py<Self>, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
@@ -525,7 +719,7 @@ impl Callable for PySlotWrapper {
with(GetDescriptor, Callable, Representable),
flags(DISALLOW_INSTANTIATION)
)]
impl PySlotWrapper {
impl PyWrapper {
#[pygetset]
fn __name__(&self) -> &'static PyStrInterned {
self.name
@@ -547,7 +741,7 @@ impl PySlotWrapper {
}
}
impl Representable for PySlotWrapper {
impl Representable for PyWrapper {
#[inline]
fn repr_str(zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<String> {
Ok(format!(
@@ -565,7 +759,7 @@ impl Representable for PySlotWrapper {
#[pyclass(name = "method-wrapper", module = false, traverse)]
#[derive(Debug)]
pub struct PyMethodWrapper {
pub wrapper: PyRef<PySlotWrapper>,
pub wrapper: PyRef<PyWrapper>,
#[pytraverse(skip)]
pub obj: PyObjectRef,
}

View File

@@ -8,8 +8,7 @@ use crate::{
common::{float_ops, format::FormatSpec, hash},
convert::{IntoPyException, ToPyObject, ToPyResult},
function::{
ArgBytesLike, FuncArgs, OptionalArg, OptionalOption,
PyArithmeticValue::{self, *},
ArgBytesLike, FuncArgs, OptionalArg, OptionalOption, PyArithmeticValue::*,
PyComparisonValue,
},
protocol::PyNumberMethods,
@@ -239,182 +238,6 @@ impl PyFloat {
.to_owned())
}
#[pymethod]
const fn __abs__(&self) -> f64 {
self.value.abs()
}
#[inline]
fn simple_op<F>(
&self,
other: PyObjectRef,
op: F,
vm: &VirtualMachine,
) -> PyResult<PyArithmeticValue<f64>>
where
F: Fn(f64, f64) -> PyResult<f64>,
{
to_op_float(&other, vm)?.map_or_else(
|| Ok(NotImplemented),
|other| Ok(Implemented(op(self.value, other)?)),
)
}
#[inline]
fn complex_op<F>(&self, other: PyObjectRef, op: F, vm: &VirtualMachine) -> PyResult
where
F: Fn(f64, f64) -> PyResult,
{
to_op_float(&other, vm)?.map_or_else(
|| Ok(vm.ctx.not_implemented()),
|other| op(self.value, other),
)
}
#[inline]
fn tuple_op<F>(
&self,
other: PyObjectRef,
op: F,
vm: &VirtualMachine,
) -> PyResult<PyArithmeticValue<(f64, f64)>>
where
F: Fn(f64, f64) -> PyResult<(f64, f64)>,
{
to_op_float(&other, vm)?.map_or_else(
|| Ok(NotImplemented),
|other| Ok(Implemented(op(self.value, other)?)),
)
}
#[pymethod(name = "__radd__")]
#[pymethod]
fn __add__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyArithmeticValue<f64>> {
self.simple_op(other, |a, b| Ok(a + b), vm)
}
#[pymethod]
const fn __bool__(&self) -> bool {
self.value != 0.0
}
#[pymethod]
fn __divmod__(
&self,
other: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<PyArithmeticValue<(f64, f64)>> {
self.tuple_op(other, |a, b| inner_divmod(a, b, vm), vm)
}
#[pymethod]
fn __rdivmod__(
&self,
other: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<PyArithmeticValue<(f64, f64)>> {
self.tuple_op(other, |a, b| inner_divmod(b, a, vm), vm)
}
#[pymethod]
fn __floordiv__(
&self,
other: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<PyArithmeticValue<f64>> {
self.simple_op(other, |a, b| inner_floordiv(a, b, vm), vm)
}
#[pymethod]
fn __rfloordiv__(
&self,
other: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<PyArithmeticValue<f64>> {
self.simple_op(other, |a, b| inner_floordiv(b, a, vm), vm)
}
#[pymethod(name = "__mod__")]
fn mod_(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyArithmeticValue<f64>> {
self.simple_op(other, |a, b| inner_mod(a, b, vm), vm)
}
#[pymethod]
fn __rmod__(
&self,
other: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<PyArithmeticValue<f64>> {
self.simple_op(other, |a, b| inner_mod(b, a, vm), vm)
}
#[pymethod]
const fn __pos__(&self) -> f64 {
self.value
}
#[pymethod]
const fn __neg__(&self) -> f64 {
-self.value
}
#[pymethod]
fn __pow__(
&self,
other: PyObjectRef,
mod_val: OptionalOption<PyObjectRef>,
vm: &VirtualMachine,
) -> PyResult {
if mod_val.flatten().is_some() {
Err(vm.new_type_error("floating point pow() does not accept a 3rd argument"))
} else {
self.complex_op(other, |a, b| float_pow(a, b, vm), vm)
}
}
#[pymethod]
fn __rpow__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
self.complex_op(other, |a, b| float_pow(b, a, vm), vm)
}
#[pymethod]
fn __sub__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyArithmeticValue<f64>> {
self.simple_op(other, |a, b| Ok(a - b), vm)
}
#[pymethod]
fn __rsub__(
&self,
other: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<PyArithmeticValue<f64>> {
self.simple_op(other, |a, b| Ok(b - a), vm)
}
#[pymethod]
fn __truediv__(
&self,
other: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<PyArithmeticValue<f64>> {
self.simple_op(other, |a, b| inner_div(a, b, vm), vm)
}
#[pymethod]
fn __rtruediv__(
&self,
other: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<PyArithmeticValue<f64>> {
self.simple_op(other, |a, b| inner_div(b, a, vm), vm)
}
#[pymethod(name = "__rmul__")]
#[pymethod]
fn __mul__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyArithmeticValue<f64>> {
self.simple_op(other, |a, b| Ok(a * b), vm)
}
#[pymethod]
fn __trunc__(&self, vm: &VirtualMachine) -> PyResult<BigInt> {
try_to_bigint(self.value, vm)
@@ -460,16 +283,6 @@ impl PyFloat {
Ok(value)
}
#[pymethod]
fn __int__(&self, vm: &VirtualMachine) -> PyResult<BigInt> {
self.__trunc__(vm)
}
#[pymethod]
const fn __float__(zelf: PyRef<Self>) -> PyRef<Self> {
zelf
}
#[pygetset]
const fn real(zelf: PyRef<Self>) -> PyRef<Self> {
zelf

View File

@@ -12,8 +12,7 @@ use crate::{
},
convert::{IntoPyException, ToPyObject, ToPyResult},
function::{
ArgByteOrder, ArgIntoBool, FuncArgs, OptionalArg, OptionalOption, PyArithmeticValue,
PyComparisonValue,
ArgByteOrder, ArgIntoBool, FuncArgs, OptionalArg, PyArithmeticValue, PyComparisonValue,
},
protocol::{PyNumberMethods, handle_bytes_to_int_err},
types::{AsNumber, Comparable, Constructor, Hashable, PyComparisonOp, Representable},
@@ -325,83 +324,15 @@ impl PyInt {
with(PyRef, Comparable, Hashable, Constructor, AsNumber, Representable)
)]
impl PyInt {
#[pymethod(name = "__radd__")]
#[pymethod]
fn __add__(&self, other: PyObjectRef) -> PyArithmeticValue<BigInt> {
self.int_op(other, |a, b| a + b)
}
#[pymethod]
fn __sub__(&self, other: PyObjectRef) -> PyArithmeticValue<BigInt> {
self.int_op(other, |a, b| a - b)
}
#[pymethod]
fn __rsub__(&self, other: PyObjectRef) -> PyArithmeticValue<BigInt> {
self.int_op(other, |a, b| b - a)
}
#[pymethod(name = "__rmul__")]
#[pymethod]
fn __mul__(&self, other: PyObjectRef) -> PyArithmeticValue<BigInt> {
self.int_op(other, |a, b| a * b)
}
#[pymethod]
fn __truediv__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
self.general_op(other, |a, b| inner_truediv(a, b, vm), vm)
}
#[pymethod]
fn __rtruediv__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
self.general_op(other, |a, b| inner_truediv(b, a, vm), vm)
}
#[pymethod]
fn __floordiv__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
self.general_op(other, |a, b| inner_floordiv(a, b, vm), vm)
}
#[pymethod]
fn __rfloordiv__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
self.general_op(other, |a, b| inner_floordiv(b, a, vm), vm)
}
#[pymethod]
fn __lshift__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
self.general_op(other, |a, b| inner_lshift(a, b, vm), vm)
}
#[pymethod]
fn __rlshift__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
self.general_op(other, |a, b| inner_lshift(b, a, vm), vm)
}
#[pymethod]
fn __rshift__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
self.general_op(other, |a, b| inner_rshift(a, b, vm), vm)
}
#[pymethod]
fn __rrshift__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
self.general_op(other, |a, b| inner_rshift(b, a, vm), vm)
}
#[pymethod(name = "__rxor__")]
#[pymethod]
pub fn __xor__(&self, other: PyObjectRef) -> PyArithmeticValue<BigInt> {
pub(crate) fn __xor__(&self, other: PyObjectRef) -> PyArithmeticValue<BigInt> {
self.int_op(other, |a, b| a ^ b)
}
#[pymethod(name = "__ror__")]
#[pymethod]
pub fn __or__(&self, other: PyObjectRef) -> PyArithmeticValue<BigInt> {
pub(crate) fn __or__(&self, other: PyObjectRef) -> PyArithmeticValue<BigInt> {
self.int_op(other, |a, b| a | b)
}
#[pymethod(name = "__rand__")]
#[pymethod]
pub fn __and__(&self, other: PyObjectRef) -> PyArithmeticValue<BigInt> {
pub(crate) fn __and__(&self, other: PyObjectRef) -> PyArithmeticValue<BigInt> {
self.int_op(other, |a, b| a & b)
}
@@ -447,54 +378,6 @@ impl PyInt {
)
}
#[pymethod]
fn __pow__(
&self,
other: PyObjectRef,
r#mod: OptionalOption<PyObjectRef>,
vm: &VirtualMachine,
) -> PyResult {
match r#mod.flatten() {
Some(modulus) => self.modpow(other, modulus, vm),
None => self.general_op(other, |a, b| inner_pow(a, b, vm), vm),
}
}
#[pymethod]
fn __rpow__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
self.general_op(other, |a, b| inner_pow(b, a, vm), vm)
}
#[pymethod(name = "__mod__")]
fn mod_(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
self.general_op(other, |a, b| inner_mod(a, b, vm), vm)
}
#[pymethod]
fn __rmod__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
self.general_op(other, |a, b| inner_mod(b, a, vm), vm)
}
#[pymethod]
fn __divmod__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
self.general_op(other, |a, b| inner_divmod(a, b, vm), vm)
}
#[pymethod]
fn __rdivmod__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
self.general_op(other, |a, b| inner_divmod(b, a, vm), vm)
}
#[pymethod]
fn __neg__(&self) -> BigInt {
-(&self.value)
}
#[pymethod]
fn __abs__(&self) -> BigInt {
self.value.abs()
}
#[pymethod]
fn __round__(
zelf: PyRef<Self>,
@@ -537,16 +420,6 @@ impl PyInt {
Ok(zelf)
}
#[pymethod]
fn __pos__(&self) -> BigInt {
self.value.clone()
}
#[pymethod]
fn __float__(&self, vm: &VirtualMachine) -> PyResult<f64> {
try_to_float(&self.value, vm)
}
#[pymethod]
fn __trunc__(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyRefExact<Self> {
zelf.__int__(vm)
@@ -562,16 +435,6 @@ impl PyInt {
zelf.__int__(vm)
}
#[pymethod]
fn __index__(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyRefExact<Self> {
zelf.__int__(vm)
}
#[pymethod]
fn __invert__(&self) -> BigInt {
!(&self.value)
}
#[pymethod]
fn __format__(&self, spec: PyStrRef, vm: &VirtualMachine) -> PyResult<String> {
FormatSpec::parse(spec.as_str())
@@ -579,11 +442,6 @@ impl PyInt {
.map_err(|err| err.into_pyexception(vm))
}
#[pymethod]
fn __bool__(&self) -> bool {
!self.value.is_zero()
}
#[pymethod]
fn __sizeof__(&self) -> usize {
std::mem::size_of::<Self>() + (((self.value.bits() + 7) & !7) / 8) as usize
@@ -706,8 +564,7 @@ impl PyInt {
#[pyclass]
impl PyRef<PyInt> {
#[pymethod]
fn __int__(self, vm: &VirtualMachine) -> PyRefExact<PyInt> {
pub(crate) fn __int__(self, vm: &VirtualMachine) -> PyRefExact<PyInt> {
self.into_exact_or(&vm.ctx, |zelf| unsafe {
// TODO: this is actually safe. we need better interface
PyRefExact::new_unchecked(vm.ctx.new_bigint(&zelf.value))

View File

@@ -26,7 +26,7 @@ use crate::{
protocol::{PyIterReturn, PyNumberMethods},
types::{
AsNumber, Callable, Constructor, GetAttr, Initializer, PyTypeFlags, PyTypeSlots,
Representable, SetAttr, TypeDataRef, TypeDataRefMut, TypeDataSlot,
Representable, SLOT_DEFS, SetAttr, TypeDataRef, TypeDataRefMut, TypeDataSlot,
},
};
use indexmap::{IndexMap, map::Entry};
@@ -464,173 +464,11 @@ impl PyType {
/// Inherit slots from base type. inherit_slots
pub(crate) fn inherit_slots(&self, base: &Self) {
macro_rules! copyslot {
($slot:ident) => {
if self.slots.$slot.load().is_none() {
if let Some(base_val) = base.slots.$slot.load() {
self.slots.$slot.store(Some(base_val));
}
}
};
// Use SLOT_DEFS to iterate all slots
// Note: as_buffer is handled in inherit_readonly_slots (not AtomicCell)
for def in SLOT_DEFS {
def.accessor.copyslot_if_none(self, base);
}
// Copy init slot only if base actually defines it (not just inherited)
// This is needed for multiple inheritance where a later base might
// have a more specific init slot
macro_rules! copyslot_defined {
($slot:ident) => {
if self.slots.$slot.load().is_none() {
if let Some(base_val) = base.slots.$slot.load() {
// SLOTDEFINED: base->SLOT && (basebase == NULL || base->SLOT != basebase->SLOT)
let basebase = base.base.as_ref();
let slot_defined = match basebase {
None => true,
Some(bb) => bb.slots.$slot.load().map(|v| v as usize)
!= Some(base_val as usize),
};
if slot_defined {
self.slots.$slot.store(Some(base_val));
}
}
}
};
}
// Core slots
copyslot!(hash);
copyslot!(call);
copyslot!(str);
copyslot!(repr);
copyslot!(getattro);
copyslot!(setattro);
copyslot!(richcompare);
copyslot!(iter);
copyslot!(iternext);
copyslot!(descr_get);
copyslot!(descr_set);
// init uses SLOTDEFINED check for multiple inheritance support
copyslot_defined!(init);
copyslot!(del);
// new is handled by set_new()
// as_buffer is inherited at type creation time (not AtomicCell)
// Sub-slots (number, sequence, mapping)
self.inherit_number_slots(base);
self.inherit_sequence_slots(base);
self.inherit_mapping_slots(base);
}
/// Inherit number sub-slots from base type
fn inherit_number_slots(&self, base: &Self) {
macro_rules! copy_num_slot {
($slot:ident) => {
if self.slots.as_number.$slot.load().is_none() {
if let Some(base_val) = base.slots.as_number.$slot.load() {
self.slots.as_number.$slot.store(Some(base_val));
}
}
};
}
// Binary operations
copy_num_slot!(add);
copy_num_slot!(right_add);
copy_num_slot!(inplace_add);
copy_num_slot!(subtract);
copy_num_slot!(right_subtract);
copy_num_slot!(inplace_subtract);
copy_num_slot!(multiply);
copy_num_slot!(right_multiply);
copy_num_slot!(inplace_multiply);
copy_num_slot!(remainder);
copy_num_slot!(right_remainder);
copy_num_slot!(inplace_remainder);
copy_num_slot!(divmod);
copy_num_slot!(right_divmod);
copy_num_slot!(power);
copy_num_slot!(right_power);
copy_num_slot!(inplace_power);
// Bitwise operations
copy_num_slot!(lshift);
copy_num_slot!(right_lshift);
copy_num_slot!(inplace_lshift);
copy_num_slot!(rshift);
copy_num_slot!(right_rshift);
copy_num_slot!(inplace_rshift);
copy_num_slot!(and);
copy_num_slot!(right_and);
copy_num_slot!(inplace_and);
copy_num_slot!(xor);
copy_num_slot!(right_xor);
copy_num_slot!(inplace_xor);
copy_num_slot!(or);
copy_num_slot!(right_or);
copy_num_slot!(inplace_or);
// Division operations
copy_num_slot!(floor_divide);
copy_num_slot!(right_floor_divide);
copy_num_slot!(inplace_floor_divide);
copy_num_slot!(true_divide);
copy_num_slot!(right_true_divide);
copy_num_slot!(inplace_true_divide);
// Matrix multiplication
copy_num_slot!(matrix_multiply);
copy_num_slot!(right_matrix_multiply);
copy_num_slot!(inplace_matrix_multiply);
// Unary operations
copy_num_slot!(negative);
copy_num_slot!(positive);
copy_num_slot!(absolute);
copy_num_slot!(boolean);
copy_num_slot!(invert);
// Conversion
copy_num_slot!(int);
copy_num_slot!(float);
copy_num_slot!(index);
}
/// Inherit sequence sub-slots from base type
fn inherit_sequence_slots(&self, base: &Self) {
macro_rules! copy_seq_slot {
($slot:ident) => {
if self.slots.as_sequence.$slot.load().is_none() {
if let Some(base_val) = base.slots.as_sequence.$slot.load() {
self.slots.as_sequence.$slot.store(Some(base_val));
}
}
};
}
copy_seq_slot!(length);
copy_seq_slot!(concat);
copy_seq_slot!(repeat);
copy_seq_slot!(item);
copy_seq_slot!(ass_item);
copy_seq_slot!(contains);
copy_seq_slot!(inplace_concat);
copy_seq_slot!(inplace_repeat);
}
/// Inherit mapping sub-slots from base type
fn inherit_mapping_slots(&self, base: &Self) {
macro_rules! copy_map_slot {
($slot:ident) => {
if self.slots.as_mapping.$slot.load().is_none() {
if let Some(base_val) = base.slots.as_mapping.$slot.load() {
self.slots.as_mapping.$slot.store(Some(base_val));
}
}
};
}
copy_map_slot!(length);
copy_map_slot!(subscript);
copy_map_slot!(ass_subscript);
}
// This is used for class initialization where the vm is not yet available.

View File

@@ -2,17 +2,60 @@
use crate::{
PyPayload,
builtins::{
PyBaseObject, PyType, PyTypeRef,
descriptor::{PySlotWrapper, SlotFunc},
},
builtins::{PyBaseObject, PyType, PyTypeRef, descriptor::PyWrapper},
function::PyMethodDef,
object::Py,
types::{PyTypeFlags, PyTypeSlots, hash_not_implemented},
types::{PyTypeFlags, PyTypeSlots, SLOT_DEFS, hash_not_implemented},
vm::Context,
};
use rustpython_common::static_cell;
/// Add slot wrapper descriptors to a type's dict
///
/// Iterates SLOT_DEFS and creates a PyWrapper for each slot that:
/// 1. Has a function set in the type's slots
/// 2. Doesn't already have an attribute in the type's dict
pub fn add_operators(class: &'static Py<PyType>, ctx: &Context) {
for def in SLOT_DEFS.iter() {
// Skip __new__ - it has special handling
if def.name == "__new__" {
continue;
}
// Special handling for __hash__ = None
if def.name == "__hash__"
&& class
.slots
.hash
.load()
.is_some_and(|h| h as usize == hash_not_implemented as usize)
{
class.set_attr(ctx.names.__hash__, ctx.none.clone().into());
continue;
}
// Get the slot function wrapped in SlotFunc
let Some(slot_func) = def.accessor.get_slot_func_with_op(&class.slots, def.op) else {
continue;
};
// Check if attribute already exists in dict
let attr_name = ctx.intern_str(def.name);
if class.attributes.read().contains_key(attr_name) {
continue;
}
// Create and add the wrapper
let wrapper = PyWrapper {
typ: class,
name: attr_name,
wrapped: slot_func,
doc: Some(def.doc),
};
class.set_attr(attr_name, wrapper.into_ref(ctx).into());
}
}
pub trait StaticType {
// Ideally, saving PyType is better than PyTypeRef
fn static_cell() -> &'static static_cell::StaticCell<PyTypeRef>;
@@ -140,42 +183,8 @@ pub trait PyClassImpl: PyClassDef {
}
}
// Add slot wrappers for slots that exist and are not already in dict
// This mirrors CPython's add_operators() in typeobject.c
macro_rules! add_slot_wrapper {
($slot:ident, $name:ident, $variant:ident, $doc:expr) => {
if let Some(func) = class.slots.$slot.load() {
let attr_name = identifier!(ctx, $name);
if !class.attributes.read().contains_key(attr_name) {
let wrapper = PySlotWrapper {
typ: class,
name: ctx.intern_str(stringify!($name)),
wrapped: SlotFunc::$variant(func),
doc: Some($doc),
};
class.set_attr(attr_name, wrapper.into_ref(ctx).into());
}
}
};
}
add_slot_wrapper!(
init,
__init__,
Init,
"Initialize self. See help(type(self)) for accurate signature."
);
add_slot_wrapper!(repr, __repr__, Repr, "Return repr(self).");
add_slot_wrapper!(str, __str__, Str, "Return str(self).");
add_slot_wrapper!(iter, __iter__, Iter, "Implement iter(self).");
add_slot_wrapper!(iternext, __next__, IterNext, "Implement next(self).");
// __hash__ needs special handling: hash_not_implemented sets __hash__ = None
if class.slots.hash.load().map_or(0, |h| h as usize) == hash_not_implemented as usize {
class.set_attr(ctx.names.__hash__, ctx.none.clone().into());
} else {
add_slot_wrapper!(hash, __hash__, Hash, "Return hash(self).");
}
// Add slot wrappers using SLOT_DEFS array
add_operators(class, ctx);
// Inherit slots from base types after slots are fully initialized
for base in class.bases.read().iter() {

View File

@@ -12,6 +12,6 @@ pub use iter::{PyIter, PyIterIter, PyIterReturn};
pub use mapping::{PyMapping, PyMappingMethods, PyMappingSlots};
pub use number::{
PyNumber, PyNumberBinaryFunc, PyNumberBinaryOp, PyNumberMethods, PyNumberSlots,
PyNumberTernaryOp, PyNumberUnaryFunc, handle_bytes_to_int_err,
PyNumberTernaryFunc, PyNumberTernaryOp, PyNumberUnaryFunc, handle_bytes_to_int_err,
};
pub use sequence::{PySequence, PySequenceMethods, PySequenceSlots};

View File

@@ -256,6 +256,7 @@ pub struct PyNumberSlots {
pub int: AtomicCell<Option<PyNumberUnaryFunc>>,
pub float: AtomicCell<Option<PyNumberUnaryFunc>>,
// Right variants (internal - not exposed in SlotAccessor)
pub right_add: AtomicCell<Option<PyNumberBinaryFunc>>,
pub right_subtract: AtomicCell<Option<PyNumberBinaryFunc>>,
pub right_multiply: AtomicCell<Option<PyNumberBinaryFunc>>,
@@ -295,8 +296,7 @@ pub struct PyNumberSlots {
impl From<&PyNumberMethods> for PyNumberSlots {
fn from(value: &PyNumberMethods) -> Self {
// right_* functions will use the same left function as PyNumberMethods
// allows both f(self, other) and f(other, self)
// right_* slots use the same function as left ops for native types
Self {
add: AtomicCell::new(value.add),
subtract: AtomicCell::new(value.subtract),
@@ -352,6 +352,115 @@ impl From<&PyNumberMethods> for PyNumberSlots {
}
impl PyNumberSlots {
/// Copy from static PyNumberMethods
pub fn copy_from(&self, methods: &PyNumberMethods) {
if let Some(f) = methods.add {
self.add.store(Some(f));
}
if let Some(f) = methods.subtract {
self.subtract.store(Some(f));
}
if let Some(f) = methods.multiply {
self.multiply.store(Some(f));
}
if let Some(f) = methods.remainder {
self.remainder.store(Some(f));
}
if let Some(f) = methods.divmod {
self.divmod.store(Some(f));
}
if let Some(f) = methods.power {
self.power.store(Some(f));
}
if let Some(f) = methods.negative {
self.negative.store(Some(f));
}
if let Some(f) = methods.positive {
self.positive.store(Some(f));
}
if let Some(f) = methods.absolute {
self.absolute.store(Some(f));
}
if let Some(f) = methods.boolean {
self.boolean.store(Some(f));
}
if let Some(f) = methods.invert {
self.invert.store(Some(f));
}
if let Some(f) = methods.lshift {
self.lshift.store(Some(f));
}
if let Some(f) = methods.rshift {
self.rshift.store(Some(f));
}
if let Some(f) = methods.and {
self.and.store(Some(f));
}
if let Some(f) = methods.xor {
self.xor.store(Some(f));
}
if let Some(f) = methods.or {
self.or.store(Some(f));
}
if let Some(f) = methods.int {
self.int.store(Some(f));
}
if let Some(f) = methods.float {
self.float.store(Some(f));
}
if let Some(f) = methods.inplace_add {
self.inplace_add.store(Some(f));
}
if let Some(f) = methods.inplace_subtract {
self.inplace_subtract.store(Some(f));
}
if let Some(f) = methods.inplace_multiply {
self.inplace_multiply.store(Some(f));
}
if let Some(f) = methods.inplace_remainder {
self.inplace_remainder.store(Some(f));
}
if let Some(f) = methods.inplace_power {
self.inplace_power.store(Some(f));
}
if let Some(f) = methods.inplace_lshift {
self.inplace_lshift.store(Some(f));
}
if let Some(f) = methods.inplace_rshift {
self.inplace_rshift.store(Some(f));
}
if let Some(f) = methods.inplace_and {
self.inplace_and.store(Some(f));
}
if let Some(f) = methods.inplace_xor {
self.inplace_xor.store(Some(f));
}
if let Some(f) = methods.inplace_or {
self.inplace_or.store(Some(f));
}
if let Some(f) = methods.floor_divide {
self.floor_divide.store(Some(f));
}
if let Some(f) = methods.true_divide {
self.true_divide.store(Some(f));
}
if let Some(f) = methods.inplace_floor_divide {
self.inplace_floor_divide.store(Some(f));
}
if let Some(f) = methods.inplace_true_divide {
self.inplace_true_divide.store(Some(f));
}
if let Some(f) = methods.index {
self.index.store(Some(f));
}
if let Some(f) = methods.matrix_multiply {
self.matrix_multiply.store(Some(f));
}
if let Some(f) = methods.inplace_matrix_multiply {
self.inplace_matrix_multiply.store(Some(f));
}
}
pub fn left_binary_op(&self, op_slot: PyNumberBinaryOp) -> Option<PyNumberBinaryFunc> {
use PyNumberBinaryOp::*;
match op_slot {

View File

@@ -1,7 +1,9 @@
mod slot;
pub mod slot_defs;
mod structseq;
mod zoo;
pub use slot::*;
pub use slot_defs::{SLOT_DEFS, SlotAccessor, SlotDef};
pub use structseq::{PyStructSequence, PyStructSequenceData, struct_sequence_new};
pub(crate) use zoo::TypeZoo;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -189,7 +189,7 @@ impl TypeZoo {
generic_alias_type: genericalias::PyGenericAlias::init_builtin_type(),
union_type: union_::PyUnion::init_builtin_type(),
member_descriptor_type: descriptor::PyMemberDescriptor::init_builtin_type(),
wrapper_descriptor_type: descriptor::PySlotWrapper::init_builtin_type(),
wrapper_descriptor_type: descriptor::PyWrapper::init_builtin_type(),
method_wrapper_type: descriptor::PyMethodWrapper::init_builtin_type(),
method_def: crate::function::HeapMethodDef::init_builtin_type(),