mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
PyWrapperDescrObject and rewrite toggle_slot (#6536)
* SlotFunc * slotdef * unify slots * remove unsed slots
This commit is contained in:
@@ -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
|
||||
|
||||
1
Lib/test/test_descr.py
vendored
1
Lib/test/test_descr.py
vendored
@@ -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
|
||||
|
||||
4
Lib/test/test_inspect/test_inspect.py
vendored
4
Lib/test/test_inspect/test_inspect.py
vendored
@@ -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',
|
||||
|
||||
2
Lib/test/test_sqlite3/test_factory.py
vendored
2
Lib/test/test_sqlite3/test_factory.py
vendored
@@ -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
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)),
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
1465
crates/vm/src/types/slot_defs.rs
Normal file
1465
crates/vm/src/types/slot_defs.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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(),
|
||||
|
||||
Reference in New Issue
Block a user