diff --git a/tests/snippets/stdlib_array.py b/tests/snippets/stdlib_array.py index 0ef0969ff..8d4b9d85e 100644 --- a/tests/snippets/stdlib_array.py +++ b/tests/snippets/stdlib_array.py @@ -19,4 +19,16 @@ a = array("b", [0, 1, 2, 3]) b = a assert a.__ne__(b) is False b = array("B", [3, 2, 1, 0]) -assert a.__ne__(b) is True \ No newline at end of file +assert a.__ne__(b) is True + +def test_float_with_integer_input(): + f = array("f", [0, 1, 2.0, 3.0]) + f.append(4) + f.insert(0, -1) + assert f.count(4) == 1 + f.remove(1) + assert f.index(0) == 1 + f[0] = -2 + assert f == array("f", [-2, 0, 2, 3, 4]) + +test_float_with_integer_input() diff --git a/vm/src/stdlib/array.rs b/vm/src/stdlib/array.rs index d01773e9d..c5a6e0a64 100644 --- a/vm/src/stdlib/array.rs +++ b/vm/src/stdlib/array.rs @@ -4,6 +4,7 @@ use crate::common::cell::{ }; use crate::function::OptionalArg; use crate::obj::objbytes::PyBytesRef; +use crate::obj::objfloat::try_float; use crate::obj::objsequence::PySliceableSequence; use crate::obj::objslice::PySliceRef; use crate::obj::objstr::PyStringRef; @@ -11,7 +12,7 @@ use crate::obj::objtype::PyClassRef; use crate::obj::{objbool, objiter}; use crate::pyobject::{ BorrowValue, Either, IntoPyObject, PyArithmaticValue, PyClassImpl, PyComparisonValue, - PyIterable, PyObject, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, + PyIterable, PyObject, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TypeProtocol, }; use crate::VirtualMachine; use crossbeam_utils::atomic::AtomicCell; @@ -74,7 +75,7 @@ macro_rules! def_array_enum { fn push(&mut self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { match self { $(ArrayContentType::$n(v) => { - let val = $t::try_from_object(vm, obj)?; + let val = $t::try_into_from_object(vm, obj)?; v.push(val); })* } @@ -92,7 +93,7 @@ macro_rules! def_array_enum { fn insert(&mut self, i: usize, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { match self { $(ArrayContentType::$n(v) => { - let val = $t::try_from_object(vm, obj)?; + let val = $t::try_into_from_object(vm, obj)?; v.insert(i, val); })* } @@ -102,9 +103,11 @@ macro_rules! def_array_enum { fn count(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult { match self { $(ArrayContentType::$n(v) => { - Ok(>::try_from_object(vm, obj)?.map_or(0, |val| { + Ok(if let Ok(val) = $t::try_into_from_object(vm, obj) { v.iter().filter(|&&a| a == val).count() - })) + } else { + 0 + }) })* } } @@ -112,13 +115,15 @@ macro_rules! def_array_enum { fn remove(&mut self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()>{ match self { $(ArrayContentType::$n(v) => { - let pos = >::try_from_object(vm, obj)?.map_or(None, |val| { - v.iter().position(|&a| a == val) - }).ok_or_else(||vm.new_value_error("array.remove(x): x not in array".to_owned()) )?; - v.remove(pos); + if let Ok(val) = $t::try_into_from_object(vm, obj) { + if let Some(pos) = v.iter().position(|&a| a == val) { + v.remove(pos); + return Ok(()); + } + } + Err(vm.new_value_error("array.remove(x): x not in array".to_owned())) })* } - Ok(()) } fn frombytes(&mut self, b: &[u8]) { @@ -156,12 +161,15 @@ macro_rules! def_array_enum { } } - fn index(&self, x: PyObjectRef, vm: &VirtualMachine) -> PyResult> { + fn index(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult { match self { $(ArrayContentType::$n(v) => { - Ok(>::try_from_object(vm, x)?.map_or(None, |val| { - v.iter().position(|&a| a == val) - })) + if let Ok(val) = $t::try_into_from_object(vm, obj) { + if let Some(pos) = v.iter().position(|&a| a == val) { + return Ok(pos); + } + } + Err(vm.new_value_error("array.index(x): x not in array".to_owned())) })* } } @@ -228,7 +236,7 @@ macro_rules! def_array_enum { Either::A(i) => { let i = self.idx(i, "array assignment", vm)?; match self { - $(ArrayContentType::$n(v) => { v[i] = TryFromObject::try_from_object(vm, value)? },)* + $(ArrayContentType::$n(v) => { v[i] = $t::try_into_from_object(vm, value)? },)* } Ok(()) } @@ -264,6 +272,44 @@ def_array_enum!( (Double, f64, 'd'), ); +trait TryIntoFromObject: Sized { + fn try_into_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult; +} + +macro_rules! adapt_try_into_from_object { + ($(($t:ty, $f: path),)*) => {$( + impl TryIntoFromObject for $t { + fn try_into_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { + $f(vm, obj) + } + } + )*}; +} + +adapt_try_into_from_object!( + (i8, i8::try_from_object), + (u8, u8::try_from_object), + (i16, i16::try_from_object), + (u16, u16::try_from_object), + (i32, i32::try_from_object), + (u32, u32::try_from_object), + (i64, i64::try_from_object), + (u64, u64::try_from_object), + (f32, f32_try_into_from_object), + (f64, f64_try_into_from_object), +); + +fn f32_try_into_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { + try_float(&obj, vm)? + .map(|x| x as f32) + .ok_or_else(|| vm.new_type_error(format!("must be real number, not {}", obj.class().name))) +} + +fn f64_try_into_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { + try_float(&obj, vm)? + .ok_or_else(|| vm.new_type_error(format!("must be real number, not {}", obj.class().name))) +} + #[pyclass(module = "array", name = "array")] #[derive(Debug)] pub struct PyArray { @@ -364,9 +410,7 @@ impl PyArray { #[pymethod] fn index(&self, x: PyObjectRef, vm: &VirtualMachine) -> PyResult { - self.borrow_value() - .index(x, vm)? - .ok_or_else(|| vm.new_value_error("x not in array".to_owned())) + self.borrow_value().index(x, vm) } #[pymethod]