Add PyNumberSlots to support right binary ops

This commit is contained in:
Zhiyan Xiao committed 2023-03-09 23:41:48 +09:00
1 parent ba9c354e1b
commit 984db6798c
16 files changed
+611 -434

No files matched your search

+8 -7
View File
@@ -37,7 +37,6 @@ use crate::{
VirtualMachine,
};
use bstr::ByteSlice;
use once_cell::sync::Lazy;
use std::mem::size_of;
#[pyclass(module = false, name = "bytearray", unhashable = true)]
@@ -859,14 +858,16 @@ impl AsSequence for PyByteArray {
impl AsNumber for PyByteArray {
fn as_number() -> &'static PyNumberMethods {
static AS_NUMBER: Lazy<PyNumberMethods> = Lazy::new(|| PyNumberMethods {
remainder: atomic_func!(|number, other, vm| {
PyByteArray::number_downcast(number)
.mod_(other.to_owned(), vm)
.to_pyresult(vm)
static AS_NUMBER: PyNumberMethods = PyNumberMethods {
remainder: Some(|number, other, vm| {
if let Some(number) = number.obj.downcast_ref::<PyByteArray>() {
number.mod_(other.to_owned(), vm).to_pyresult(vm)
} else {
Ok(vm.ctx.not_implemented())
}
}),
..PyNumberMethods::NOT_IMPLEMENTED
});
};
&AS_NUMBER
}
}
+8 -6
View File
@@ -629,14 +629,16 @@ impl AsSequence for PyBytes {
impl AsNumber for PyBytes {
fn as_number() -> &'static PyNumberMethods {
static AS_NUMBER: Lazy<PyNumberMethods> = Lazy::new(|| PyNumberMethods {
remainder: atomic_func!(|number, other, vm| {
PyBytes::number_downcast(number)
.mod_(other.to_owned(), vm)
.to_pyresult(vm)
static AS_NUMBER: PyNumberMethods = PyNumberMethods {
remainder: Some(|number, other, vm| {
if let Some(number) = number.obj.downcast_ref::<PyBytes>() {
number.mod_(other.to_owned(), vm).to_pyresult(vm)
} else {
Ok(vm.ctx.not_implemented())
}
}),
..PyNumberMethods::NOT_IMPLEMENTED
});
};
&AS_NUMBER
}
}
+13 -19
View File
@@ -1,6 +1,5 @@
use super::{float, PyStr, PyType, PyTypeRef};
use crate::{
atomic_func,
class::PyClassImpl,
convert::{ToPyObject, ToPyResult},
function::{
@@ -15,7 +14,6 @@ use crate::{
};
use num_complex::Complex64;
use num_traits::Zero;
use once_cell::sync::Lazy;
use rustpython_common::{float_ops, hash};
use std::num::Wrapping;
@@ -454,38 +452,34 @@ impl Hashable for PyComplex {
impl AsNumber for PyComplex {
fn as_number() -> &'static PyNumberMethods {
static AS_NUMBER: Lazy<PyNumberMethods> = Lazy::new(|| PyNumberMethods {
add: atomic_func!(|number, other, vm| {
static AS_NUMBER: PyNumberMethods = PyNumberMethods {
add: Some(|number, other, vm| {
PyComplex::number_op(number, other, |a, b, _vm| a + b, vm)
}),
subtract: atomic_func!(|number, other, vm| {
subtract: Some(|number, other, vm| {
PyComplex::number_op(number, other, |a, b, _vm| a - b, vm)
}),
multiply: atomic_func!(|number, other, vm| {
multiply: Some(|number, other, vm| {
PyComplex::number_op(number, other, |a, b, _vm| a * b, vm)
}),
power: atomic_func!(|number, other, vm| PyComplex::number_op(
number, other, inner_pow, vm
)),
negative: atomic_func!(|number, vm| {
power: Some(|number, other, vm| PyComplex::number_op(number, other, inner_pow, vm)),
negative: Some(|number, vm| {
let value = PyComplex::number_downcast(number).value;
(-value).to_pyresult(vm)
}),
positive: atomic_func!(
|number, vm| PyComplex::number_downcast_exact(number, vm).to_pyresult(vm)
),
absolute: atomic_func!(|number, vm| {
positive: Some(|number, vm| {
PyComplex::number_downcast_exact(number, vm).to_pyresult(vm)
}),
absolute: Some(|number, vm| {
let value = PyComplex::number_downcast(number).value;
value.norm().to_pyresult(vm)
}),
boolean: atomic_func!(|number, _vm| Ok(PyComplex::number_downcast(number)
.value
.is_zero())),
true_divide: atomic_func!(|number, other, vm| {
boolean: Some(|number, _vm| Ok(PyComplex::number_downcast(number).value.is_zero())),
true_divide: Some(|number, other, vm| {
PyComplex::number_op(number, other, inner_div, vm)
}),
..PyNumberMethods::NOT_IMPLEMENTED
});
};
&AS_NUMBER
}
+14 -11
View File
@@ -479,20 +479,23 @@ impl AsSequence for PyDict {
impl AsNumber for PyDict {
fn as_number() -> &'static PyNumberMethods {
static AS_NUMBER: Lazy<PyNumberMethods> = Lazy::new(|| PyNumberMethods {
or: atomic_func!(|num, args, vm| {
PyDict::number_downcast(num).or(args.to_pyobject(vm), vm)
static AS_NUMBER: PyNumberMethods = PyNumberMethods {
or: Some(|num, args, vm| {
if let Some(num) = num.obj.downcast_ref::<PyDict>() {
PyDict::or(num, args.to_pyobject(vm), vm)
} else {
Ok(vm.ctx.not_implemented())
}
}),
inplace_or: atomic_func!(|num, args, vm| {
PyDict::ior(
PyDict::number_downcast(num).to_owned(),
args.to_pyobject(vm),
vm,
)
.map(|d| d.into())
inplace_or: Some(|num, args, vm| {
if let Some(num) = num.obj.downcast_ref::<PyDict>() {
PyDict::ior(num.to_owned(), args.to_pyobject(vm), vm).map(|d| d.into())
} else {
Ok(vm.ctx.not_implemented())
}
}),
..PyNumberMethods::NOT_IMPLEMENTED
});
};
&AS_NUMBER
}
}
+16 -39
View File
@@ -2,7 +2,6 @@ use super::{
try_bigint_to_f64, PyByteArray, PyBytes, PyInt, PyIntRef, PyStr, PyStrRef, PyType, PyTypeRef,
};
use crate::{
atomic_func,
class::PyClassImpl,
common::format::FormatSpec,
common::{float_ops, hash},
@@ -21,7 +20,6 @@ use num_bigint::{BigInt, ToBigInt};
use num_complex::Complex64;
use num_rational::Ratio;
use num_traits::{Signed, ToPrimitive, Zero};
use once_cell::sync::Lazy;
#[pyclass(module = false, name = "float")]
#[derive(Debug, Copy, Clone, PartialEq)]
@@ -545,53 +543,32 @@ impl Hashable for PyFloat {
impl AsNumber for PyFloat {
fn as_number() -> &'static PyNumberMethods {
static AS_NUMBER: Lazy<PyNumberMethods> = Lazy::new(|| PyNumberMethods {
add: atomic_func!(|num, other, vm| PyFloat::number_op(
num,
other,
|a, b, _vm| a + b,
vm
)),
subtract: atomic_func!(|num, other, vm| PyFloat::number_op(
num,
other,
|a, b, _vm| a - b,
vm
)),
multiply: atomic_func!(|num, other, vm| PyFloat::number_op(
num,
other,
|a, b, _vm| a * b,
vm
)),
remainder: atomic_func!(|num, other, vm| PyFloat::number_op(num, other, inner_mod, vm)),
divmod: atomic_func!(|num, other, vm| PyFloat::number_op(num, other, inner_divmod, vm)),
power: atomic_func!(|num, other, vm| PyFloat::number_op(num, other, float_pow, vm)),
negative: atomic_func!(|num, vm| {
static AS_NUMBER: PyNumberMethods = PyNumberMethods {
add: Some(|num, other, vm| PyFloat::number_op(num, other, |a, b, _vm| a + b, vm)),
subtract: Some(|num, other, vm| PyFloat::number_op(num, other, |a, b, _vm| a - b, vm)),
multiply: Some(|num, other, vm| PyFloat::number_op(num, other, |a, b, _vm| a * b, vm)),
remainder: Some(|num, other, vm| PyFloat::number_op(num, other, inner_mod, vm)),
divmod: Some(|num, other, vm| PyFloat::number_op(num, other, inner_divmod, vm)),
power: Some(|num, other, vm| PyFloat::number_op(num, other, float_pow, vm)),
negative: Some(|num, vm| {
let value = PyFloat::number_downcast(num).value;
(-value).to_pyresult(vm)
}),
positive: atomic_func!(
|num, vm| PyFloat::number_downcast_exact(num, vm).to_pyresult(vm)
),
absolute: atomic_func!(|num, vm| {
positive: Some(|num, vm| PyFloat::number_downcast_exact(num, vm).to_pyresult(vm)),
absolute: Some(|num, vm| {
let value = PyFloat::number_downcast(num).value;
value.abs().to_pyresult(vm)
}),
boolean: atomic_func!(|num, _vm| Ok(PyFloat::number_downcast(num).value.is_zero())),
int: atomic_func!(|num, vm| {
boolean: Some(|num, _vm| Ok(PyFloat::number_downcast(num).value.is_zero())),
int: Some(|num, vm| {
let value = PyFloat::number_downcast(num).value;
try_to_bigint(value, vm).map(|x| vm.ctx.new_int(x))
}),
float: atomic_func!(|num, vm| Ok(PyFloat::number_downcast_exact(num, vm))),
floor_divide: atomic_func!(|num, other, vm| {
PyFloat::number_op(num, other, inner_floordiv, vm)
}),
true_divide: atomic_func!(|num, other, vm| {
PyFloat::number_op(num, other, inner_div, vm)
}),
float: Some(|num, vm| Ok(PyFloat::number_downcast_exact(num, vm))),
floor_divide: Some(|num, other, vm| PyFloat::number_op(num, other, inner_floordiv, vm)),
true_divide: Some(|num, other, vm| PyFloat::number_op(num, other, inner_div, vm)),
..PyNumberMethods::NOT_IMPLEMENTED
});
};
&AS_NUMBER
}
+23 -46
View File
@@ -1,6 +1,5 @@
use super::{float, PyByteArray, PyBytes, PyStr, PyType, PyTypeRef};
use crate::{
atomic_func,
builtins::PyStrRef,
bytesinner::PyBytesInner,
class::PyClassImpl,
@@ -20,7 +19,6 @@ use num_bigint::{BigInt, BigUint, Sign};
use num_integer::Integer;
use num_rational::Ratio;
use num_traits::{One, Pow, PrimInt, Signed, ToPrimitive, Zero};
use once_cell::sync::Lazy;
use std::ops::{Div, Neg};
use std::{fmt, ops::Not};
@@ -729,54 +727,33 @@ impl Hashable for PyInt {
impl AsNumber for PyInt {
fn as_number() -> &'static PyNumberMethods {
static AS_NUMBER: Lazy<PyNumberMethods> = Lazy::new(|| PyNumberMethods {
add: atomic_func!(|num, other, vm| PyInt::number_op(num, other, |a, b, _vm| a + b, vm)),
subtract: atomic_func!(|num, other, vm| PyInt::number_op(
num,
other,
|a, b, _vm| a - b,
vm
)),
multiply: atomic_func!(|num, other, vm| PyInt::number_op(
num,
other,
|a, b, _vm| a * b,
vm
)),
remainder: atomic_func!(|num, other, vm| PyInt::number_op(num, other, inner_mod, vm)),
divmod: atomic_func!(|num, other, vm| PyInt::number_op(num, other, inner_divmod, vm)),
power: atomic_func!(|num, other, vm| PyInt::number_op(num, other, inner_pow, vm)),
negative: atomic_func!(|num, vm| (&PyInt::number_downcast(num).value)
.neg()
.to_pyresult(vm)),
positive: atomic_func!(|num, vm| Ok(PyInt::number_downcast_exact(num, vm).into())),
absolute: atomic_func!(|num, vm| PyInt::number_downcast(num)
.value
.abs()
.to_pyresult(vm)),
boolean: atomic_func!(|num, _vm| Ok(PyInt::number_downcast(num).value.is_zero())),
invert: atomic_func!(|num, vm| (&PyInt::number_downcast(num).value)
.not()
.to_pyresult(vm)),
lshift: atomic_func!(|num, other, vm| PyInt::number_op(num, other, inner_lshift, vm)),
rshift: atomic_func!(|num, other, vm| PyInt::number_op(num, other, inner_rshift, vm)),
and: atomic_func!(|num, other, vm| PyInt::number_op(num, other, |a, b, _vm| a & b, vm)),
xor: atomic_func!(|num, other, vm| PyInt::number_op(num, other, |a, b, _vm| a ^ b, vm)),
or: atomic_func!(|num, other, vm| PyInt::number_op(num, other, |a, b, _vm| a | b, vm)),
int: atomic_func!(|num, vm| Ok(PyInt::number_downcast_exact(num, vm))),
float: atomic_func!(|num, vm| {
static AS_NUMBER: PyNumberMethods = PyNumberMethods {
add: Some(|num, other, vm| PyInt::number_op(num, other, |a, b, _vm| a + b, vm)),
subtract: Some(|num, other, vm| PyInt::number_op(num, other, |a, b, _vm| a - b, vm)),
multiply: Some(|num, other, vm| PyInt::number_op(num, other, |a, b, _vm| a * b, vm)),
remainder: Some(|num, other, vm| PyInt::number_op(num, other, inner_mod, vm)),
divmod: Some(|num, other, vm| PyInt::number_op(num, other, inner_divmod, vm)),
power: Some(|num, other, vm| PyInt::number_op(num, other, inner_pow, vm)),
negative: Some(|num, vm| (&PyInt::number_downcast(num).value).neg().to_pyresult(vm)),
positive: Some(|num, vm| Ok(PyInt::number_downcast_exact(num, vm).into())),
absolute: Some(|num, vm| PyInt::number_downcast(num).value.abs().to_pyresult(vm)),
boolean: Some(|num, _vm| Ok(PyInt::number_downcast(num).value.is_zero())),
invert: Some(|num, vm| (&PyInt::number_downcast(num).value).not().to_pyresult(vm)),
lshift: Some(|num, other, vm| PyInt::number_op(num, other, inner_lshift, vm)),
rshift: Some(|num, other, vm| PyInt::number_op(num, other, inner_rshift, vm)),
and: Some(|num, other, vm| PyInt::number_op(num, other, |a, b, _vm| a & b, vm)),
xor: Some(|num, other, vm| PyInt::number_op(num, other, |a, b, _vm| a ^ b, vm)),
or: Some(|num, other, vm| PyInt::number_op(num, other, |a, b, _vm| a | b, vm)),
int: Some(|num, vm| Ok(PyInt::number_downcast_exact(num, vm))),
float: Some(|num, vm| {
let zelf = PyInt::number_downcast(num);
try_to_float(&zelf.value, vm).map(|x| vm.ctx.new_float(x))
}),
floor_divide: atomic_func!(|num, other, vm| {
PyInt::number_op(num, other, inner_floordiv, vm)
}),
true_divide: atomic_func!(|num, other, vm| {
PyInt::number_op(num, other, inner_truediv, vm)
}),
index: atomic_func!(|num, vm| Ok(PyInt::number_downcast_exact(num, vm))),
floor_divide: Some(|num, other, vm| PyInt::number_op(num, other, inner_floordiv, vm)),
true_divide: Some(|num, other, vm| PyInt::number_op(num, other, inner_truediv, vm)),
index: Some(|num, vm| Ok(PyInt::number_downcast_exact(num, vm))),
..PyNumberMethods::NOT_IMPLEMENTED
});
};
&AS_NUMBER
}
+16 -9
View File
@@ -1,5 +1,3 @@
use once_cell::sync::Lazy;
use super::{PyDict, PyDictRef, PyGenericAlias, PyList, PyTuple, PyType, PyTypeRef};
use crate::{
atomic_func,
@@ -10,6 +8,7 @@ use crate::{
types::{AsMapping, AsNumber, AsSequence, Comparable, Constructor, Iterable, PyComparisonOp},
AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
};
use once_cell::sync::Lazy;
#[pyclass(module = false, name = "mappingproxy")]
#[derive(Debug)]
@@ -70,7 +69,7 @@ impl Constructor for PyMappingProxy {
}
}
#[pyclass(with(AsMapping, Iterable, Constructor, AsSequence, Comparable))]
#[pyclass(with(AsMapping, Iterable, Constructor, AsSequence, Comparable, AsNumber))]
impl PyMappingProxy {
fn get_inner(&self, key: PyObjectRef, vm: &VirtualMachine) -> PyResult<Option<PyObjectRef>> {
let opt = match &self.mapping {
@@ -232,15 +231,23 @@ impl AsSequence for PyMappingProxy {
impl AsNumber for PyMappingProxy {
fn as_number() -> &'static PyNumberMethods {
static AS_NUMBER: Lazy<PyNumberMethods> = Lazy::new(|| PyNumberMethods {
or: atomic_func!(|num, args, vm| {
PyMappingProxy::number_downcast(num).or(args.to_pyobject(vm), vm)
static AS_NUMBER: PyNumberMethods = PyNumberMethods {
or: Some(|num, args, vm| {
if let Some(num) = num.obj.downcast_ref::<PyMappingProxy>() {
num.or(args.to_pyobject(vm), vm)
} else {
Ok(vm.ctx.not_implemented())
}
}),
inplace_or: atomic_func!(|num, args, vm| {
PyMappingProxy::number_downcast(num).ior(args.to_pyobject(vm), vm)
inplace_or: Some(|num, args, vm| {
if let Some(num) = num.obj.downcast_ref::<PyMappingProxy>() {
num.ior(args.to_pyobject(vm), vm)
} else {
Ok(vm.ctx.not_implemented())
}
}),
..PyNumberMethods::NOT_IMPLEMENTED
});
};
&AS_NUMBER
}
}
+96 -64
View File
@@ -805,61 +805,85 @@ impl Iterable for PySet {
impl AsNumber for PySet {
fn as_number() -> &'static PyNumberMethods {
static AS_NUMBER: Lazy<PyNumberMethods> = Lazy::new(|| PyNumberMethods {
subtract: atomic_func!(|number, other, vm| {
PySet::number_downcast(number)
.sub(other.to_owned(), vm)
static AS_NUMBER: PyNumberMethods = PyNumberMethods {
subtract: Some(|number, other, vm| {
if let Some(number) = number.obj.downcast_ref::<PySet>() {
number.sub(other.to_owned(), vm).to_pyresult(vm)
} else {
Ok(vm.ctx.not_implemented())
}
}),
and: Some(|number, other, vm| {
if let Some(number) = number.obj.downcast_ref::<PySet>() {
number.and(other.to_owned(), vm).to_pyresult(vm)
} else {
Ok(vm.ctx.not_implemented())
}
}),
xor: Some(|number, other, vm| {
if let Some(number) = number.obj.downcast_ref::<PySet>() {
number.xor(other.to_owned(), vm).to_pyresult(vm)
} else {
Ok(vm.ctx.not_implemented())
}
}),
or: Some(|number, other, vm| {
if let Some(number) = number.obj.downcast_ref::<PySet>() {
number.or(other.to_owned(), vm).to_pyresult(vm)
} else {
Ok(vm.ctx.not_implemented())
}
}),
inplace_subtract: Some(|number, other, vm| {
if let Some(number) = number.obj.downcast_ref::<PySet>() {
PySet::isub(
number.to_owned(),
AnySet::try_from_object(vm, other.to_owned())?,
vm,
)
.to_pyresult(vm)
} else {
Ok(vm.ctx.not_implemented())
}
}),
and: atomic_func!(|number, other, vm| {
PySet::number_downcast(number)
.and(other.to_owned(), vm)
inplace_and: Some(|number, other, vm| {
if let Some(number) = number.obj.downcast_ref::<PySet>() {
PySet::iand(
number.to_owned(),
AnySet::try_from_object(vm, other.to_owned())?,
vm,
)
.to_pyresult(vm)
} else {
Ok(vm.ctx.not_implemented())
}
}),
xor: atomic_func!(|number, other, vm| {
PySet::number_downcast(number)
.xor(other.to_owned(), vm)
inplace_xor: Some(|number, other, vm| {
if let Some(number) = number.obj.downcast_ref::<PySet>() {
PySet::ixor(
number.to_owned(),
AnySet::try_from_object(vm, other.to_owned())?,
vm,
)
.to_pyresult(vm)
} else {
Ok(vm.ctx.not_implemented())
}
}),
or: atomic_func!(|number, other, vm| {
PySet::number_downcast(number)
.or(other.to_owned(), vm)
inplace_or: Some(|number, other, vm| {
if let Some(number) = number.obj.downcast_ref::<PySet>() {
PySet::ior(
number.to_owned(),
AnySet::try_from_object(vm, other.to_owned())?,
vm,
)
.to_pyresult(vm)
}),
inplace_subtract: atomic_func!(|number, other, vm| {
PySet::isub(
PySet::number_downcast(number).to_owned(),
AnySet::try_from_object(vm, other.to_owned())?,
vm,
)
.to_pyresult(vm)
}),
inplace_and: atomic_func!(|number, other, vm| {
PySet::iand(
PySet::number_downcast(number).to_owned(),
AnySet::try_from_object(vm, other.to_owned())?,
vm,
)
.to_pyresult(vm)
}),
inplace_xor: atomic_func!(|number, other, vm| {
PySet::ixor(
PySet::number_downcast(number).to_owned(),
AnySet::try_from_object(vm, other.to_owned())?,
vm,
)
.to_pyresult(vm)
}),
inplace_or: atomic_func!(|number, other, vm| {
PySet::ior(
PySet::number_downcast(number).to_owned(),
AnySet::try_from_object(vm, other.to_owned())?,
vm,
)
.to_pyresult(vm)
} else {
Ok(vm.ctx.not_implemented())
}
}),
..PyNumberMethods::NOT_IMPLEMENTED
});
};
&AS_NUMBER
}
}
@@ -1105,29 +1129,37 @@ impl Iterable for PyFrozenSet {
impl AsNumber for PyFrozenSet {
fn as_number() -> &'static PyNumberMethods {
static AS_NUMBER: Lazy<PyNumberMethods> = Lazy::new(|| PyNumberMethods {
subtract: atomic_func!(|number, other, vm| {
PyFrozenSet::number_downcast(number)
.sub(other.to_owned(), vm)
.to_pyresult(vm)
static AS_NUMBER: PyNumberMethods = PyNumberMethods {
subtract: Some(|number, other, vm| {
if let Some(number) = number.obj.downcast_ref::<PyFrozenSet>() {
number.sub(other.to_owned(), vm).to_pyresult(vm)
} else {
Ok(vm.ctx.not_implemented())
}
}),
and: atomic_func!(|number, other, vm| {
PyFrozenSet::number_downcast(number)
.and(other.to_owned(), vm)
.to_pyresult(vm)
and: Some(|number, other, vm| {
if let Some(number) = number.obj.downcast_ref::<PyFrozenSet>() {
number.and(other.to_owned(), vm).to_pyresult(vm)
} else {
Ok(vm.ctx.not_implemented())
}
}),
xor: atomic_func!(|number, other, vm| {
PyFrozenSet::number_downcast(number)
.xor(other.to_owned(), vm)
.to_pyresult(vm)
xor: Some(|number, other, vm| {
if let Some(number) = number.obj.downcast_ref::<PyFrozenSet>() {
number.xor(other.to_owned(), vm).to_pyresult(vm)
} else {
Ok(vm.ctx.not_implemented())
}
}),
or: atomic_func!(|number, other, vm| {
PyFrozenSet::number_downcast(number)
.or(other.to_owned(), vm)
.to_pyresult(vm)
or: Some(|number, other, vm| {
if let Some(number) = number.obj.downcast_ref::<PyFrozenSet>() {
number.or(other.to_owned(), vm).to_pyresult(vm)
} else {
Ok(vm.ctx.not_implemented())
}
}),
..PyNumberMethods::NOT_IMPLEMENTED
});
};
&AS_NUMBER
}
}
+3 -6
View File
@@ -1,8 +1,5 @@
use once_cell::sync::Lazy;
use super::{PyType, PyTypeRef};
use crate::{
atomic_func,
class::PyClassImpl,
convert::ToPyObject,
protocol::PyNumberMethods,
@@ -60,10 +57,10 @@ impl PyNone {
impl AsNumber for PyNone {
fn as_number() -> &'static PyNumberMethods {
static AS_NUMBER: Lazy<PyNumberMethods> = Lazy::new(|| PyNumberMethods {
boolean: atomic_func!(|_number, _vm| Ok(false)),
static AS_NUMBER: PyNumberMethods = PyNumberMethods {
boolean: Some(|_number, _vm| Ok(false)),
..PyNumberMethods::NOT_IMPLEMENTED
});
};
&AS_NUMBER
}
}
+8 -6
View File
@@ -1301,14 +1301,16 @@ impl AsMapping for PyStr {
impl AsNumber for PyStr {
fn as_number() -> &'static PyNumberMethods {
static AS_NUMBER: Lazy<PyNumberMethods> = Lazy::new(|| PyNumberMethods {
remainder: atomic_func!(|number, other, vm| {
PyStr::number_downcast(number)
.modulo(other.to_owned(), vm)
.to_pyresult(vm)
static AS_NUMBER: PyNumberMethods = PyNumberMethods {
remainder: Some(|number, other, vm| {
if let Some(number) = number.obj.downcast_ref::<PyStr>() {
number.modulo(other.to_owned(), vm).to_pyresult(vm)
} else {
Ok(vm.ctx.not_implemented())
}
}),
..PyNumberMethods::NOT_IMPLEMENTED
});
};
&AS_NUMBER
}
}
+3 -5
View File
@@ -3,7 +3,6 @@ use super::{
PyStr, PyStrInterned, PyStrRef, PyTuple, PyTupleRef, PyWeak,
};
use crate::{
atomic_func,
builtins::{
descriptor::{
DescrObject, MemberDef, MemberDescrObject, MemberGetter, MemberKind, MemberSetter,
@@ -28,7 +27,6 @@ use crate::{
};
use indexmap::{map::Entry, IndexMap};
use itertools::Itertools;
use once_cell::sync::Lazy;
use std::{borrow::Borrow, collections::HashSet, fmt, ops::Deref, pin::Pin, ptr::NonNull};
#[pyclass(module = false, name = "type")]
@@ -1061,12 +1059,12 @@ impl Callable for PyType {
impl AsNumber for PyType {
fn as_number() -> &'static PyNumberMethods {
static AS_NUMBER: Lazy<PyNumberMethods> = Lazy::new(|| PyNumberMethods {
or: atomic_func!(|num, other, vm| {
static AS_NUMBER: PyNumberMethods = PyNumberMethods {
or: Some(|num, other, vm| {
or_(num.obj.to_owned(), other.to_owned(), vm).to_pyresult(vm)
}),
..PyNumberMethods::NOT_IMPLEMENTED
});
};
&AS_NUMBER
}
}
+4 -5
View File
@@ -1,5 +1,3 @@
use once_cell::sync::Lazy;
use super::{genericalias, type_};
use crate::{
atomic_func,
@@ -13,6 +11,7 @@ use crate::{
AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject,
VirtualMachine,
};
use once_cell::sync::Lazy;
use std::fmt;
const CLS_ATTRS: &[&str] = &["__module__"];
@@ -257,12 +256,12 @@ impl AsMapping for PyUnion {
impl AsNumber for PyUnion {
fn as_number() -> &'static PyNumberMethods {
static AS_NUMBER: Lazy<PyNumberMethods> = Lazy::new(|| PyNumberMethods {
or: atomic_func!(|num, other, vm| {
static AS_NUMBER: PyNumberMethods = PyNumberMethods {
or: Some(|num, other, vm| {
PyUnion::or(num.obj.to_owned(), other.to_owned(), vm).to_pyresult(vm)
}),
..PyNumberMethods::NOT_IMPLEMENTED
});
};
&AS_NUMBER
}
}
+3 -1
View File
@@ -10,5 +10,7 @@ pub use buffer::{BufferDescriptor, BufferMethods, BufferResizeGuard, PyBuffer, V
pub use callable::PyCallable;
pub use iter::{PyIter, PyIterIter, PyIterReturn};
pub use mapping::{PyMapping, PyMappingMethods};
pub use number::{PyNumber, PyNumberBinaryOpSlot, PyNumberMethods};
pub use number::{
PyNumber, PyNumberBinaryFunc, PyNumberBinaryOpSlot, PyNumberMethods, PyNumberUnaryFunc,
};
pub use sequence::{PySequence, PySequenceMethods};
+85 -84
View File
@@ -7,11 +7,9 @@ use crate::{
AsObject, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromBorrowedObject,
VirtualMachine,
};
use crossbeam_utils::atomic::AtomicCell;
type UnaryFunc<R = PyObjectRef> = AtomicCell<Option<fn(PyNumber, &VirtualMachine) -> PyResult<R>>>;
type BinaryFunc<R = PyObjectRef> =
AtomicCell<Option<fn(PyNumber, &PyObject, &VirtualMachine) -> PyResult<R>>>;
pub type PyNumberUnaryFunc<R = PyObjectRef> = fn(PyNumber, &VirtualMachine) -> PyResult<R>;
pub type PyNumberBinaryFunc = fn(PyNumber, &PyObject, &VirtualMachine) -> PyResult;
impl PyObject {
#[inline]
@@ -113,45 +111,45 @@ pub struct PyNumberMethods {
/* Number implementations must check *both*
arguments for proper type and implement the necessary conversions
in the slot functions themselves. */
pub add: BinaryFunc,
pub subtract: BinaryFunc,
pub multiply: BinaryFunc,
pub remainder: BinaryFunc,
pub divmod: BinaryFunc,
pub power: BinaryFunc,
pub negative: UnaryFunc,
pub positive: UnaryFunc,
pub absolute: UnaryFunc,
pub boolean: UnaryFunc<bool>,
pub invert: UnaryFunc,
pub lshift: BinaryFunc,
pub rshift: BinaryFunc,
pub and: BinaryFunc,
pub xor: BinaryFunc,
pub or: BinaryFunc,
pub int: UnaryFunc<PyRef<PyInt>>,
pub float: UnaryFunc<PyRef<PyFloat>>,
pub add: Option<PyNumberBinaryFunc>,
pub subtract: Option<PyNumberBinaryFunc>,
pub multiply: Option<PyNumberBinaryFunc>,
pub remainder: Option<PyNumberBinaryFunc>,
pub divmod: Option<PyNumberBinaryFunc>,
pub power: Option<PyNumberBinaryFunc>,
pub negative: Option<PyNumberUnaryFunc>,
pub positive: Option<PyNumberUnaryFunc>,
pub absolute: Option<PyNumberUnaryFunc>,
pub boolean: Option<PyNumberUnaryFunc<bool>>,
pub invert: Option<PyNumberUnaryFunc>,
pub lshift: Option<PyNumberBinaryFunc>,
pub rshift: Option<PyNumberBinaryFunc>,
pub and: Option<PyNumberBinaryFunc>,
pub xor: Option<PyNumberBinaryFunc>,
pub or: Option<PyNumberBinaryFunc>,
pub int: Option<PyNumberUnaryFunc<PyRef<PyInt>>>,
pub float: Option<PyNumberUnaryFunc<PyRef<PyFloat>>>,
pub inplace_add: BinaryFunc,
pub inplace_subtract: BinaryFunc,
pub inplace_multiply: BinaryFunc,
pub inplace_remainder: BinaryFunc,
pub inplace_power: BinaryFunc,
pub inplace_lshift: BinaryFunc,
pub inplace_rshift: BinaryFunc,
pub inplace_and: BinaryFunc,
pub inplace_xor: BinaryFunc,
pub inplace_or: BinaryFunc,
pub inplace_add: Option<PyNumberBinaryFunc>,
pub inplace_subtract: Option<PyNumberBinaryFunc>,
pub inplace_multiply: Option<PyNumberBinaryFunc>,
pub inplace_remainder: Option<PyNumberBinaryFunc>,
pub inplace_power: Option<PyNumberBinaryFunc>,
pub inplace_lshift: Option<PyNumberBinaryFunc>,
pub inplace_rshift: Option<PyNumberBinaryFunc>,
pub inplace_and: Option<PyNumberBinaryFunc>,
pub inplace_xor: Option<PyNumberBinaryFunc>,
pub inplace_or: Option<PyNumberBinaryFunc>,
pub floor_divide: BinaryFunc,
pub true_divide: BinaryFunc,
pub inplace_floor_divide: BinaryFunc,
pub inplace_true_divide: BinaryFunc,
pub floor_divide: Option<PyNumberBinaryFunc>,
pub true_divide: Option<PyNumberBinaryFunc>,
pub inplace_floor_divide: Option<PyNumberBinaryFunc>,
pub inplace_true_divide: Option<PyNumberBinaryFunc>,
pub index: UnaryFunc<PyRef<PyInt>>,
pub index: Option<PyNumberUnaryFunc<PyRef<PyInt>>>,
pub matrix_multiply: BinaryFunc,
pub inplace_matrix_multiply: BinaryFunc,
pub matrix_multiply: Option<PyNumberBinaryFunc>,
pub inplace_matrix_multiply: Option<PyNumberBinaryFunc>,
}
impl PyNumberMethods {
@@ -159,44 +157,47 @@ impl PyNumberMethods {
// TODO: weak order read for performance
#[allow(clippy::declare_interior_mutable_const)]
pub const NOT_IMPLEMENTED: PyNumberMethods = PyNumberMethods {
add: AtomicCell::new(None),
subtract: AtomicCell::new(None),
multiply: AtomicCell::new(None),
remainder: AtomicCell::new(None),
divmod: AtomicCell::new(None),
power: AtomicCell::new(None),
negative: AtomicCell::new(None),
positive: AtomicCell::new(None),
absolute: AtomicCell::new(None),
boolean: AtomicCell::new(None),
invert: AtomicCell::new(None),
lshift: AtomicCell::new(None),
rshift: AtomicCell::new(None),
and: AtomicCell::new(None),
xor: AtomicCell::new(None),
or: AtomicCell::new(None),
int: AtomicCell::new(None),
float: AtomicCell::new(None),
inplace_add: AtomicCell::new(None),
inplace_subtract: AtomicCell::new(None),
inplace_multiply: AtomicCell::new(None),
inplace_remainder: AtomicCell::new(None),
inplace_power: AtomicCell::new(None),
inplace_lshift: AtomicCell::new(None),
inplace_rshift: AtomicCell::new(None),
inplace_and: AtomicCell::new(None),
inplace_xor: AtomicCell::new(None),
inplace_or: AtomicCell::new(None),
floor_divide: AtomicCell::new(None),
true_divide: AtomicCell::new(None),
inplace_floor_divide: AtomicCell::new(None),
inplace_true_divide: AtomicCell::new(None),
index: AtomicCell::new(None),
matrix_multiply: AtomicCell::new(None),
inplace_matrix_multiply: AtomicCell::new(None),
add: None,
subtract: None,
multiply: None,
remainder: None,
divmod: None,
power: None,
negative: None,
positive: None,
absolute: None,
boolean: None,
invert: None,
lshift: None,
rshift: None,
and: None,
xor: None,
or: None,
int: None,
float: None,
inplace_add: None,
inplace_subtract: None,
inplace_multiply: None,
inplace_remainder: None,
inplace_power: None,
inplace_lshift: None,
inplace_rshift: None,
inplace_and: None,
inplace_xor: None,
inplace_or: None,
floor_divide: None,
true_divide: None,
inplace_floor_divide: None,
inplace_true_divide: None,
index: None,
matrix_multiply: None,
inplace_matrix_multiply: None,
};
pub fn get_binary_op(&self, op_slot: &PyNumberBinaryOpSlot) -> PyResult<&BinaryFunc> {
pub fn get_binary_op(
&self,
op_slot: &PyNumberBinaryOpSlot,
) -> PyResult<&Option<PyNumberBinaryFunc>> {
use PyNumberBinaryOpSlot::*;
let binary_op = match op_slot {
Add => &self.add,
@@ -287,16 +288,16 @@ impl PyNumber<'_> {
self.methods
}
pub fn get_binary_op(&self, op_slot: &PyNumberBinaryOpSlot) -> PyResult<&BinaryFunc> {
pub fn get_binary_op(
&self,
op_slot: &PyNumberBinaryOpSlot,
) -> PyResult<&Option<PyNumberBinaryFunc>> {
self.methods().get_binary_op(op_slot)
}
// PyNumber_Check
pub fn check(obj: &PyObject) -> bool {
let Some(methods) = Self::find_methods(obj) else {
return false;
};
let methods = methods.as_ref();
let methods = &obj.class().slots.number;
methods.int.load().is_some()
|| methods.index.load().is_some()
|| methods.float.load().is_some()
@@ -305,12 +306,12 @@ impl PyNumber<'_> {
// PyIndex_Check
pub fn is_index(&self) -> bool {
self.methods().index.load().is_some()
self.obj.class().slots.number.index.load().is_some()
}
#[inline]
pub fn int(self, vm: &VirtualMachine) -> Option<PyResult<PyIntRef>> {
self.methods().int.load().map(|f| {
self.obj.class().slots.number.int.load().map(|f| {
let ret = f(self, vm)?;
let value = if !ret.class().is(PyInt::class(vm)) {
warnings::warn(
@@ -334,7 +335,7 @@ impl PyNumber<'_> {
#[inline]
pub fn index(self, vm: &VirtualMachine) -> Option<PyResult<PyIntRef>> {
self.methods().index.load().map(|f| {
self.obj.class().slots.number.index.load().map(|f| {
let ret = f(self, vm)?;
let value = if !ret.class().is(PyInt::class(vm)) {
warnings::warn(
@@ -358,7 +359,7 @@ impl PyNumber<'_> {
#[inline]
pub fn float(self, vm: &VirtualMachine) -> Option<PyResult<PyRef<PyFloat>>> {
self.methods().float.load().map(|f| {
self.obj.class().slots.number.float.load().map(|f| {
let ret = f(self, vm)?;
let value = if !ret.class().is(PyFloat::class(vm)) {
warnings::warn(
+303 -114
View File
@@ -1,14 +1,13 @@
use crate::common::{hash::PyHash, lock::PyRwLock};
use crate::convert::ToPyObject;
use crate::{
builtins::{type_::PointerSlot, PyFloat, PyInt, PyStrInterned, PyStrRef, PyType, PyTypeRef},
bytecode::ComparisonOperator,
convert::ToPyResult,
common::{hash::PyHash, lock::PyRwLock},
convert::{ToPyObject, ToPyResult},
function::{Either, FromArgs, FuncArgs, OptionalArg, PyComparisonValue, PySetterValue},
identifier,
protocol::{
PyBuffer, PyIterReturn, PyMapping, PyMappingMethods, PyNumber, PyNumberMethods, PySequence,
PySequenceMethods,
PyBuffer, PyIterReturn, PyMapping, PyMappingMethods, PyNumber, PyNumberBinaryFunc,
PyNumberBinaryOpSlot, PyNumberMethods, PyNumberUnaryFunc, PySequence, PySequenceMethods,
},
vm::Context,
AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
@@ -85,6 +84,7 @@ pub struct PyTypeSlots {
// The count of tp_members.
pub member_count: usize,
pub number: PyNumberSlots,
}
impl PyTypeSlots {
@@ -102,6 +102,128 @@ impl std::fmt::Debug for PyTypeSlots {
}
}
#[derive(Default)]
pub struct PyNumberSlots {
pub add: AtomicCell<Option<PyNumberBinaryFunc>>,
pub subtract: AtomicCell<Option<PyNumberBinaryFunc>>,
pub multiply: AtomicCell<Option<PyNumberBinaryFunc>>,
pub remainder: AtomicCell<Option<PyNumberBinaryFunc>>,
pub divmod: AtomicCell<Option<PyNumberBinaryFunc>>,
pub power: AtomicCell<Option<PyNumberBinaryFunc>>,
pub negative: AtomicCell<Option<PyNumberUnaryFunc>>,
pub positive: AtomicCell<Option<PyNumberUnaryFunc>>,
pub absolute: AtomicCell<Option<PyNumberUnaryFunc>>,
pub boolean: AtomicCell<Option<PyNumberUnaryFunc<bool>>>,
pub invert: AtomicCell<Option<PyNumberUnaryFunc>>,
pub lshift: AtomicCell<Option<PyNumberBinaryFunc>>,
pub rshift: AtomicCell<Option<PyNumberBinaryFunc>>,
pub and: AtomicCell<Option<PyNumberBinaryFunc>>,
pub xor: AtomicCell<Option<PyNumberBinaryFunc>>,
pub or: AtomicCell<Option<PyNumberBinaryFunc>>,
pub int: AtomicCell<Option<PyNumberUnaryFunc<PyRef<PyInt>>>>,
pub float: AtomicCell<Option<PyNumberUnaryFunc<PyRef<PyFloat>>>>,
pub right_add: AtomicCell<Option<PyNumberBinaryFunc>>,
pub right_subtract: AtomicCell<Option<PyNumberBinaryFunc>>,
pub right_multiply: AtomicCell<Option<PyNumberBinaryFunc>>,
pub right_remainder: AtomicCell<Option<PyNumberBinaryFunc>>,
pub right_divmod: AtomicCell<Option<PyNumberBinaryFunc>>,
pub right_power: AtomicCell<Option<PyNumberBinaryFunc>>,
pub right_lshift: AtomicCell<Option<PyNumberBinaryFunc>>,
pub right_rshift: AtomicCell<Option<PyNumberBinaryFunc>>,
pub right_and: AtomicCell<Option<PyNumberBinaryFunc>>,
pub right_xor: AtomicCell<Option<PyNumberBinaryFunc>>,
pub right_or: AtomicCell<Option<PyNumberBinaryFunc>>,
pub inplace_add: AtomicCell<Option<PyNumberBinaryFunc>>,
pub inplace_subtract: AtomicCell<Option<PyNumberBinaryFunc>>,
pub inplace_multiply: AtomicCell<Option<PyNumberBinaryFunc>>,
pub inplace_remainder: AtomicCell<Option<PyNumberBinaryFunc>>,
pub inplace_power: AtomicCell<Option<PyNumberBinaryFunc>>,
pub inplace_lshift: AtomicCell<Option<PyNumberBinaryFunc>>,
pub inplace_rshift: AtomicCell<Option<PyNumberBinaryFunc>>,
pub inplace_and: AtomicCell<Option<PyNumberBinaryFunc>>,
pub inplace_xor: AtomicCell<Option<PyNumberBinaryFunc>>,
pub inplace_or: AtomicCell<Option<PyNumberBinaryFunc>>,
pub floor_divide: AtomicCell<Option<PyNumberBinaryFunc>>,
pub true_divide: AtomicCell<Option<PyNumberBinaryFunc>>,
pub right_floor_divide: AtomicCell<Option<PyNumberBinaryFunc>>,
pub right_true_divide: AtomicCell<Option<PyNumberBinaryFunc>>,
pub inplace_floor_divide: AtomicCell<Option<PyNumberBinaryFunc>>,
pub inplace_true_divide: AtomicCell<Option<PyNumberBinaryFunc>>,
pub index: AtomicCell<Option<PyNumberUnaryFunc<PyRef<PyInt>>>>,
pub matrix_multiply: AtomicCell<Option<PyNumberBinaryFunc>>,
pub right_matrix_multiply: AtomicCell<Option<PyNumberBinaryFunc>>,
pub inplace_matrix_multiply: AtomicCell<Option<PyNumberBinaryFunc>>,
}
impl PyNumberSlots {
pub fn get_left_binary_op(
&self,
op_slot: &PyNumberBinaryOpSlot,
) -> PyResult<Option<PyNumberBinaryFunc>> {
use PyNumberBinaryOpSlot::*;
let binary_op = match op_slot {
Add => self.add.load(),
Subtract => self.subtract.load(),
Multiply => self.multiply.load(),
Remainder => self.remainder.load(),
Divmod => self.divmod.load(),
Power => self.power.load(),
Lshift => self.lshift.load(),
Rshift => self.rshift.load(),
And => self.and.load(),
Xor => self.xor.load(),
Or => self.or.load(),
InplaceAdd => self.inplace_add.load(),
InplaceSubtract => self.inplace_subtract.load(),
InplaceMultiply => self.inplace_multiply.load(),
InplaceRemainder => self.inplace_remainder.load(),
InplacePower => self.inplace_power.load(),
InplaceLshift => self.inplace_lshift.load(),
InplaceRshift => self.inplace_rshift.load(),
InplaceAnd => self.inplace_and.load(),
InplaceXor => self.inplace_xor.load(),
InplaceOr => self.inplace_or.load(),
FloorDivide => self.floor_divide.load(),
TrueDivide => self.true_divide.load(),
InplaceFloorDivide => self.inplace_floor_divide.load(),
InplaceTrueDivide => self.inplace_true_divide.load(),
MatrixMultiply => self.matrix_multiply.load(),
InplaceMatrixMultiply => self.inplace_matrix_multiply.load(),
};
Ok(binary_op)
}
pub fn get_right_binary_op(
&self,
op_slot: &PyNumberBinaryOpSlot,
) -> PyResult<Option<PyNumberBinaryFunc>> {
use PyNumberBinaryOpSlot::*;
let binary_op = match op_slot {
Add => self.right_add.load(),
Subtract => self.right_subtract.load(),
Multiply => self.right_multiply.load(),
Remainder => self.right_remainder.load(),
Divmod => self.right_divmod.load(),
Power => self.right_power.load(),
Lshift => self.right_lshift.load(),
Rshift => self.right_rshift.load(),
And => self.right_and.load(),
Xor => self.right_xor.load(),
Or => self.right_or.load(),
FloorDivide => self.right_floor_divide.load(),
TrueDivide => self.right_true_divide.load(),
MatrixMultiply => self.right_matrix_multiply.load(),
_ => None,
};
Ok(binary_op)
}
}
bitflags! {
#[non_exhaustive]
pub struct PyTypeFlags: u64 {
@@ -373,6 +495,15 @@ impl PyType {
}};
}
macro_rules! toggle_subslot {
($group:ident, $name:ident, $func:expr) => {
self.slots
.$group
.$name
.store(if ADD { Some($func) } else { None });
};
}
macro_rules! update_slot {
($name:ident, $func:expr) => {{
self.slots.$name.store(Some($func));
@@ -485,204 +616,188 @@ impl PyType {
toggle_slot!(del, del_wrapper);
}
_ if name == identifier!(ctx, __int__) => {
toggle_ext_func!(number_methods, int, int_wrapper);
update_pointer_slot!(as_number, number_methods);
toggle_subslot!(number, int, int_wrapper);
}
_ if name == identifier!(ctx, __index__) => {
toggle_ext_func!(number_methods, index, index_wrapper);
update_pointer_slot!(as_number, number_methods);
toggle_subslot!(number, index, index_wrapper);
}
_ if name == identifier!(ctx, __float__) => {
toggle_ext_func!(number_methods, float, float_wrapper);
update_pointer_slot!(as_number, number_methods);
toggle_subslot!(number, float, float_wrapper);
}
_ if name == identifier!(ctx, __add__) => {
toggle_ext_func!(number_methods, add, number_binary_op_wrapper!(__add__));
update_pointer_slot!(as_number, number_methods);
toggle_subslot!(number, add, number_binary_op_wrapper!(__add__));
}
_ if name == identifier!(ctx, __radd__) => {
toggle_subslot!(number, right_add, number_binary_op_wrapper!(__radd__));
}
_ if name == identifier!(ctx, __iadd__) => {
toggle_ext_func!(
number_methods,
inplace_add,
number_binary_op_wrapper!(__iadd__)
);
update_pointer_slot!(as_number, number_methods);
toggle_subslot!(number, inplace_add, number_binary_op_wrapper!(__iadd__));
}
_ if name == identifier!(ctx, __sub__) => {
toggle_ext_func!(number_methods, subtract, number_binary_op_wrapper!(__sub__));
update_pointer_slot!(as_number, number_methods);
toggle_subslot!(number, subtract, number_binary_op_wrapper!(__sub__));
}
_ if name == identifier!(ctx, __rsub__) => {
toggle_subslot!(number, right_subtract, number_binary_op_wrapper!(__rsub__));
}
_ if name == identifier!(ctx, __isub__) => {
toggle_ext_func!(
number_methods,
toggle_subslot!(
number,
inplace_subtract,
number_binary_op_wrapper!(__isub__)
);
update_pointer_slot!(as_number, number_methods);
}
_ if name == identifier!(ctx, __mul__) => {
toggle_ext_func!(number_methods, multiply, number_binary_op_wrapper!(__mul__));
update_pointer_slot!(as_number, number_methods);
toggle_subslot!(number, multiply, number_binary_op_wrapper!(__mul__));
}
_ if name == identifier!(ctx, __rmul__) => {
toggle_subslot!(number, right_multiply, number_binary_op_wrapper!(__rmul__));
}
_ if name == identifier!(ctx, __imul__) => {
toggle_ext_func!(
number_methods,
toggle_subslot!(
number,
inplace_multiply,
number_binary_op_wrapper!(__imul__)
);
update_pointer_slot!(as_number, number_methods);
}
_ if name == identifier!(ctx, __mod__) => {
toggle_ext_func!(
number_methods,
remainder,
number_binary_op_wrapper!(__mod__)
);
update_pointer_slot!(as_number, number_methods);
toggle_subslot!(number, remainder, number_binary_op_wrapper!(__mod__));
}
_ if name == identifier!(ctx, __rmod__) => {
toggle_subslot!(number, right_remainder, number_binary_op_wrapper!(__rmod__));
}
_ if name == identifier!(ctx, __imod__) => {
toggle_ext_func!(
number_methods,
toggle_subslot!(
number,
inplace_remainder,
number_binary_op_wrapper!(__imod__)
);
update_pointer_slot!(as_number, number_methods);
}
_ if name == identifier!(ctx, __divmod__) => {
toggle_ext_func!(
number_methods,
divmod,
number_binary_op_wrapper!(__divmod__)
);
update_pointer_slot!(as_number, number_methods);
toggle_subslot!(number, divmod, number_binary_op_wrapper!(__divmod__));
}
_ if name == identifier!(ctx, __rdivmod__) => {
toggle_subslot!(number, right_divmod, number_binary_op_wrapper!(__rdivmod__));
}
_ if name == identifier!(ctx, __pow__) => {
toggle_ext_func!(number_methods, power, number_binary_op_wrapper!(__pow__));
update_pointer_slot!(as_number, number_methods);
toggle_subslot!(number, power, number_binary_op_wrapper!(__pow__));
}
_ if name == identifier!(ctx, __rpow__) => {
toggle_subslot!(number, right_power, number_binary_op_wrapper!(__rpow__));
}
_ if name == identifier!(ctx, __ipow__) => {
toggle_ext_func!(
number_methods,
inplace_power,
number_binary_op_wrapper!(__ipow__)
);
update_pointer_slot!(as_number, number_methods);
toggle_subslot!(number, inplace_power, number_binary_op_wrapper!(__ipow__));
}
_ if name == identifier!(ctx, __lshift__) => {
toggle_ext_func!(
number_methods,
lshift,
number_binary_op_wrapper!(__lshift__)
);
update_pointer_slot!(as_number, number_methods);
toggle_subslot!(number, lshift, number_binary_op_wrapper!(__lshift__));
}
_ if name == identifier!(ctx, __rlshift__) => {
toggle_subslot!(number, right_lshift, number_binary_op_wrapper!(__rlshift__));
}
_ if name == identifier!(ctx, __ilshift__) => {
toggle_ext_func!(
number_methods,
toggle_subslot!(
number,
inplace_lshift,
number_binary_op_wrapper!(__ilshift__)
);
update_pointer_slot!(as_number, number_methods);
}
_ if name == identifier!(ctx, __rshift__) => {
toggle_ext_func!(
number_methods,
rshift,
number_binary_op_wrapper!(__rshift__)
);
update_pointer_slot!(as_number, number_methods);
toggle_subslot!(number, rshift, number_binary_op_wrapper!(__rshift__));
}
_ if name == identifier!(ctx, __rrshift__) => {
toggle_subslot!(number, right_rshift, number_binary_op_wrapper!(__rrshift__));
}
_ if name == identifier!(ctx, __irshift__) => {
toggle_ext_func!(
number_methods,
toggle_subslot!(
number,
inplace_rshift,
number_binary_op_wrapper!(__irshift__)
);
update_pointer_slot!(as_number, number_methods);
}
_ if name == identifier!(ctx, __and__) => {
toggle_ext_func!(number_methods, and, number_binary_op_wrapper!(__and__));
update_pointer_slot!(as_number, number_methods);
toggle_subslot!(number, and, number_binary_op_wrapper!(__and__));
}
_ if name == identifier!(ctx, __rand__) => {
toggle_subslot!(number, right_and, number_binary_op_wrapper!(__rand__));
}
_ if name == identifier!(ctx, __iand__) => {
toggle_ext_func!(
number_methods,
inplace_and,
number_binary_op_wrapper!(__iand__)
);
update_pointer_slot!(as_number, number_methods);
toggle_subslot!(number, inplace_and, number_binary_op_wrapper!(__iand__));
}
_ if name == identifier!(ctx, __xor__) => {
toggle_ext_func!(number_methods, xor, number_binary_op_wrapper!(__xor__));
update_pointer_slot!(as_number, number_methods);
toggle_subslot!(number, xor, number_binary_op_wrapper!(__xor__));
}
_ if name == identifier!(ctx, __rxor__) => {
toggle_subslot!(number, right_xor, number_binary_op_wrapper!(__rxor__));
}
_ if name == identifier!(ctx, __ixor__) => {
toggle_ext_func!(
number_methods,
inplace_xor,
number_binary_op_wrapper!(__ixor__)
);
update_pointer_slot!(as_number, number_methods);
toggle_subslot!(number, inplace_xor, number_binary_op_wrapper!(__ixor__));
}
_ if name == identifier!(ctx, __or__) => {
toggle_ext_func!(number_methods, or, number_binary_op_wrapper!(__or__));
update_pointer_slot!(as_number, number_methods);
toggle_subslot!(number, or, number_binary_op_wrapper!(__or__));
}
_ if name == identifier!(ctx, __ror__) => {
toggle_subslot!(number, right_or, number_binary_op_wrapper!(__ror__));
}
_ if name == identifier!(ctx, __ior__) => {
toggle_ext_func!(
number_methods,
inplace_or,
number_binary_op_wrapper!(__ior__)
);
update_pointer_slot!(as_number, number_methods);
toggle_subslot!(number, inplace_or, number_binary_op_wrapper!(__ior__));
}
_ if name == identifier!(ctx, __floordiv__) => {
toggle_ext_func!(
number_methods,
toggle_subslot!(
number,
floor_divide,
number_binary_op_wrapper!(__floordiv__)
);
update_pointer_slot!(as_number, number_methods);
}
_ if name == identifier!(ctx, __rfloordiv__) => {
toggle_subslot!(
number,
right_floor_divide,
number_binary_op_wrapper!(__rfloordiv__)
);
}
_ if name == identifier!(ctx, __ifloordiv__) => {
toggle_ext_func!(
number_methods,
toggle_subslot!(
number,
inplace_floor_divide,
number_binary_op_wrapper!(__ifloordiv__)
);
update_pointer_slot!(as_number, number_methods);
}
_ if name == identifier!(ctx, __truediv__) => {
toggle_ext_func!(
number_methods,
true_divide,
number_binary_op_wrapper!(__truediv__)
toggle_subslot!(number, true_divide, number_binary_op_wrapper!(__truediv__));
}
_ if name == identifier!(ctx, __rtruediv__) => {
toggle_subslot!(
number,
right_true_divide,
number_binary_op_wrapper!(__rtruediv__)
);
update_pointer_slot!(as_number, number_methods);
}
_ if name == identifier!(ctx, __itruediv__) => {
toggle_ext_func!(
number_methods,
toggle_subslot!(
number,
inplace_true_divide,
number_binary_op_wrapper!(__itruediv__)
);
update_pointer_slot!(as_number, number_methods);
}
_ if name == identifier!(ctx, __matmul__) => {
toggle_ext_func!(
number_methods,
toggle_subslot!(
number,
matrix_multiply,
number_binary_op_wrapper!(__matmul__)
);
update_pointer_slot!(as_number, number_methods);
}
_ if name == identifier!(ctx, __rmatmul__) => {
toggle_subslot!(
number,
right_matrix_multiply,
number_binary_op_wrapper!(__rmatmul__)
);
}
_ if name == identifier!(ctx, __imatmul__) => {
toggle_ext_func!(
number_methods,
toggle_subslot!(
number,
inplace_matrix_multiply,
number_binary_op_wrapper!(__imatmul__)
);
update_pointer_slot!(as_number, number_methods);
}
_ => {}
}
@@ -1161,6 +1276,26 @@ pub trait AsSequence: PyPayload {
}
}
macro_rules! extend_number_slot {
($slots:ident, $methods:ident, $method:ident, $right_method:ident, $op_slot:ident) => {
if $methods.$method.is_some() {
$slots.number.$method.store($methods.$method);
$slots.number.$right_method.store(Some(|num, other, vm| {
num.get_binary_op(&PyNumberBinaryOpSlot::$op_slot)?.unwrap()(
other.to_number(),
num.obj,
vm,
)
}));
}
};
($slots:ident, $methods:ident, $method:ident) => {
if $methods.$method.is_some() {
$slots.number.$method.store($methods.$method);
}
};
}
#[pyclass]
pub trait AsNumber: PyPayload {
#[pyslot]
@@ -1184,6 +1319,60 @@ pub trait AsNumber: PyPayload {
Self::clone_exact(Self::number_downcast(number), vm)
}
}
fn extend_slots(slots: &mut PyTypeSlots) {
let methods = Self::as_number();
extend_number_slot!(slots, methods, add, right_add, Add);
extend_number_slot!(slots, methods, subtract, right_subtract, Subtract);
extend_number_slot!(slots, methods, multiply, right_multiply, Multiply);
extend_number_slot!(slots, methods, remainder, right_remainder, Remainder);
extend_number_slot!(slots, methods, divmod, right_divmod, Divmod);
extend_number_slot!(slots, methods, power, right_power, Power);
extend_number_slot!(slots, methods, lshift, right_lshift, Lshift);
extend_number_slot!(slots, methods, rshift, right_rshift, Rshift);
extend_number_slot!(slots, methods, and, right_and, And);
extend_number_slot!(slots, methods, xor, right_xor, Xor);
extend_number_slot!(slots, methods, or, right_or, Or);
extend_number_slot!(
slots,
methods,
floor_divide,
right_floor_divide,
FloorDivide
);
extend_number_slot!(slots, methods, true_divide, right_true_divide, TrueDivide);
extend_number_slot!(
slots,
methods,
matrix_multiply,
right_matrix_multiply,
MatrixMultiply
);
extend_number_slot!(slots, methods, negative);
extend_number_slot!(slots, methods, positive);
extend_number_slot!(slots, methods, absolute);
extend_number_slot!(slots, methods, boolean);
extend_number_slot!(slots, methods, invert);
extend_number_slot!(slots, methods, int);
extend_number_slot!(slots, methods, float);
extend_number_slot!(slots, methods, index);
extend_number_slot!(slots, methods, inplace_add);
extend_number_slot!(slots, methods, inplace_subtract);
extend_number_slot!(slots, methods, inplace_multiply);
extend_number_slot!(slots, methods, inplace_remainder);
extend_number_slot!(slots, methods, inplace_power);
extend_number_slot!(slots, methods, inplace_lshift);
extend_number_slot!(slots, methods, inplace_rshift);
extend_number_slot!(slots, methods, inplace_and);
extend_number_slot!(slots, methods, inplace_xor);
extend_number_slot!(slots, methods, inplace_or);
extend_number_slot!(slots, methods, inplace_floor_divide);
extend_number_slot!(slots, methods, inplace_true_divide);
extend_number_slot!(slots, methods, inplace_matrix_multiply);
}
}
#[pyclass]
+8 -12
View File
@@ -128,18 +128,15 @@ impl VirtualMachine {
/// Calling scheme used for binary operations:
///
/// Order operations are tried until either a valid result or error:
/// b.op(a,b)[*], a.op(a,b), b.op(a,b)
/// b.rop(b,a)[*], a.op(a,b), b.rop(b,a)
///
/// [*] only when Py_TYPE(a) != Py_TYPE(b) && Py_TYPE(b) is a subclass of Py_TYPE(a)
fn binary_op1(&self, a: &PyObject, b: &PyObject, op_slot: &PyNumberBinaryOpSlot) -> PyResult {
let num_a = a.to_number();
let num_b = b.to_number();
let slot_a = num_a.get_binary_op(op_slot)?.load();
let slot_a = a.class().slots.number.get_left_binary_op(op_slot)?;
let mut slot_b = if b.class().is(a.class()) {
None
} else {
match num_b.get_binary_op(op_slot)?.load() {
match b.class().slots.number.get_right_binary_op(op_slot)? {
Some(slot_b)
if slot_b as usize == slot_a.map(|s| s as usize).unwrap_or_default() =>
{
@@ -152,21 +149,21 @@ impl VirtualMachine {
if let Some(slot_a) = slot_a {
if let Some(slot_bb) = slot_b {
if b.fast_isinstance(a.class()) {
let x = slot_bb(num_a, b, self)?;
let x = slot_bb(b.to_number(), a, self)?;
if !x.is(&self.ctx.not_implemented) {
return Ok(x);
}
slot_b = None;
}
}
let x = slot_a(num_a, b, self)?;
let x = slot_a(a.to_number(), b, self)?;
if !x.is(&self.ctx.not_implemented) {
return Ok(x);
}
}
if let Some(slot_b) = slot_b {
let x = slot_b(num_a, b, self)?;
let x = slot_b(b.to_number(), a, self)?;
if !x.is(&self.ctx.not_implemented) {
return Ok(x);
}
@@ -209,9 +206,8 @@ impl VirtualMachine {
iop_slot: &PyNumberBinaryOpSlot,
op_slot: &PyNumberBinaryOpSlot,
) -> PyResult {
let num_a = a.to_number();
if let Some(slot) = num_a.get_binary_op(iop_slot)?.load() {
let x = slot(num_a, b, self)?;
if let Some(slot) = a.class().slots.number.get_left_binary_op(iop_slot)? {
let x = slot(a.to_number(), b, self)?;
if !x.is(&self.ctx.not_implemented) {
return Ok(x);
}