|
1 | 1 | use super::{float, PyStr, PyType, PyTypeRef};
|
2 | 2 | use crate::{
|
3 | 3 | class::PyClassImpl,
|
4 |
| - convert::ToPyObject, |
| 4 | + convert::{ToPyObject, ToPyResult}, |
5 | 5 | function::{
|
6 | 6 | OptionalArg, OptionalOption,
|
7 | 7 | PyArithmeticValue::{self, *},
|
8 | 8 | PyComparisonValue,
|
9 | 9 | },
|
10 | 10 | identifier,
|
11 |
| - types::{Comparable, Constructor, Hashable, PyComparisonOp}, |
| 11 | + protocol::{PyNumber, PyNumberMethods}, |
| 12 | + types::{AsNumber, Comparable, Constructor, Hashable, PyComparisonOp}, |
12 | 13 | AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
|
13 | 14 | };
|
14 | 15 | use num_complex::Complex64;
|
@@ -203,7 +204,7 @@ impl PyComplex {
|
203 | 204 | }
|
204 | 205 | }
|
205 | 206 |
|
206 |
| -#[pyimpl(flags(BASETYPE), with(Comparable, Hashable, Constructor))] |
| 207 | +#[pyimpl(flags(BASETYPE), with(Comparable, Hashable, Constructor, AsNumber))] |
207 | 208 | impl PyComplex {
|
208 | 209 | #[pymethod(magic)]
|
209 | 210 | fn complex(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyRef<PyComplex> {
|
@@ -419,6 +420,72 @@ impl Hashable for PyComplex {
|
419 | 420 | }
|
420 | 421 | }
|
421 | 422 |
|
| 423 | +impl AsNumber for PyComplex { |
| 424 | + const AS_NUMBER: PyNumberMethods = PyNumberMethods { |
| 425 | + add: Some(|number, other, vm| Self::number_complex_op(number, other, |a, b| a + b, vm)), |
| 426 | + subtract: Some(|number, other, vm| { |
| 427 | + Self::number_complex_op(number, other, |a, b| a - b, vm) |
| 428 | + }), |
| 429 | + multiply: Some(|number, other, vm| { |
| 430 | + Self::number_complex_op(number, other, |a, b| a * b, vm) |
| 431 | + }), |
| 432 | + power: Some(|number, other, vm| Self::number_general_op(number, other, inner_pow, vm)), |
| 433 | + negative: Some(|number, vm| { |
| 434 | + let value = Self::number_downcast(number).value; |
| 435 | + (-value).to_pyresult(vm) |
| 436 | + }), |
| 437 | + positive: Some(|number, vm| Self::number_complex(number, vm).to_pyresult(vm)), |
| 438 | + absolute: Some(|number, vm| { |
| 439 | + let value = Self::number_downcast(number).value; |
| 440 | + value.norm().to_pyresult(vm) |
| 441 | + }), |
| 442 | + boolean: Some(|number, _vm| Ok(Self::number_downcast(number).value.is_zero())), |
| 443 | + true_divide: Some(|number, other, vm| { |
| 444 | + Self::number_general_op(number, other, inner_div, vm) |
| 445 | + }), |
| 446 | + ..PyNumberMethods::NOT_IMPLEMENTED |
| 447 | + }; |
| 448 | +} |
| 449 | + |
| 450 | +impl PyComplex { |
| 451 | + fn number_general_op<F, R>( |
| 452 | + number: &PyNumber, |
| 453 | + other: &PyObject, |
| 454 | + op: F, |
| 455 | + vm: &VirtualMachine, |
| 456 | + ) -> PyResult |
| 457 | + where |
| 458 | + F: FnOnce(Complex64, Complex64, &VirtualMachine) -> R, |
| 459 | + R: ToPyResult, |
| 460 | + { |
| 461 | + if let (Some(a), Some(b)) = (number.obj.payload::<Self>(), other.payload::<Self>()) { |
| 462 | + op(a.value, b.value, vm).to_pyresult(vm) |
| 463 | + } else { |
| 464 | + Ok(vm.ctx.not_implemented()) |
| 465 | + } |
| 466 | + } |
| 467 | + |
| 468 | + fn number_complex_op<F>( |
| 469 | + number: &PyNumber, |
| 470 | + other: &PyObject, |
| 471 | + op: F, |
| 472 | + vm: &VirtualMachine, |
| 473 | + ) -> PyResult |
| 474 | + where |
| 475 | + F: FnOnce(Complex64, Complex64) -> Complex64, |
| 476 | + { |
| 477 | + Self::number_general_op(number, other, |a, b, _vm| op(a, b), vm) |
| 478 | + } |
| 479 | + |
| 480 | + fn number_complex(number: &PyNumber, vm: &VirtualMachine) -> PyRef<PyComplex> { |
| 481 | + if let Some(zelf) = number.obj.downcast_ref_if_exact::<Self>(vm) { |
| 482 | + zelf.to_owned() |
| 483 | + } else { |
| 484 | + vm.ctx.new_complex(Self::number_downcast(number).value) |
| 485 | + } |
| 486 | + } |
| 487 | +} |
| 488 | + |
422 | 489 | #[derive(FromArgs)]
|
423 | 490 | pub struct ComplexArgs {
|
424 | 491 | #[pyarg(any, optional)]
|
|
0 commit comments