From f635afcae511e3b25aa33f657731390996905ad9 Mon Sep 17 00:00:00 2001 From: Owen Leung Date: Tue, 16 Jul 2024 21:15:26 +0800 Subject: [PATCH] Implement PartialEq for PyFloat with f64 and f32 (#4348) * Implement PartialEq for PyFloat Implement PartialEq for PyFloat * Add changelog under newsfragments, and fix failing fmt CI job * Use match arm instead of if else * use value API instead of extract API --- newsfragments/4348.added.md | 1 + src/types/float.rs | 144 +++++++++++++++++++++++++++++++++++- 2 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 newsfragments/4348.added.md diff --git a/newsfragments/4348.added.md b/newsfragments/4348.added.md new file mode 100644 index 00000000000..57d3e415187 --- /dev/null +++ b/newsfragments/4348.added.md @@ -0,0 +1 @@ +Implement `PartialEq` and `PartialEq` for `Bound<'py, PyFloat>`. \ No newline at end of file diff --git a/src/types/float.rs b/src/types/float.rs index 0a981d60cec..b1992d3983a 100644 --- a/src/types/float.rs +++ b/src/types/float.rs @@ -2,8 +2,8 @@ use super::any::PyAnyMethods; #[cfg(feature = "experimental-inspect")] use crate::inspect::types::TypeInfo; use crate::{ - ffi, ffi_ptr_ext::FfiPtrExt, instance::Bound, FromPyObject, IntoPy, PyAny, PyErr, PyObject, - PyResult, Python, ToPyObject, + ffi, ffi_ptr_ext::FfiPtrExt, instance::Bound, Borrowed, FromPyObject, IntoPy, PyAny, PyErr, + PyObject, PyResult, Python, ToPyObject, }; use std::os::raw::c_double; @@ -140,6 +140,83 @@ impl<'py> FromPyObject<'py> for f32 { } } +macro_rules! impl_partial_eq_for_float { + ($float_type: ty) => { + impl PartialEq<$float_type> for Bound<'_, PyFloat> { + #[inline] + fn eq(&self, other: &$float_type) -> bool { + self.value() as $float_type == *other + } + } + + impl PartialEq<$float_type> for &Bound<'_, PyFloat> { + #[inline] + fn eq(&self, other: &$float_type) -> bool { + self.value() as $float_type == *other + } + } + + impl PartialEq<&$float_type> for Bound<'_, PyFloat> { + #[inline] + fn eq(&self, other: &&$float_type) -> bool { + self.value() as $float_type == **other + } + } + + impl PartialEq> for $float_type { + #[inline] + fn eq(&self, other: &Bound<'_, PyFloat>) -> bool { + other.value() as $float_type == *self + } + } + + impl PartialEq<&'_ Bound<'_, PyFloat>> for $float_type { + #[inline] + fn eq(&self, other: &&'_ Bound<'_, PyFloat>) -> bool { + other.value() as $float_type == *self + } + } + + impl PartialEq> for &'_ $float_type { + #[inline] + fn eq(&self, other: &Bound<'_, PyFloat>) -> bool { + other.value() as $float_type == **self + } + } + + impl PartialEq<$float_type> for Borrowed<'_, '_, PyFloat> { + #[inline] + fn eq(&self, other: &$float_type) -> bool { + self.value() as $float_type == *other + } + } + + impl PartialEq<&$float_type> for Borrowed<'_, '_, PyFloat> { + #[inline] + fn eq(&self, other: &&$float_type) -> bool { + self.value() as $float_type == **other + } + } + + impl PartialEq> for $float_type { + #[inline] + fn eq(&self, other: &Borrowed<'_, '_, PyFloat>) -> bool { + other.value() as $float_type == *self + } + } + + impl PartialEq> for &$float_type { + #[inline] + fn eq(&self, other: &Borrowed<'_, '_, PyFloat>) -> bool { + other.value() as $float_type == **self + } + } + }; +} + +impl_partial_eq_for_float!(f64); +impl_partial_eq_for_float!(f32); + #[cfg(test)] mod tests { use crate::{ @@ -177,4 +254,67 @@ mod tests { assert_approx_eq!(v, obj.value()); }); } + + #[test] + fn test_pyfloat_comparisons() { + Python::with_gil(|py| { + let f_64 = 1.01f64; + let py_f64 = PyFloat::new_bound(py, 1.01); + let py_f64_ref = &py_f64; + let py_f64_borrowed = py_f64.as_borrowed(); + + // Bound<'_, PyFloat> == f64 and vice versa + assert_eq!(py_f64, f_64); + assert_eq!(f_64, py_f64); + + // Bound<'_, PyFloat> == &f64 and vice versa + assert_eq!(py_f64, &f_64); + assert_eq!(&f_64, py_f64); + + // &Bound<'_, PyFloat> == &f64 and vice versa + assert_eq!(py_f64_ref, f_64); + assert_eq!(f_64, py_f64_ref); + + // &Bound<'_, PyFloat> == &f64 and vice versa + assert_eq!(py_f64_ref, &f_64); + assert_eq!(&f_64, py_f64_ref); + + // Borrowed<'_, '_, PyFloat> == f64 and vice versa + assert_eq!(py_f64_borrowed, f_64); + assert_eq!(f_64, py_f64_borrowed); + + // Borrowed<'_, '_, PyFloat> == &f64 and vice versa + assert_eq!(py_f64_borrowed, &f_64); + assert_eq!(&f_64, py_f64_borrowed); + + let f_32 = 2.02f32; + let py_f32 = PyFloat::new_bound(py, 2.02); + let py_f32_ref = &py_f32; + let py_f32_borrowed = py_f32.as_borrowed(); + + // Bound<'_, PyFloat> == f32 and vice versa + assert_eq!(py_f32, f_32); + assert_eq!(f_32, py_f32); + + // Bound<'_, PyFloat> == &f32 and vice versa + assert_eq!(py_f32, &f_32); + assert_eq!(&f_32, py_f32); + + // &Bound<'_, PyFloat> == &f32 and vice versa + assert_eq!(py_f32_ref, f_32); + assert_eq!(f_32, py_f32_ref); + + // &Bound<'_, PyFloat> == &f32 and vice versa + assert_eq!(py_f32_ref, &f_32); + assert_eq!(&f_32, py_f32_ref); + + // Borrowed<'_, '_, PyFloat> == f32 and vice versa + assert_eq!(py_f32_borrowed, f_32); + assert_eq!(f_32, py_f32_borrowed); + + // Borrowed<'_, '_, PyFloat> == &f32 and vice versa + assert_eq!(py_f32_borrowed, &f_32); + assert_eq!(&f_32, py_f32_borrowed); + }); + } }