From 361686a09c65080aa41d3e5419f5ea4ea8834946 Mon Sep 17 00:00:00 2001 From: MrGVSV Date: Tue, 26 Apr 2022 19:41:26 +0000 Subject: [PATCH] bevy_reflect: Added `PartialEq` to reflected `f32` & `f64` (#4217) # Objective Comparing two reflected floating points would always fail: ```rust let a: &dyn Reflect = &1.23_f32; let b: &dyn Reflect = &1.23_f32; // Panics: assert!(a.reflect_partial_eq(b).unwrap_or_default()); ``` The comparison returns `None` since `f32` (and `f64`) does not have a reflected `PartialEq` implementation. ## Solution Include `PartialEq` in the `impl_reflect_value!` macro call for both `f32` and `f64`. `Hash` is still excluded since neither implement `Hash`. Also added equality tests for some of the common types from `std` (including `f32`). --- crates/bevy_reflect/src/impls/std.rs | 65 +++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/crates/bevy_reflect/src/impls/std.rs b/crates/bevy_reflect/src/impls/std.rs index 4a60096b7f..b84b18a93f 100644 --- a/crates/bevy_reflect/src/impls/std.rs +++ b/crates/bevy_reflect/src/impls/std.rs @@ -28,8 +28,8 @@ impl_reflect_value!(i32(Hash, PartialEq, Serialize, Deserialize)); impl_reflect_value!(i64(Hash, PartialEq, Serialize, Deserialize)); impl_reflect_value!(i128(Hash, PartialEq, Serialize, Deserialize)); impl_reflect_value!(isize(Hash, PartialEq, Serialize, Deserialize)); -impl_reflect_value!(f32(Serialize, Deserialize)); -impl_reflect_value!(f64(Serialize, Deserialize)); +impl_reflect_value!(f32(PartialEq, Serialize, Deserialize)); +impl_reflect_value!(f64(PartialEq, Serialize, Deserialize)); impl_reflect_value!(String(Hash, PartialEq, Serialize, Deserialize)); impl_reflect_value!(Option Deserialize<'de> + Reflect + 'static>(Serialize, Deserialize)); impl_reflect_value!(HashSet Deserialize<'de> + Send + Sync + 'static>(Serialize, Deserialize)); @@ -392,9 +392,70 @@ impl FromReflect for Cow<'static, str> { #[cfg(test)] mod tests { use crate::Reflect; + use bevy_utils::HashMap; + use std::f32::consts::{PI, TAU}; #[test] fn can_serialize_duration() { assert!(std::time::Duration::ZERO.serializable().is_some()); } + + #[test] + fn should_partial_eq_i32() { + let a: &dyn Reflect = &123_i32; + let b: &dyn Reflect = &123_i32; + let c: &dyn Reflect = &321_i32; + assert!(a.reflect_partial_eq(b).unwrap_or_default()); + assert!(!a.reflect_partial_eq(c).unwrap_or_default()); + } + + #[test] + fn should_partial_eq_f32() { + let a: &dyn Reflect = &PI; + let b: &dyn Reflect = &PI; + let c: &dyn Reflect = &TAU; + assert!(a.reflect_partial_eq(b).unwrap_or_default()); + assert!(!a.reflect_partial_eq(c).unwrap_or_default()); + } + + #[test] + fn should_partial_eq_string() { + let a: &dyn Reflect = &String::from("Hello"); + let b: &dyn Reflect = &String::from("Hello"); + let c: &dyn Reflect = &String::from("World"); + assert!(a.reflect_partial_eq(b).unwrap_or_default()); + assert!(!a.reflect_partial_eq(c).unwrap_or_default()); + } + + #[test] + fn should_partial_eq_vec() { + let a: &dyn Reflect = &vec![1, 2, 3]; + let b: &dyn Reflect = &vec![1, 2, 3]; + let c: &dyn Reflect = &vec![3, 2, 1]; + assert!(a.reflect_partial_eq(b).unwrap_or_default()); + assert!(!a.reflect_partial_eq(c).unwrap_or_default()); + } + + #[test] + fn should_partial_eq_hash_map() { + let mut a = HashMap::new(); + a.insert(0usize, 1.23_f64); + let b = a.clone(); + let mut c = HashMap::new(); + c.insert(0usize, 3.21_f64); + + let a: &dyn Reflect = &a; + let b: &dyn Reflect = &b; + let c: &dyn Reflect = &c; + assert!(a.reflect_partial_eq(b).unwrap_or_default()); + assert!(!a.reflect_partial_eq(c).unwrap_or_default()); + } + + #[test] + fn should_not_partial_eq_option() { + // Option does not contain a `PartialEq` implementation, so it should return `None` + let a: &dyn Reflect = &Some(123); + let b: &dyn Reflect = &Some(123); + assert_eq!(None, a.reflect_partial_eq(b)); + } }