Simplify AsNumber trait

This commit is contained in:
Kangzhi Shi
2022-05-29 16:09:56 +09:00
committed by Jeong Yunwon
parent 1ed18c012a
commit ea95777ec7
5 changed files with 138 additions and 159 deletions

View File

@@ -1,5 +1,3 @@
use std::borrow::Cow;
use super::{
try_bigint_to_f64, PyByteArray, PyBytes, PyInt, PyIntRef, PyStr, PyStrRef, PyType, PyTypeRef,
};
@@ -153,9 +151,7 @@ impl Constructor for PyFloat {
let float_val = match arg {
OptionalArg::Missing => 0.0,
OptionalArg::Present(val) => {
if cls.is(vm.ctx.types.float_type) && val.class().is(PyFloat::class(vm)) {
unsafe { val.downcast_unchecked::<PyFloat>().value }
} else if let Some(f) = val.try_float_opt(vm)? {
if let Some(f) = val.try_float_opt(vm)? {
f.value
} else {
float_from_string(val, vm)?
@@ -539,13 +535,40 @@ impl Hashable for PyFloat {
}
impl AsNumber for PyFloat {
fn as_number(_zelf: &crate::Py<Self>, _vm: &VirtualMachine) -> Cow<'static, PyNumberMethods> {
Cow::Borrowed(&Self::NUMBER_METHODS)
}
const AS_NUMBER: PyNumberMethods = PyNumberMethods {
add: Some(|number, other, vm| Self::number_float_op(number, other, |a, b| a + b, vm)),
subtract: Some(|number, other, vm| Self::number_float_op(number, other, |a, b| a - b, vm)),
multiply: Some(|number, other, vm| Self::number_float_op(number, other, |a, b| a * b, vm)),
remainder: Some(|number, other, vm| Self::number_general_op(number, other, inner_mod, vm)),
divmod: Some(|number, other, vm| Self::number_general_op(number, other, inner_divmod, vm)),
power: Some(|number, other, vm| Self::number_general_op(number, other, float_pow, vm)),
negative: Some(|number, vm| {
let value = Self::number_downcast(number).value;
(-value).to_pyresult(vm)
}),
positive: Some(|number, vm| Self::number_float(number, vm).to_pyresult(vm)),
absolute: Some(|number, vm| {
let value = Self::number_downcast(number).value;
value.abs().to_pyresult(vm)
}),
boolean: Some(|number, _vm| Ok(Self::number_downcast(number).value.is_zero())),
int: Some(|number, vm| {
let value = Self::number_downcast(number).value;
try_to_bigint(value, vm).map(|x| vm.ctx.new_int(x))
}),
float: Some(|number, vm| Ok(Self::number_float(number, vm))),
floor_divide: Some(|number, other, vm| {
Self::number_general_op(number, other, inner_floordiv, vm)
}),
true_divide: Some(|number, other, vm| {
Self::number_general_op(number, other, inner_div, vm)
}),
..PyNumberMethods::NOT_IMPLEMENTED
};
}
impl PyFloat {
fn np_general_op<F, R>(
fn number_general_op<F, R>(
number: &PyNumber,
other: &PyObject,
op: F,
@@ -562,49 +585,25 @@ impl PyFloat {
}
}
fn np_float_op<F>(number: &PyNumber, other: &PyObject, op: F, vm: &VirtualMachine) -> PyResult
fn number_float_op<F>(
number: &PyNumber,
other: &PyObject,
op: F,
vm: &VirtualMachine,
) -> PyResult
where
F: FnOnce(f64, f64) -> f64,
{
Self::np_general_op(number, other, |a, b, _vm| op(a, b), vm)
Self::number_general_op(number, other, |a, b, _vm| op(a, b), vm)
}
fn np_float(number: &PyNumber, vm: &VirtualMachine) -> PyRef<PyFloat> {
fn number_float(number: &PyNumber, vm: &VirtualMachine) -> PyRef<PyFloat> {
if let Some(zelf) = number.obj.downcast_ref_if_exact::<Self>(vm) {
zelf.to_owned()
} else {
vm.ctx.new_float(Self::number_downcast(number).value)
}
}
const NUMBER_METHODS: PyNumberMethods = PyNumberMethods {
add: Some(|number, other, vm| Self::np_float_op(number, other, |a, b| a + b, vm)),
subtract: Some(|number, other, vm| Self::np_float_op(number, other, |a, b| a - b, vm)),
multiply: Some(|number, other, vm| Self::np_float_op(number, other, |a, b| a * b, vm)),
remainder: Some(|number, other, vm| Self::np_general_op(number, other, inner_mod, vm)),
divmod: Some(|number, other, vm| Self::np_general_op(number, other, inner_divmod, vm)),
power: Some(|number, other, vm| Self::np_general_op(number, other, float_pow, vm)),
negative: Some(|number, vm| {
let value = Self::number_downcast(number).value;
(-value).to_pyresult(vm)
}),
positive: Some(|number, vm| Self::np_float(number, vm).to_pyresult(vm)),
absolute: Some(|number, vm| {
let value = Self::number_downcast(number).value;
value.abs().to_pyresult(vm)
}),
boolean: Some(|number, _vm| Ok(Self::number_downcast(number).value.is_zero())),
int: Some(|number, vm| {
let value = Self::number_downcast(number).value;
try_to_bigint(value, vm).map(|x| vm.ctx.new_int(x))
}),
float: Some(|number, vm| Ok(Self::np_float(number, vm))),
floor_divide: Some(|number, other, vm| {
Self::np_general_op(number, other, inner_floordiv, vm)
}),
true_divide: Some(|number, other, vm| Self::np_general_op(number, other, inner_div, vm)),
..*PyNumberMethods::not_implemented()
};
}
// Retrieve inner float value:

View File

@@ -18,8 +18,8 @@ use bstr::ByteSlice;
use num_bigint::{BigInt, BigUint, Sign};
use num_integer::Integer;
use num_traits::{One, Pow, PrimInt, Signed, ToPrimitive, Zero};
use std::fmt;
use std::{borrow::Cow, ops::Neg};
use std::ops::Neg;
use std::{fmt, ops::Not};
/// int(x=0) -> integer
/// int(x, base=10) -> integer
@@ -756,13 +756,46 @@ impl Hashable for PyInt {
}
impl AsNumber for PyInt {
fn as_number(_zelf: &crate::Py<Self>, _vm: &VirtualMachine) -> Cow<'static, PyNumberMethods> {
Cow::Borrowed(&Self::NUMBER_METHODS)
}
const AS_NUMBER: PyNumberMethods = PyNumberMethods {
add: Some(|number, other, vm| Self::number_int_op(number, other, |a, b| a + b, vm)),
subtract: Some(|number, other, vm| Self::number_int_op(number, other, |a, b| a - b, vm)),
multiply: Some(|number, other, vm| Self::number_int_op(number, other, |a, b| a * b, vm)),
remainder: Some(|number, other, vm| Self::number_general_op(number, other, inner_mod, vm)),
divmod: Some(|number, other, vm| Self::number_general_op(number, other, inner_divmod, vm)),
power: Some(|number, other, vm| Self::number_general_op(number, other, inner_pow, vm)),
negative: Some(|number, vm| (&Self::number_downcast(number).value).neg().to_pyresult(vm)),
positive: Some(|number, vm| Ok(Self::number_int(number, vm).into())),
absolute: Some(|number, vm| Self::number_downcast(number).value.abs().to_pyresult(vm)),
boolean: Some(|number, _vm| Ok(Self::number_downcast(number).value.is_zero())),
invert: Some(|number, vm| (&Self::number_downcast(number).value).not().to_pyresult(vm)),
lshift: Some(|number, other, vm| Self::number_general_op(number, other, inner_lshift, vm)),
rshift: Some(|number, other, vm| Self::number_general_op(number, other, inner_rshift, vm)),
and: Some(|number, other, vm| Self::number_int_op(number, other, |a, b| a & b, vm)),
xor: Some(|number, other, vm| Self::number_int_op(number, other, |a, b| a ^ b, vm)),
or: Some(|number, other, vm| Self::number_int_op(number, other, |a, b| a | b, vm)),
int: Some(|number, other| Ok(Self::number_int(number, other))),
float: Some(|number, vm| {
let zelf = Self::number_downcast(number);
try_to_float(&zelf.value, vm).map(|x| vm.ctx.new_float(x))
}),
floor_divide: Some(|number, other, vm| {
Self::number_general_op(number, other, inner_floordiv, vm)
}),
true_divide: Some(|number, other, vm| {
Self::number_general_op(number, other, inner_truediv, vm)
}),
index: Some(|number, vm| Ok(Self::number_int(number, vm))),
..PyNumberMethods::NOT_IMPLEMENTED
};
}
impl PyInt {
fn np_general_op<F>(number: &PyNumber, other: &PyObject, op: F, vm: &VirtualMachine) -> PyResult
fn number_general_op<F>(
number: &PyNumber,
other: &PyObject,
op: F,
vm: &VirtualMachine,
) -> PyResult
where
F: FnOnce(&BigInt, &BigInt, &VirtualMachine) -> PyResult,
{
@@ -773,14 +806,14 @@ impl PyInt {
}
}
fn np_int_op<F>(number: &PyNumber, other: &PyObject, op: F, vm: &VirtualMachine) -> PyResult
fn number_int_op<F>(number: &PyNumber, other: &PyObject, op: F, vm: &VirtualMachine) -> PyResult
where
F: FnOnce(&BigInt, &BigInt) -> BigInt,
{
Self::np_general_op(number, other, |a, b, _vm| op(a, b).to_pyresult(vm), vm)
Self::number_general_op(number, other, |a, b, _vm| op(a, b).to_pyresult(vm), vm)
}
fn np_int(number: &PyNumber, vm: &VirtualMachine) -> PyIntRef {
fn number_int(number: &PyNumber, vm: &VirtualMachine) -> PyIntRef {
if let Some(zelf) = number.obj.downcast_ref_if_exact::<Self>(vm) {
zelf.to_owned()
} else {
@@ -788,47 +821,6 @@ impl PyInt {
vm.ctx.new_int(zelf.value.clone())
}
}
const NUMBER_METHODS: PyNumberMethods = PyNumberMethods {
add: Some(|number, other, vm| Self::np_int_op(number, other, |a, b| a + b, vm)),
subtract: Some(|number, other, vm| Self::np_int_op(number, other, |a, b| a - b, vm)),
multiply: Some(|number, other, vm| Self::np_int_op(number, other, |a, b| a * b, vm)),
remainder: Some(|number, other, vm| Self::np_general_op(number, other, inner_mod, vm)),
divmod: Some(|number, other, vm| Self::np_general_op(number, other, inner_divmod, vm)),
power: Some(|number, other, vm| Self::np_general_op(number, other, inner_pow, vm)),
negative: Some(|number, vm| {
Self::number_downcast(number)
.value
.clone()
.neg()
.to_pyresult(vm)
}),
positive: Some(|number, vm| Ok(Self::np_int(number, vm).into())),
absolute: Some(|number, vm| Self::number_downcast(number).value.abs().to_pyresult(vm)),
boolean: Some(|number, _vm| Ok(Self::number_downcast(number).value.is_zero())),
invert: Some(|number, vm| {
let value = Self::number_downcast(number).value.clone();
(!value).to_pyresult(vm)
}),
lshift: Some(|number, other, vm| Self::np_general_op(number, other, inner_lshift, vm)),
rshift: Some(|number, other, vm| Self::np_general_op(number, other, inner_rshift, vm)),
and: Some(|number, other, vm| Self::np_int_op(number, other, |a, b| a & b, vm)),
xor: Some(|number, other, vm| Self::np_int_op(number, other, |a, b| a ^ b, vm)),
or: Some(|number, other, vm| Self::np_int_op(number, other, |a, b| a | b, vm)),
int: Some(|number, other| Ok(Self::np_int(number, other))),
float: Some(|number, vm| {
let zelf = Self::number_downcast(number);
try_to_float(&zelf.value, vm).map(|x| vm.ctx.new_float(x))
}),
floor_divide: Some(|number, other, vm| {
Self::np_general_op(number, other, inner_floordiv, vm)
}),
true_divide: Some(|number, other, vm| {
Self::np_general_op(number, other, inner_truediv, vm)
}),
index: Some(|number, vm| Ok(Self::np_int(number, vm))),
..*PyNumberMethods::not_implemented()
};
}
#[derive(FromArgs)]

View File

@@ -34,7 +34,7 @@ pub struct PyNumberMethods {
pub float: Option<fn(&PyNumber, &VirtualMachine) -> PyResult<PyRef<PyFloat>>>,
pub inplace_add: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
pub inplace_substract: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
pub inplace_subtract: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
pub inplace_multiply: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
pub inplace_remainder: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
pub inplace_divmod: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
@@ -48,7 +48,7 @@ pub struct PyNumberMethods {
pub floor_divide: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
pub true_divide: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
pub inplace_floor_divide: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
pub inplace_true_devide: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
pub inplace_true_divide: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
pub index: Option<fn(&PyNumber, &VirtualMachine) -> PyResult<PyIntRef>>,
@@ -57,9 +57,44 @@ pub struct PyNumberMethods {
}
impl PyNumberMethods {
pub const fn not_implemented() -> &'static Self {
&NOT_IMPLEMENTED
}
pub const NOT_IMPLEMENTED: PyNumberMethods = PyNumberMethods {
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_divmod: 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 struct PyNumber<'a> {
@@ -88,7 +123,7 @@ impl PyNumber<'_> {
.class()
.mro_find_map(|x| x.slots.as_number.load())
.map(|f| f(self.obj, vm))
.unwrap_or_else(|| Cow::Borrowed(PyNumberMethods::not_implemented()))
.unwrap_or_else(|| Cow::Borrowed(&PyNumberMethods::NOT_IMPLEMENTED))
})
}
@@ -119,8 +154,8 @@ impl PyNumber<'_> {
}
}
if self.obj.class().is(PyInt::class(vm)) {
Ok(unsafe { self.obj.to_owned().downcast_unchecked::<PyInt>() })
if let Some(i) = self.obj.downcast_ref_if_exact::<PyInt>(vm) {
Ok(i.to_owned())
} else if let Some(f) = self.methods(vm).int {
let ret = f(self, vm)?;
if !ret.class().is(PyInt::class(vm)) {
@@ -135,7 +170,7 @@ impl PyNumber<'_> {
1,
vm,
)?;
Ok(vm.ctx.new_int(ret.as_bigint().clone()))
Ok(vm.ctx.new_bigint(ret.as_bigint()))
} else {
Ok(ret)
}
@@ -176,12 +211,10 @@ impl PyNumber<'_> {
}
pub fn index_opt(&self, vm: &VirtualMachine) -> PyResult<Option<PyIntRef>> {
if self.obj.class().is(PyInt::class(vm)) {
Ok(Some(unsafe {
self.obj.to_owned().downcast_unchecked::<PyInt>()
}))
} else if let Some(i) = self.obj.downcast_ref::<PyInt>() {
if let Some(i) = self.obj.downcast_ref_if_exact::<PyInt>(vm) {
Ok(Some(i.to_owned()))
} else if let Some(i) = self.obj.payload::<PyInt>() {
Ok(Some(vm.ctx.new_bigint(i.as_bigint())))
} else if let Some(f) = self.methods(vm).index {
let ret = f(self, vm)?;
if !ret.class().is(PyInt::class(vm)) {
@@ -196,7 +229,7 @@ impl PyNumber<'_> {
1,
vm,
)?;
Ok(Some(vm.ctx.new_int(ret.as_bigint().clone())))
Ok(Some(vm.ctx.new_bigint(ret.as_bigint())))
} else {
Ok(Some(ret))
}
@@ -215,10 +248,8 @@ impl PyNumber<'_> {
}
pub fn float_opt(&self, vm: &VirtualMachine) -> PyResult<Option<PyRef<PyFloat>>> {
if self.obj.class().is(PyFloat::class(vm)) {
Ok(Some(unsafe {
self.obj.to_owned().downcast_unchecked::<PyFloat>()
}))
if let Some(float) = self.obj.downcast_ref_if_exact::<PyFloat>(vm) {
Ok(Some(float.to_owned()))
} else if let Some(f) = self.methods(vm).float {
let ret = f(self, vm)?;
if !ret.class().is(PyFloat::class(vm)) {
@@ -254,42 +285,3 @@ impl PyNumber<'_> {
})
}
}
const NOT_IMPLEMENTED: PyNumberMethods = PyNumberMethods {
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_substract: None,
inplace_multiply: None,
inplace_remainder: None,
inplace_divmod: 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_devide: None,
index: None,
matrix_multiply: None,
inplace_matrix_multiply: None,
};

View File

@@ -8,10 +8,7 @@ pub fn warn(
stack_level: usize,
vm: &VirtualMachine,
) -> PyResult<()> {
// let module = vm.import("warnings", None, 0)?;
// let func = module.get_attr("warn", vm)?;
// vm.invoke(&func, (message, category, stack_level))?;
// TODO
// TODO: use rust warnings module
if let Ok(module) = vm.import("warnings", None, 0) {
if let Ok(func) = module.get_attr("warn", vm) {
let _ = vm.invoke(&func, (message, category.to_owned(), stack_level));

View File

@@ -375,7 +375,7 @@ fn as_number_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> Cow<'static, PyNum
})
}
),
..*PyNumberMethods::not_implemented()
..PyNumberMethods::NOT_IMPLEMENTED
})
}
@@ -1037,15 +1037,14 @@ pub trait AsSequence: PyPayload {
#[pyimpl]
pub trait AsNumber: PyPayload {
const AS_NUMBER: PyNumberMethods;
#[inline]
#[pyslot]
fn slot_as_number(zelf: &PyObject, vm: &VirtualMachine) -> Cow<'static, PyNumberMethods> {
let zelf = unsafe { zelf.downcast_unchecked_ref::<Self>() };
Self::as_number(zelf, vm)
fn as_number(_zelf: &PyObject, _vm: &VirtualMachine) -> Cow<'static, PyNumberMethods> {
Cow::Borrowed(&Self::AS_NUMBER)
}
fn as_number(zelf: &Py<Self>, vm: &VirtualMachine) -> Cow<'static, PyNumberMethods>;
fn number_downcast<'a>(number: &'a PyNumber) -> &'a Py<Self> {
unsafe { number.obj.downcast_unchecked_ref() }
}