Skip to content

Commit

Permalink
Add several missing wrappers to PyAnyMethods
Browse files Browse the repository at this point in the history
  • Loading branch information
xen0n committed Jun 19, 2024
1 parent 0e142f0 commit 8d48a7f
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 0 deletions.
1 change: 1 addition & 0 deletions newsfragments/4264.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added `PyAnyMethods::{bitnot, matmul, floor_div, rem, divmod}` for completeness.
52 changes: 52 additions & 0 deletions src/types/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1143,6 +1143,9 @@ pub trait PyAnyMethods<'py>: crate::sealed::Sealed {
/// Equivalent to the Python expression `abs(self)`.
fn abs(&self) -> PyResult<Bound<'py, PyAny>>;

/// Computes `~self`.
fn bitnot(&self) -> PyResult<Bound<'py, PyAny>>;

/// Tests whether this object is less than another.
///
/// This is equivalent to the Python expression `self < other`.
Expand Down Expand Up @@ -1200,11 +1203,31 @@ pub trait PyAnyMethods<'py>: crate::sealed::Sealed {
where
O: ToPyObject;

/// Computes `self @ other`.
fn matmul<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
where
O: ToPyObject;

/// Computes `self / other`.
fn div<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
where
O: ToPyObject;

/// Computes `self // other`.
fn floor_div<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
where
O: ToPyObject;

/// Computes `self % other`.
fn rem<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
where
O: ToPyObject;

/// Computes `divmod(self, other)`.
fn divmod<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
where
O: ToPyObject;

/// Computes `self << other`.
fn lshift<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
where
Expand Down Expand Up @@ -1898,6 +1921,14 @@ impl<'py> PyAnyMethods<'py> for Bound<'py, PyAny> {
inner(self)
}

fn bitnot(&self) -> PyResult<Bound<'py, PyAny>> {
fn inner<'py>(any: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyAny>> {
unsafe { ffi::PyNumber_Invert(any.as_ptr()).assume_owned_or_err(any.py()) }
}

inner(self)
}

fn lt<O>(&self, other: O) -> PyResult<bool>
where
O: ToPyObject,
Expand Down Expand Up @@ -1949,13 +1980,34 @@ impl<'py> PyAnyMethods<'py> for Bound<'py, PyAny> {
implement_binop!(add, PyNumber_Add, "+");
implement_binop!(sub, PyNumber_Subtract, "-");
implement_binop!(mul, PyNumber_Multiply, "*");
implement_binop!(matmul, PyNumber_MatrixMultiply, "@");
implement_binop!(div, PyNumber_TrueDivide, "/");
implement_binop!(floor_div, PyNumber_FloorDivide, "//");
implement_binop!(rem, PyNumber_Remainder, "%");
implement_binop!(lshift, PyNumber_Lshift, "<<");
implement_binop!(rshift, PyNumber_Rshift, ">>");
implement_binop!(bitand, PyNumber_And, "&");
implement_binop!(bitor, PyNumber_Or, "|");
implement_binop!(bitxor, PyNumber_Xor, "^");

/// Computes `divmod(self, other)`.
fn divmod<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
where
O: ToPyObject,
{
fn inner<'py>(
any: &Bound<'py, PyAny>,
other: Bound<'_, PyAny>,
) -> PyResult<Bound<'py, PyAny>> {
unsafe {
ffi::PyNumber_Divmod(any.as_ptr(), other.as_ptr()).assume_owned_or_err(any.py())
}
}

let py = self.py();
inner(self, other.to_object(py).into_bound(py))
}

/// Computes `self ** other % modulus` (`pow(self, other, modulus)`).
/// `py.None()` may be passed for the `modulus`.
fn pow<O1, O2>(&self, other: O1, modulus: O2) -> PyResult<Bound<'py, PyAny>>
Expand Down
30 changes: 30 additions & 0 deletions tests/test_arithmetics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,26 @@ impl BinaryArithmetic {
format!("BA * {:?}", rhs)
}

fn __matmul__(&self, rhs: &Bound<'_, PyAny>) -> String {
format!("BA @ {:?}", rhs)
}

fn __truediv__(&self, rhs: &Bound<'_, PyAny>) -> String {
format!("BA / {:?}", rhs)
}

fn __floordiv__(&self, rhs: &Bound<'_, PyAny>) -> String {
format!("BA // {:?}", rhs)
}

fn __mod__(&self, rhs: &Bound<'_, PyAny>) -> String {
format!("BA % {:?}", rhs)
}

fn __divmod__(&self, rhs: &Bound<'_, PyAny>) -> String {
format!("divmod(BA, {:?})", rhs)
}

fn __lshift__(&self, rhs: &Bound<'_, PyAny>) -> String {
format!("BA << {:?}", rhs)
}
Expand Down Expand Up @@ -217,6 +233,11 @@ fn binary_arithmetic() {
py_run!(py, c, "assert c + 1 == 'BA + 1'");
py_run!(py, c, "assert c - 1 == 'BA - 1'");
py_run!(py, c, "assert c * 1 == 'BA * 1'");
py_run!(py, c, "assert c @ 1 == 'BA @ 1'");
py_run!(py, c, "assert c / 1 == 'BA / 1'");
py_run!(py, c, "assert c // 1 == 'BA // 1'");
py_run!(py, c, "assert c % 1 == 'BA % 1'");
py_run!(py, c, "assert divmod(c, 1) == 'divmod(BA, 1)'");
py_run!(py, c, "assert c << 1 == 'BA << 1'");
py_run!(py, c, "assert c >> 1 == 'BA >> 1'");
py_run!(py, c, "assert c & 1 == 'BA & 1'");
Expand All @@ -230,6 +251,11 @@ fn binary_arithmetic() {
py_expect_exception!(py, c, "1 + c", PyTypeError);
py_expect_exception!(py, c, "1 - c", PyTypeError);
py_expect_exception!(py, c, "1 * c", PyTypeError);
py_expect_exception!(py, c, "1 @ c", PyTypeError);
py_expect_exception!(py, c, "1 / c", PyTypeError);
py_expect_exception!(py, c, "1 // c", PyTypeError);
py_expect_exception!(py, c, "1 % c", PyTypeError);
py_expect_exception!(py, c, "divmod(1, c)", PyTypeError);
py_expect_exception!(py, c, "1 << c", PyTypeError);
py_expect_exception!(py, c, "1 >> c", PyTypeError);
py_expect_exception!(py, c, "1 & c", PyTypeError);
Expand All @@ -243,7 +269,11 @@ fn binary_arithmetic() {
assert_py_eq!(c.add(&c).unwrap(), "BA + BA");
assert_py_eq!(c.sub(&c).unwrap(), "BA - BA");
assert_py_eq!(c.mul(&c).unwrap(), "BA * BA");
assert_py_eq!(c.matmul(&c).unwrap(), "BA @ BA");
assert_py_eq!(c.div(&c).unwrap(), "BA / BA");
assert_py_eq!(c.floor_div(&c).unwrap(), "BA // BA");
assert_py_eq!(c.rem(&c).unwrap(), "BA % BA");
assert_py_eq!(c.divmod(&c).unwrap(), "divmod(BA, BA)");
assert_py_eq!(c.lshift(&c).unwrap(), "BA << BA");
assert_py_eq!(c.rshift(&c).unwrap(), "BA >> BA");
assert_py_eq!(c.bitand(&c).unwrap(), "BA & BA");
Expand Down

0 comments on commit 8d48a7f

Please sign in to comment.