From 55580759f9801b7d62efba224cb5a36cc5578ecf Mon Sep 17 00:00:00 2001 From: Owen Leung Date: Sun, 14 Jul 2024 11:40:29 +0800 Subject: [PATCH 1/4] Implement PartialEq for PyFloat Implement PartialEq for PyFloat --- src/types/float.rs | 184 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 180 insertions(+), 4 deletions(-) diff --git a/src/types/float.rs b/src/types/float.rs index 0a981d60cec..c2a6a7e62a1 100644 --- a/src/types/float.rs +++ b/src/types/float.rs @@ -1,10 +1,7 @@ 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, -}; +use crate::{ffi, ffi_ptr_ext::FfiPtrExt, instance::Bound, FromPyObject, IntoPy, PyAny, PyErr, PyObject, PyResult, Python, ToPyObject, Borrowed}; use std::os::raw::c_double; /// Represents a Python `float` object. @@ -140,6 +137,122 @@ 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 { + if let Ok(val) = self.extract::<$float_type>(){ + val == *other + } else { + false + } + } + } + + impl PartialEq<$float_type> for &Bound<'_, PyFloat> { + #[inline] + fn eq(&self, other: &$float_type) -> bool { + if let Ok(val) = self.extract::<$float_type>(){ + val == *other + } else { + false + } + } + } + + impl PartialEq<&$float_type> for Bound<'_, PyFloat> { + #[inline] + fn eq(&self, other: &&$float_type) -> bool { + if let Ok(val) = self.extract::<$float_type>(){ + val == **other + } else { + false + } + } + } + + impl PartialEq> for $float_type { + #[inline] + fn eq(&self, other: &Bound<'_, PyFloat>) -> bool { + if let Ok(val) = other.extract::<$float_type>() { + val == *self + } else { + false + } + } + } + + impl PartialEq<&'_ Bound<'_, PyFloat>> for $float_type { + #[inline] + fn eq(&self, other: &&'_ Bound<'_, PyFloat>) -> bool { + if let Ok(val) = other.extract::<$float_type>() { + val == *self + } else { + false + } + } + } + + impl PartialEq> for &'_ $float_type { + #[inline] + fn eq(&self, other: &Bound<'_, PyFloat>) -> bool { + if let Ok(val) = other.extract::<$float_type>() { + val == **self + } else { + false + } + } + } + + impl PartialEq<$float_type> for Borrowed<'_, '_, PyFloat> { + #[inline] + fn eq(&self, other: &$float_type) -> bool { + if let Ok(val) = self.extract::<$float_type>(){ + val == *other + } else { + false + } + } + } + + impl PartialEq<&$float_type> for Borrowed<'_, '_, PyFloat> { + #[inline] + fn eq(&self, other: &&$float_type) -> bool { + if let Ok(val) = self.extract::<$float_type>(){ + val == **other + } else { + false + } + } + } + + impl PartialEq> for $float_type { + #[inline] + fn eq(&self, other: &Borrowed<'_, '_, PyFloat>) -> bool { + if let Ok(val) = other.extract::<$float_type>() { + val == *self + } else { + false + } + } + } + + impl PartialEq> for &$float_type { + #[inline] + fn eq(&self, other: &Borrowed<'_, '_, PyFloat>) -> bool { + if let Ok(val) = other.extract::<$float_type>() { + val == **self + } else { + false + } + } + } +}} + +impl_partial_eq_for_float!(f64); +impl_partial_eq_for_float!(f32); + #[cfg(test)] mod tests { use crate::{ @@ -177,4 +290,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); + }); + } } From 72f8d2e62189fb71fe2f1e773c629b5555f22b31 Mon Sep 17 00:00:00 2001 From: Owen Leung Date: Sun, 14 Jul 2024 11:46:47 +0800 Subject: [PATCH 2/4] Add changelog under newsfragments, and fix failing fmt CI job --- newsfragments/4348.added.md | 1 + src/types/float.rs | 168 ++++++++++++++++++------------------ 2 files changed, 87 insertions(+), 82 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 c2a6a7e62a1..f13b033fc39 100644 --- a/src/types/float.rs +++ b/src/types/float.rs @@ -1,7 +1,10 @@ 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, Borrowed}; +use crate::{ + ffi, ffi_ptr_ext::FfiPtrExt, instance::Bound, Borrowed, FromPyObject, IntoPy, PyAny, PyErr, + PyObject, PyResult, Python, ToPyObject, +}; use std::os::raw::c_double; /// Represents a Python `float` object. @@ -139,116 +142,117 @@ 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 { - if let Ok(val) = self.extract::<$float_type>(){ - val == *other - } else { - false + impl PartialEq<$float_type> for Bound<'_, PyFloat> { + #[inline] + fn eq(&self, other: &$float_type) -> bool { + if let Ok(val) = self.extract::<$float_type>() { + val == *other + } else { + false + } } } - } - impl PartialEq<$float_type> for &Bound<'_, PyFloat> { - #[inline] - fn eq(&self, other: &$float_type) -> bool { - if let Ok(val) = self.extract::<$float_type>(){ - val == *other - } else { - false + impl PartialEq<$float_type> for &Bound<'_, PyFloat> { + #[inline] + fn eq(&self, other: &$float_type) -> bool { + if let Ok(val) = self.extract::<$float_type>() { + val == *other + } else { + false + } } } - } - impl PartialEq<&$float_type> for Bound<'_, PyFloat> { - #[inline] - fn eq(&self, other: &&$float_type) -> bool { - if let Ok(val) = self.extract::<$float_type>(){ - val == **other - } else { - false + impl PartialEq<&$float_type> for Bound<'_, PyFloat> { + #[inline] + fn eq(&self, other: &&$float_type) -> bool { + if let Ok(val) = self.extract::<$float_type>() { + val == **other + } else { + false + } } } - } - impl PartialEq> for $float_type { - #[inline] - fn eq(&self, other: &Bound<'_, PyFloat>) -> bool { - if let Ok(val) = other.extract::<$float_type>() { - val == *self - } else { - false + impl PartialEq> for $float_type { + #[inline] + fn eq(&self, other: &Bound<'_, PyFloat>) -> bool { + if let Ok(val) = other.extract::<$float_type>() { + val == *self + } else { + false + } } } - } - impl PartialEq<&'_ Bound<'_, PyFloat>> for $float_type { - #[inline] - fn eq(&self, other: &&'_ Bound<'_, PyFloat>) -> bool { - if let Ok(val) = other.extract::<$float_type>() { - val == *self - } else { - false + impl PartialEq<&'_ Bound<'_, PyFloat>> for $float_type { + #[inline] + fn eq(&self, other: &&'_ Bound<'_, PyFloat>) -> bool { + if let Ok(val) = other.extract::<$float_type>() { + val == *self + } else { + false + } } } - } - impl PartialEq> for &'_ $float_type { - #[inline] - fn eq(&self, other: &Bound<'_, PyFloat>) -> bool { - if let Ok(val) = other.extract::<$float_type>() { - val == **self - } else { - false + impl PartialEq> for &'_ $float_type { + #[inline] + fn eq(&self, other: &Bound<'_, PyFloat>) -> bool { + if let Ok(val) = other.extract::<$float_type>() { + val == **self + } else { + false + } } } - } - impl PartialEq<$float_type> for Borrowed<'_, '_, PyFloat> { - #[inline] - fn eq(&self, other: &$float_type) -> bool { - if let Ok(val) = self.extract::<$float_type>(){ - val == *other - } else { - false + impl PartialEq<$float_type> for Borrowed<'_, '_, PyFloat> { + #[inline] + fn eq(&self, other: &$float_type) -> bool { + if let Ok(val) = self.extract::<$float_type>() { + val == *other + } else { + false + } } } - } - impl PartialEq<&$float_type> for Borrowed<'_, '_, PyFloat> { - #[inline] - fn eq(&self, other: &&$float_type) -> bool { - if let Ok(val) = self.extract::<$float_type>(){ - val == **other - } else { - false + impl PartialEq<&$float_type> for Borrowed<'_, '_, PyFloat> { + #[inline] + fn eq(&self, other: &&$float_type) -> bool { + if let Ok(val) = self.extract::<$float_type>() { + val == **other + } else { + false + } } } - } - impl PartialEq> for $float_type { - #[inline] - fn eq(&self, other: &Borrowed<'_, '_, PyFloat>) -> bool { - if let Ok(val) = other.extract::<$float_type>() { - val == *self - } else { - false + impl PartialEq> for $float_type { + #[inline] + fn eq(&self, other: &Borrowed<'_, '_, PyFloat>) -> bool { + if let Ok(val) = other.extract::<$float_type>() { + val == *self + } else { + false + } } } - } - impl PartialEq> for &$float_type { - #[inline] - fn eq(&self, other: &Borrowed<'_, '_, PyFloat>) -> bool { - if let Ok(val) = other.extract::<$float_type>() { - val == **self - } else { - false + impl PartialEq> for &$float_type { + #[inline] + fn eq(&self, other: &Borrowed<'_, '_, PyFloat>) -> bool { + if let Ok(val) = other.extract::<$float_type>() { + val == **self + } else { + false + } } } - } -}} + }; +} impl_partial_eq_for_float!(f64); impl_partial_eq_for_float!(f32); From ec20d12871bb0281ff17476867332ea6bcd9c298 Mon Sep 17 00:00:00 2001 From: Owen Leung Date: Mon, 15 Jul 2024 11:07:15 +0800 Subject: [PATCH 3/4] Use match arm instead of if else --- src/types/float.rs | 70 ++++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 40 deletions(-) diff --git a/src/types/float.rs b/src/types/float.rs index f13b033fc39..ffa211f1882 100644 --- a/src/types/float.rs +++ b/src/types/float.rs @@ -145,10 +145,9 @@ macro_rules! impl_partial_eq_for_float { impl PartialEq<$float_type> for Bound<'_, PyFloat> { #[inline] fn eq(&self, other: &$float_type) -> bool { - if let Ok(val) = self.extract::<$float_type>() { - val == *other - } else { - false + match self.extract::<$float_type>() { + Ok(val) => val == *other, + Err(_) => false, } } } @@ -156,10 +155,9 @@ macro_rules! impl_partial_eq_for_float { impl PartialEq<$float_type> for &Bound<'_, PyFloat> { #[inline] fn eq(&self, other: &$float_type) -> bool { - if let Ok(val) = self.extract::<$float_type>() { - val == *other - } else { - false + match self.extract::<$float_type>() { + Ok(val) => val == *other, + Err(_) => false, } } } @@ -167,10 +165,9 @@ macro_rules! impl_partial_eq_for_float { impl PartialEq<&$float_type> for Bound<'_, PyFloat> { #[inline] fn eq(&self, other: &&$float_type) -> bool { - if let Ok(val) = self.extract::<$float_type>() { - val == **other - } else { - false + match self.extract::<$float_type>() { + Ok(val) => val == **other, + Err(_) => false, } } } @@ -178,10 +175,9 @@ macro_rules! impl_partial_eq_for_float { impl PartialEq> for $float_type { #[inline] fn eq(&self, other: &Bound<'_, PyFloat>) -> bool { - if let Ok(val) = other.extract::<$float_type>() { - val == *self - } else { - false + match other.extract::<$float_type>() { + Ok(val) => val == *self, + Err(_) => false, } } } @@ -189,10 +185,9 @@ macro_rules! impl_partial_eq_for_float { impl PartialEq<&'_ Bound<'_, PyFloat>> for $float_type { #[inline] fn eq(&self, other: &&'_ Bound<'_, PyFloat>) -> bool { - if let Ok(val) = other.extract::<$float_type>() { - val == *self - } else { - false + match other.extract::<$float_type>() { + Ok(val) => val == *self, + Err(_) => false, } } } @@ -200,10 +195,9 @@ macro_rules! impl_partial_eq_for_float { impl PartialEq> for &'_ $float_type { #[inline] fn eq(&self, other: &Bound<'_, PyFloat>) -> bool { - if let Ok(val) = other.extract::<$float_type>() { - val == **self - } else { - false + match other.extract::<$float_type>() { + Ok(val) => val == **self, + Err(_) => false, } } } @@ -211,10 +205,9 @@ macro_rules! impl_partial_eq_for_float { impl PartialEq<$float_type> for Borrowed<'_, '_, PyFloat> { #[inline] fn eq(&self, other: &$float_type) -> bool { - if let Ok(val) = self.extract::<$float_type>() { - val == *other - } else { - false + match self.extract::<$float_type>() { + Ok(val) => val == *other, + Err(_) => false, } } } @@ -222,10 +215,9 @@ macro_rules! impl_partial_eq_for_float { impl PartialEq<&$float_type> for Borrowed<'_, '_, PyFloat> { #[inline] fn eq(&self, other: &&$float_type) -> bool { - if let Ok(val) = self.extract::<$float_type>() { - val == **other - } else { - false + match self.extract::<$float_type>() { + Ok(val) => val == **other, + Err(_) => false, } } } @@ -233,10 +225,9 @@ macro_rules! impl_partial_eq_for_float { impl PartialEq> for $float_type { #[inline] fn eq(&self, other: &Borrowed<'_, '_, PyFloat>) -> bool { - if let Ok(val) = other.extract::<$float_type>() { - val == *self - } else { - false + match other.extract::<$float_type>() { + Ok(val) => val == *self, + Err(_) => false, } } } @@ -244,10 +235,9 @@ macro_rules! impl_partial_eq_for_float { impl PartialEq> for &$float_type { #[inline] fn eq(&self, other: &Borrowed<'_, '_, PyFloat>) -> bool { - if let Ok(val) = other.extract::<$float_type>() { - val == **self - } else { - false + match other.extract::<$float_type>() { + Ok(val) => val == **self, + Err(_) => false, } } } From 2626ad4efc824e3cd1aa82c183c25084244e5955 Mon Sep 17 00:00:00 2001 From: Owen Leung Date: Tue, 16 Jul 2024 20:36:22 +0800 Subject: [PATCH 4/4] use value API instead of extract API --- src/types/float.rs | 50 ++++++++++------------------------------------ 1 file changed, 10 insertions(+), 40 deletions(-) diff --git a/src/types/float.rs b/src/types/float.rs index ffa211f1882..b1992d3983a 100644 --- a/src/types/float.rs +++ b/src/types/float.rs @@ -145,100 +145,70 @@ macro_rules! impl_partial_eq_for_float { impl PartialEq<$float_type> for Bound<'_, PyFloat> { #[inline] fn eq(&self, other: &$float_type) -> bool { - match self.extract::<$float_type>() { - Ok(val) => val == *other, - Err(_) => false, - } + self.value() as $float_type == *other } } impl PartialEq<$float_type> for &Bound<'_, PyFloat> { #[inline] fn eq(&self, other: &$float_type) -> bool { - match self.extract::<$float_type>() { - Ok(val) => val == *other, - Err(_) => false, - } + self.value() as $float_type == *other } } impl PartialEq<&$float_type> for Bound<'_, PyFloat> { #[inline] fn eq(&self, other: &&$float_type) -> bool { - match self.extract::<$float_type>() { - Ok(val) => val == **other, - Err(_) => false, - } + self.value() as $float_type == **other } } impl PartialEq> for $float_type { #[inline] fn eq(&self, other: &Bound<'_, PyFloat>) -> bool { - match other.extract::<$float_type>() { - Ok(val) => val == *self, - Err(_) => false, - } + other.value() as $float_type == *self } } impl PartialEq<&'_ Bound<'_, PyFloat>> for $float_type { #[inline] fn eq(&self, other: &&'_ Bound<'_, PyFloat>) -> bool { - match other.extract::<$float_type>() { - Ok(val) => val == *self, - Err(_) => false, - } + other.value() as $float_type == *self } } impl PartialEq> for &'_ $float_type { #[inline] fn eq(&self, other: &Bound<'_, PyFloat>) -> bool { - match other.extract::<$float_type>() { - Ok(val) => val == **self, - Err(_) => false, - } + other.value() as $float_type == **self } } impl PartialEq<$float_type> for Borrowed<'_, '_, PyFloat> { #[inline] fn eq(&self, other: &$float_type) -> bool { - match self.extract::<$float_type>() { - Ok(val) => val == *other, - Err(_) => false, - } + self.value() as $float_type == *other } } impl PartialEq<&$float_type> for Borrowed<'_, '_, PyFloat> { #[inline] fn eq(&self, other: &&$float_type) -> bool { - match self.extract::<$float_type>() { - Ok(val) => val == **other, - Err(_) => false, - } + self.value() as $float_type == **other } } impl PartialEq> for $float_type { #[inline] fn eq(&self, other: &Borrowed<'_, '_, PyFloat>) -> bool { - match other.extract::<$float_type>() { - Ok(val) => val == *self, - Err(_) => false, - } + other.value() as $float_type == *self } } impl PartialEq> for &$float_type { #[inline] fn eq(&self, other: &Borrowed<'_, '_, PyFloat>) -> bool { - match other.extract::<$float_type>() { - Ok(val) => val == **self, - Err(_) => false, - } + other.value() as $float_type == **self } } };