From ea95777ec72bc8c22f9bb7cf7cdadcb1345d46d2 Mon Sep 17 00:00:00 2001 From: Kangzhi Shi Date: Sun, 29 May 2022 16:09:56 +0900 Subject: [PATCH] Simplify AsNumber trait --- vm/src/builtins/float.rs | 81 ++++++++++++++-------------- vm/src/builtins/int.rs | 92 +++++++++++++++----------------- vm/src/protocol/number.rs | 108 ++++++++++++++++++-------------------- vm/src/stdlib/warnings.rs | 5 +- vm/src/types/slot.rs | 11 ++-- 5 files changed, 138 insertions(+), 159 deletions(-) diff --git a/vm/src/builtins/float.rs b/vm/src/builtins/float.rs index 771292117..cfa2e7e25 100644 --- a/vm/src/builtins/float.rs +++ b/vm/src/builtins/float.rs @@ -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::().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, _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( + fn number_general_op( number: &PyNumber, other: &PyObject, op: F, @@ -562,49 +585,25 @@ impl PyFloat { } } - fn np_float_op(number: &PyNumber, other: &PyObject, op: F, vm: &VirtualMachine) -> PyResult + fn number_float_op( + 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 { + fn number_float(number: &PyNumber, vm: &VirtualMachine) -> PyRef { if let Some(zelf) = number.obj.downcast_ref_if_exact::(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: diff --git a/vm/src/builtins/int.rs b/vm/src/builtins/int.rs index c4baea3a2..37405831c 100644 --- a/vm/src/builtins/int.rs +++ b/vm/src/builtins/int.rs @@ -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, _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(number: &PyNumber, other: &PyObject, op: F, vm: &VirtualMachine) -> PyResult + fn number_general_op( + 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(number: &PyNumber, other: &PyObject, op: F, vm: &VirtualMachine) -> PyResult + fn number_int_op(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::(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)] diff --git a/vm/src/protocol/number.rs b/vm/src/protocol/number.rs index 2868ca8bd..046ba8fae 100644 --- a/vm/src/protocol/number.rs +++ b/vm/src/protocol/number.rs @@ -34,7 +34,7 @@ pub struct PyNumberMethods { pub float: Option PyResult>>, pub inplace_add: Option PyResult>, - pub inplace_substract: Option PyResult>, + pub inplace_subtract: Option PyResult>, pub inplace_multiply: Option PyResult>, pub inplace_remainder: Option PyResult>, pub inplace_divmod: Option PyResult>, @@ -48,7 +48,7 @@ pub struct PyNumberMethods { pub floor_divide: Option PyResult>, pub true_divide: Option PyResult>, pub inplace_floor_divide: Option PyResult>, - pub inplace_true_devide: Option PyResult>, + pub inplace_true_divide: Option PyResult>, pub index: Option PyResult>, @@ -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::() }) + if let Some(i) = self.obj.downcast_ref_if_exact::(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> { - if self.obj.class().is(PyInt::class(vm)) { - Ok(Some(unsafe { - self.obj.to_owned().downcast_unchecked::() - })) - } else if let Some(i) = self.obj.downcast_ref::() { + if let Some(i) = self.obj.downcast_ref_if_exact::(vm) { Ok(Some(i.to_owned())) + } else if let Some(i) = self.obj.payload::() { + 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>> { - if self.obj.class().is(PyFloat::class(vm)) { - Ok(Some(unsafe { - self.obj.to_owned().downcast_unchecked::() - })) + if let Some(float) = self.obj.downcast_ref_if_exact::(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, -}; diff --git a/vm/src/stdlib/warnings.rs b/vm/src/stdlib/warnings.rs index 4bf14ef22..7eca878a4 100644 --- a/vm/src/stdlib/warnings.rs +++ b/vm/src/stdlib/warnings.rs @@ -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)); diff --git a/vm/src/types/slot.rs b/vm/src/types/slot.rs index 0ca434398..38ad64654 100644 --- a/vm/src/types/slot.rs +++ b/vm/src/types/slot.rs @@ -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::as_number(zelf, vm) + fn as_number(_zelf: &PyObject, _vm: &VirtualMachine) -> Cow<'static, PyNumberMethods> { + Cow::Borrowed(&Self::AS_NUMBER) } - fn as_number(zelf: &Py, vm: &VirtualMachine) -> Cow<'static, PyNumberMethods>; - fn number_downcast<'a>(number: &'a PyNumber) -> &'a Py { unsafe { number.obj.downcast_unchecked_ref() } }