From 0965df060ceef9f1448c7e6f8b4127baf16c04e5 Mon Sep 17 00:00:00 2001 From: Dmitry Stepanov Date: Fri, 5 Jun 2026 23:06:29 +0300 Subject: [PATCH 1/8] `Reflect::try_compare` draft --- fyrox-core-derive/src/reflect.rs | 14 ++++++++++++++ fyrox-core-derive/src/reflect/args.rs | 3 +++ fyrox-core/src/math/mod.rs | 2 +- fyrox-core/src/pool/handle.rs | 6 ++++++ fyrox-core/src/pool/mod.rs | 6 ++++++ fyrox-core/src/reflect/impls.rs | 2 ++ fyrox-core/src/reflect/macros.rs | 6 ++++++ fyrox-core/src/reflect/mod.rs | 12 +++++++++--- 8 files changed, 47 insertions(+), 4 deletions(-) diff --git a/fyrox-core-derive/src/reflect.rs b/fyrox-core-derive/src/reflect.rs index 066333e78..204f23490 100644 --- a/fyrox-core-derive/src/reflect.rs +++ b/fyrox-core-derive/src/reflect.rs @@ -443,6 +443,18 @@ fn gen_impl( } }; + let try_compare = if ty_args.non_comparable { + quote! { + fn try_compare(&self, _other: &dyn Reflect) -> Option { None } + } + } else { + quote! { + fn try_compare(&self, other: &dyn Reflect) -> Option { + (other as &dyn Any).downcast_ref::().map(|other| other == self) + } + } + }; + let type_uuid_str = ty_args.type_uuid.as_str(); let type_uuid = if ty_args.generics.params.is_empty() { quote! { uuid!(#type_uuid_str) } @@ -494,6 +506,8 @@ fn gen_impl( #try_clone_box + #try_compare + fn fields_ref(&self, func: &mut dyn FnMut(&[FieldRef])) { #metadata_ref } diff --git a/fyrox-core-derive/src/reflect/args.rs b/fyrox-core-derive/src/reflect/args.rs index 45b574e0e..82cff433f 100644 --- a/fyrox-core-derive/src/reflect/args.rs +++ b/fyrox-core-derive/src/reflect/args.rs @@ -63,6 +63,9 @@ pub struct TypeArgs { #[darling(default)] pub non_cloneable: bool, + #[darling(default)] + pub non_comparable: bool, + #[darling(default)] pub clone_fn: Option, diff --git a/fyrox-core/src/math/mod.rs b/fyrox-core/src/math/mod.rs index 15043e05a..cc9bb2aec 100644 --- a/fyrox-core/src/math/mod.rs +++ b/fyrox-core/src/math/mod.rs @@ -37,7 +37,7 @@ use fyrox_core_derive::{impl_reflect, impl_visit}; impl_reflect!( #[reflect(type_uuid = "64ef33b7-d05a-4d8d-b0c7-99bcc919271f")] - pub struct Rect {} + pub struct Rect {} ); impl Visit for Rect diff --git a/fyrox-core/src/pool/handle.rs b/fyrox-core/src/pool/handle.rs index 2206e6963..29bdd96f9 100644 --- a/fyrox-core/src/pool/handle.rs +++ b/fyrox-core/src/pool/handle.rs @@ -207,6 +207,12 @@ impl Reflect for Handle { None } } + + fn try_compare(&self, other: &dyn Reflect) -> Option { + (other as &dyn std::any::Any) + .downcast_ref::() + .map(|other| other == self) + } } impl Copy for Handle {} diff --git a/fyrox-core/src/pool/mod.rs b/fyrox-core/src/pool/mod.rs index 02f259a10..985a966d2 100644 --- a/fyrox-core/src/pool/mod.rs +++ b/fyrox-core/src/pool/mod.rs @@ -170,6 +170,12 @@ where Some(Box::new(self.clone())) } + fn try_compare(&self, other: &dyn Reflect) -> Option { + (other as &dyn std::any::Any) + .downcast_ref::() + .map(|other| other == self) + } + #[inline] fn fields_ref(&self, func: &mut dyn FnMut(&[FieldRef])) { func(&[]) diff --git a/fyrox-core/src/reflect/impls.rs b/fyrox-core/src/reflect/impls.rs index ba8249907..1186e3349 100644 --- a/fyrox-core/src/reflect/impls.rs +++ b/fyrox-core/src/reflect/impls.rs @@ -334,6 +334,8 @@ macro_rules! impl_reflect_inner_mutability { Some(Box::new($clone)) } + + fn fields_ref(&$self, func: &mut dyn FnMut(&[FieldRef])) { let guard = $acquire_lock_guard; func(&[{ diff --git a/fyrox-core/src/reflect/macros.rs b/fyrox-core/src/reflect/macros.rs index cf699784a..c99ace23a 100644 --- a/fyrox-core/src/reflect/macros.rs +++ b/fyrox-core/src/reflect/macros.rs @@ -158,6 +158,12 @@ macro_rules! blank_reflect { Some(Box::new(self.clone())) } + fn try_compare(&self, other: &dyn Reflect) -> Option { + (other as &dyn std::any::Any) + .downcast_ref::() + .map(|other| other == self) + } + fn fields_ref(&self, func: &mut dyn FnMut(&[$crate::reflect::FieldRef])) { func(&[]) } diff --git a/fyrox-core/src/reflect/mod.rs b/fyrox-core/src/reflect/mod.rs index 1b789ba8d..af3c6cf27 100644 --- a/fyrox-core/src/reflect/mod.rs +++ b/fyrox-core/src/reflect/mod.rs @@ -53,6 +53,7 @@ pub mod prelude { TypeInfo, }; pub use crate::uuid::{uuid, Uuid}; + pub use std::any::Any; } #[inline] @@ -175,6 +176,11 @@ pub trait Reflect: Any + Debug { /// [`None`] for non-cloneable objects. fn try_clone_box(&self) -> Option>; + /// Tries to compare this object with some other. The result is `Some(bool)` if the underlying + /// type implements [`PartialEq`] trait, `None` - otherwise or if the type is marked with + /// `#[reflect(non_comparable)]` attribute. + fn try_compare(&self, other: &dyn Reflect) -> Option; + /// Calls the given closure with the reference to a slice that contains description for all /// fields in the object. fn fields_ref(&self, func: &mut dyn FnMut(&[FieldRef])); @@ -1021,7 +1027,7 @@ mod test { }, } - #[derive(Reflect, Clone, Default, Debug)] + #[derive(Reflect, Clone, Default, Debug, PartialEq)] #[reflect(type_uuid = "97718a85-3901-407e-9347-b684c0047743")] struct Foo { enum_field: InheritableVariable, @@ -1031,13 +1037,13 @@ mod test { hash_map: HashMap, } - #[derive(Reflect, Clone, Default, Debug)] + #[derive(Reflect, Clone, Default, Debug, PartialEq)] #[reflect(type_uuid = "9465ea72-dd27-43f3-8ccf-b634e4b2887f")] struct Item { payload: u32, } - #[derive(Reflect, Clone, Default, Debug)] + #[derive(Reflect, Clone, Default, Debug, PartialEq)] #[reflect(type_uuid = "8fb478ac-e4c4-4762-a43a-451147e6e509")] struct Bar { stuff: String, From 7a798f7e683f44a3d4fef01c9c7df14dae29c091 Mon Sep 17 00:00:00 2001 From: Dmitry Stepanov Date: Sat, 6 Jun 2026 22:37:34 +0300 Subject: [PATCH 2/8] `Reflect::try_compare` impls --- fyrox-core-derive/tests/it/reflect.rs | 48 +++---- fyrox-core/src/dyntype.rs | 22 +++- fyrox-core/src/pool/mod.rs | 8 +- fyrox-core/src/reflect/array.rs | 10 +- fyrox-core/src/reflect/impls.rs | 179 +++++++++++++++++--------- fyrox-core/src/reflect/map.rs | 8 +- fyrox-core/src/reflect/mod.rs | 2 +- fyrox-core/src/variable.rs | 8 +- 8 files changed, 182 insertions(+), 103 deletions(-) diff --git a/fyrox-core-derive/tests/it/reflect.rs b/fyrox-core-derive/tests/it/reflect.rs index fbc727942..c405e3b7c 100644 --- a/fyrox-core-derive/tests/it/reflect.rs +++ b/fyrox-core-derive/tests/it/reflect.rs @@ -32,7 +32,7 @@ use fyrox_core::{parking_lot::Mutex, reflect::prelude::*}; /// Struct doc comment. #[allow(dead_code)] -#[derive(Reflect, Debug, Clone)] +#[derive(Reflect, Debug, PartialEq, Clone)] #[reflect(type_uuid = "ad7fce64-1e1d-4751-b7c7-63b0f981443d")] pub struct Struct { /// This is a @@ -42,11 +42,11 @@ pub struct Struct { hidden: usize, } -#[derive(Reflect, Clone, Debug)] +#[derive(Reflect, Clone, PartialEq, Debug)] #[reflect(type_uuid = "56bb558c-3e75-44ed-b249-dfe1dc4ae00d")] pub struct Tuple(usize, usize); -#[derive(Reflect, Clone, Debug)] +#[derive(Reflect, Clone, PartialEq, Debug)] #[reflect(type_uuid = "e11dd933-5fe0-4e19-9183-e116c438eb0f")] pub enum Enum { Named { field: usize }, @@ -126,7 +126,7 @@ fn reflect_field_accessors() { #[test] fn reflect_containers() { - #[derive(Debug, Clone)] + #[derive(Debug, PartialEq, Clone)] struct DerefContainer { data: T, } @@ -144,7 +144,7 @@ fn reflect_containers() { } } - #[derive(Reflect, Clone, Debug)] + #[derive(Reflect, PartialEq, Clone, Debug)] #[reflect(type_uuid = "414ec606-65bc-478e-94ea-326f477818aa")] struct X { #[reflect(deref)] @@ -166,8 +166,8 @@ fn reflect_containers() { x.get_resolve_path::("container.field", &mut |result| assert_eq!(result, Ok(&0))); - #[derive(Reflect, Clone, Debug)] - #[reflect(bounds = "T: Reflect + Clone")] + #[derive(Reflect, PartialEq, Clone, Debug)] + #[reflect(bounds = "T: Reflect + Clone + PartialEq")] #[reflect(type_uuid = "b3120e24-2c01-40ef-9c89-6ca40e713260")] struct B { #[reflect(deref)] @@ -187,7 +187,7 @@ fn reflect_containers() { #[test] fn reflect_path() { - #[derive(Reflect, Clone, Debug)] + #[derive(Reflect, PartialEq, Clone, Debug)] #[reflect(type_uuid = "d539b45a-c8be-4009-95ff-3ac0dfeaa47f")] struct Hierarchy { s: Struct, @@ -227,13 +227,13 @@ fn reflect_list_path() { let data = vec![vec![0usize, 1], vec![2, 3, 4]]; data.get_resolve_path("[0][1]", &mut |result| assert_eq!(result, Ok(&1usize))); - #[derive(Reflect, Clone, Debug)] + #[derive(Reflect, PartialEq, Clone, Debug)] #[reflect(type_uuid = "19d84906-550f-4dcd-82f8-1261ddc86139")] struct X { data: Vec, } - #[derive(Reflect, Clone, Debug)] + #[derive(Reflect, PartialEq, Clone, Debug)] #[reflect(type_uuid = "29da25ee-14ae-42b3-89f7-bca518188600")] struct A { xs: Vec, @@ -255,8 +255,8 @@ fn reflect_list_path() { #[test] fn reflect_custom_setter() { - #[derive(Reflect, Clone, Debug)] - #[reflect(bounds = "T: Reflect + Clone")] + #[derive(Reflect, PartialEq, Clone, Debug)] + #[reflect(bounds = "T: Reflect + Clone + PartialEq")] #[reflect(type_uuid = "9b23adf0-e9dd-4fbc-b410-8f9c0da26a20")] pub struct Wrapper { #[reflect(setter = "set_value")] @@ -285,7 +285,7 @@ fn reflect_custom_setter() { #[test] fn reflect_fields_list_of_struct() { - #[derive(Reflect, Clone, Debug)] + #[derive(Reflect, PartialEq, Clone, Debug)] #[reflect(type_uuid = "45204fc1-ca94-4349-a6b8-f8a812545052")] struct Foo { field_a: f32, @@ -311,7 +311,7 @@ fn reflect_fields_list_of_struct() { #[test] fn reflect_fields_list_of_enum() { - #[derive(Reflect, Clone, Debug)] + #[derive(Reflect, PartialEq, Clone, Debug)] #[reflect(type_uuid = "ea3d20cf-7f77-40d1-b1f3-38cb9f2ccc06")] enum Foo { Bar { field_a: f32 }, @@ -359,7 +359,7 @@ fn default_prop_metadata() -> FieldMetadata<'static> { #[test] fn inspect_default() { - #[derive(Debug, Default, Clone, Reflect)] + #[derive(Debug, Default, Clone, PartialEq, Reflect)] #[reflect(type_uuid = "51374579-08e8-4233-930e-239b00938371")] pub struct Data { the_field: String, @@ -396,14 +396,14 @@ fn inspect_default() { #[test] fn inspect_attributes() { - #[derive(Debug, Default, Clone, Reflect)] + #[derive(Debug, Default, Clone, PartialEq, Reflect)] #[reflect(type_uuid = "e8bb7752-6ff6-4cbb-87fd-e7c10e5ec970")] pub struct AarGee { aar: u32, gee: u32, } - #[derive(Debug, Default, Clone, Reflect)] + #[derive(Debug, Default, Clone, PartialEq, Reflect)] #[reflect(type_uuid = "4e0709c6-b89a-47cb-ab06-f19b01b85ec1")] pub struct Data { // NOTE: Even though this field is skipped, the next field is given index `1` for simplicity @@ -488,7 +488,7 @@ fn inspect_struct() { ) }); - #[derive(Debug, Default, Clone, Reflect)] + #[derive(Debug, Default, Clone, PartialEq, Reflect)] #[reflect(type_uuid = "ea0a8630-f6ca-45b1-84f4-e49f523328b5")] struct Unit; @@ -498,13 +498,13 @@ fn inspect_struct() { #[test] fn inspect_enum() { - #[derive(Debug, Clone, Reflect)] + #[derive(Debug, Clone, PartialEq, Reflect)] #[reflect(type_uuid = "3c045962-be82-4655-8444-ec5867fc8244")] pub struct NonCopy { inner: u32, } - #[derive(Debug, Clone, Reflect)] + #[derive(Debug, Clone, PartialEq, Reflect)] #[reflect(type_uuid = "1948ec80-47d6-4607-ac39-aa92b225e2a8")] pub enum Data { Named { x: u32, y: u32, z: NonCopy }, @@ -599,7 +599,7 @@ fn inspect_enum() { #[test] fn inspect_prop_key_constants() { #[allow(dead_code)] - #[derive(Reflect, Clone, Debug)] + #[derive(PartialEq, Reflect, Clone, Debug)] #[reflect(type_uuid = "7a97f35b-3919-4ad8-bf7a-72f21c8639c4")] pub struct SStruct { field: usize, @@ -613,12 +613,12 @@ fn inspect_prop_key_constants() { // hidden properties // assert_eq!(SStruct::HIDDEN, "hidden"); - #[derive(Reflect, Clone, Debug)] + #[derive(PartialEq, Reflect, Clone, Debug)] #[reflect(type_uuid = "16aeb5c7-e3cd-49bd-999f-5d54c159dc20")] pub struct STuple(usize); assert_eq!(STuple::F_0, "0"); - #[derive(Reflect, Clone, Debug)] + #[derive(PartialEq, Reflect, Clone, Debug)] #[reflect(type_uuid = "272d8a6f-59dd-412e-a28a-0e9b63df40cc")] #[allow(unused)] pub enum E { @@ -690,7 +690,7 @@ fn test_hash_map() { } // Check path resolution. - #[derive(Reflect, Clone, Debug)] + #[derive(PartialEq, Reflect, Clone, Debug)] #[reflect(type_uuid = "89281d16-93d1-4669-8006-f7d371cb28f3")] struct Something { hash_map: HashMap, diff --git a/fyrox-core/src/dyntype.rs b/fyrox-core/src/dyntype.rs index 4159912ba..79ed830d8 100644 --- a/fyrox-core/src/dyntype.rs +++ b/fyrox-core/src/dyntype.rs @@ -156,9 +156,15 @@ impl Clone for DynTypeWrapper { } } +impl PartialEq for DynTypeWrapper { + fn eq(&self, other: &Self) -> bool { + self.0.try_compare(other.0.deref()).unwrap_or_default() + } +} + /// "Nullable" container for a dyntype. This container is essentially a wrapper for [`Option`] that /// supports additional functionality and handles serialization for you. -#[derive(Default, Reflect, Clone, Debug)] +#[derive(Default, Reflect, Clone, PartialEq, Debug)] #[reflect(type_uuid = "c0510bdd-36cd-451c-975b-9333b18db308")] pub struct DynTypeContainer(pub Option); @@ -269,6 +275,14 @@ pub struct DynTypeConstructorDefinition { pub assembly_name: &'static str, } +impl PartialEq for DynTypeConstructorDefinition { + fn eq(&self, other: &Self) -> bool { + self.name == other.name + && std::ptr::addr_eq(self.constructor.deref(), other.constructor.deref()) + && self.assembly_name == other.assembly_name + } +} + /// A set of constructors that allows to create a dyntype by its type uuid. #[derive(Default, Reflect)] #[reflect( @@ -280,6 +294,12 @@ pub struct DynTypeConstructorContainer { map: Mutex>, } +impl PartialEq for DynTypeConstructorContainer { + fn eq(&self, other: &Self) -> bool { + *self.map.lock() == *other.map.lock() + } +} + impl Debug for DynTypeConstructorContainer { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "DynTypeConstructorContainer") diff --git a/fyrox-core/src/pool/mod.rs b/fyrox-core/src/pool/mod.rs index 985a966d2..a8467168e 100644 --- a/fyrox-core/src/pool/mod.rs +++ b/fyrox-core/src/pool/mod.rs @@ -144,8 +144,8 @@ where impl Reflect for Pool where - T: Reflect, - P: PayloadContainer + Reflect, + T: Reflect + PartialEq, + P: PayloadContainer + Reflect + PartialEq, Pool: Clone, { fn type_info() -> TypeInfo { @@ -213,8 +213,8 @@ where impl ReflectArray for Pool where - T: Reflect, - P: PayloadContainer + Reflect, + T: Reflect + PartialEq, + P: PayloadContainer + Reflect + PartialEq, Pool: Clone, { #[inline] diff --git a/fyrox-core/src/reflect/array.rs b/fyrox-core/src/reflect/array.rs index b4132964f..d8b23015a 100644 --- a/fyrox-core/src/reflect/array.rs +++ b/fyrox-core/src/reflect/array.rs @@ -43,7 +43,7 @@ pub trait ReflectList: ReflectArray { ) -> Result<(), Box>; } -impl ReflectArray for [T; N] { +impl ReflectArray for [T; N] { fn reflect_index(&self, index: usize) -> Option<&dyn Reflect> { if let Some(item) = self.get(index) { Some(item) @@ -65,7 +65,7 @@ impl ReflectArray for [T; N] { } } -impl Reflect for [T; N] { +impl Reflect for [T; N] { // TODO: combine uuids. blank_reflect!("6d2a2f2d-d74e-4125-8840-b4910aa2e0cc"); @@ -80,10 +80,10 @@ impl Reflect for [T; N] { impl_reflect! { #[reflect(ReflectList, ReflectArray, type_uuid = "2d704c2b-c87e-4489-b680-aa9699ba2c91")] - pub struct Vec; + pub struct Vec; } -impl ReflectArray for Vec { +impl ReflectArray for Vec { fn reflect_index(&self, index: usize) -> Option<&dyn Reflect> { self.get(index).map(|x| x as &dyn Reflect) } @@ -98,7 +98,7 @@ impl ReflectArray for Vec { } /// REMARK: `Reflect` is implemented for `Vec` where `T: Reflect` only. -impl ReflectList for Vec { +impl ReflectList for Vec { fn reflect_push(&mut self, value: Box) -> Result<(), Box> { self.push(*value.downcast::()?); Ok(()) diff --git a/fyrox-core/src/reflect/impls.rs b/fyrox-core/src/reflect/impls.rs index 1186e3349..943c31690 100644 --- a/fyrox-core/src/reflect/impls.rs +++ b/fyrox-core/src/reflect/impls.rs @@ -47,7 +47,12 @@ impl_reflect! { impl_reflect! { #[reflect(type_uuid = "53ca268f-7f7a-4b1c-bdee-af49f2d89945")] - pub struct Matrix { + pub struct Matrix< + T: Reflect + Copy + PartialEq, + R: Dim + Reflect + PartialEq, + C: Dim + Reflect + PartialEq, + S: Copy + Reflect + PartialEq + RawStorage + > { pub data: S, // _phantoms: PhantomData<(T, R, C)>, } @@ -55,11 +60,11 @@ impl_reflect! { impl_reflect! { #[reflect(type_uuid = "469986cd-6611-4e61-b6f0-bd2d984913c4")] - pub struct ArrayStorage(pub [[T; R]; C]); + pub struct ArrayStorage(pub [[T; R]; C]); } impl_reflect! { - #[reflect(type_uuid = "470e104b-992f-405f-ba6c-c2634502a668")] + #[reflect(type_uuid = "470e104b-992f-405f-ba6c-c2634502a668", non_comparable)] pub struct Unit { // pub(crate) value: T, } @@ -67,14 +72,14 @@ impl_reflect! { impl_reflect! { #[reflect(type_uuid = "3b45cc6d-6db4-4fa3-9d96-edcc87d47919")] - pub struct Quaternion { + pub struct Quaternion { pub coords: Vector4, } } impl_reflect! { #[reflect(type_uuid = "399bf5fd-e506-4874-9d2f-ca40ed11bc5d")] - pub struct Complex { + pub struct Complex { pub re: T, pub im: T, } @@ -158,45 +163,45 @@ impl Reflect for ImmutableString { impl Reflect for (T0,) where - T0: Clone + Reflect, + T0: Clone + Reflect + PartialEq, { blank_reflect!("874c2dd7-8e5c-44dd-a4f0-b6e64e07113d"); } impl Reflect for (T0, T1) where - T0: Clone + Reflect, - T1: Clone + Reflect, + T0: Clone + Reflect + PartialEq, + T1: Clone + Reflect + PartialEq, { blank_reflect!("2722316a-172e-4c95-8cb6-b75c81454233"); } impl Reflect for (T0, T1, T2) where - T0: Clone + Reflect, - T1: Clone + Reflect, - T2: Clone + Reflect, + T0: Clone + Reflect + PartialEq, + T1: Clone + Reflect + PartialEq, + T2: Clone + Reflect + PartialEq, { blank_reflect!("99983877-3ed7-4e58-aef0-3a5951789900"); } impl Reflect for (T0, T1, T2, T3) where - T0: Clone + Reflect, - T1: Clone + Reflect, - T2: Clone + Reflect, - T3: Clone + Reflect, + T0: Clone + Reflect + PartialEq, + T1: Clone + Reflect + PartialEq, + T2: Clone + Reflect + PartialEq, + T3: Clone + Reflect + PartialEq, { blank_reflect!("1d9b68be-0bf4-498a-a337-d84960d08049"); } impl Reflect for (T0, T1, T2, T3, T4) where - T0: Clone + Reflect, - T1: Clone + Reflect, - T2: Clone + Reflect, - T3: Clone + Reflect, - T4: Clone + Reflect, + T0: Clone + Reflect + PartialEq, + T1: Clone + Reflect + PartialEq, + T2: Clone + Reflect + PartialEq, + T3: Clone + Reflect + PartialEq, + T4: Clone + Reflect + PartialEq, { blank_reflect!("02a92848-9a7b-4bdf-8cc0-0e525a1a8021"); } @@ -212,12 +217,12 @@ impl_reflect! { impl_reflect! { #[reflect(type_uuid = "c0112c31-73fb-4457-a851-a15c0bae00e6")] - pub struct Cell; + pub struct Cell; } impl_reflect! { #[reflect(type_uuid = "99c30632-b72f-4460-8f3b-c7d3c47b1702")] - pub enum Option { + pub enum Option { Some(T), None } @@ -225,13 +230,13 @@ impl_reflect! { impl_reflect! { #[reflect(type_uuid = "0e37a8f6-fae7-48a7-b7b4-f824e40d6d7e")] - pub struct Range { + pub struct Range { pub start: Idx, pub end: Idx, } } -impl Reflect for Box { +impl Reflect for Box { fn type_info() -> TypeInfo { TypeInfo { source_path: file!(), @@ -277,6 +282,12 @@ impl Reflect for Box { Some(Box::new(self.clone())) } + fn try_compare(&self, other: &dyn Reflect) -> Option { + (other as &dyn std::any::Any) + .downcast_ref::() + .map(|other| other == self) + } + fn field_direct_ref(&self, index: usize) -> Option { if index == 0 { Some(FieldRef { @@ -314,7 +325,7 @@ static CONTENT_METADATA: FieldMetadata = FieldMetadata { }; macro_rules! impl_reflect_inner_mutability { - ($self:ident, $acquire_lock_guard:block, $clone:block) => { + ($self:ident, $acquire_lock_guard:block, $clone:block, $other:ident, $compare:block) => { fn type_info() -> TypeInfo { TypeInfo { source_path: file!(), @@ -334,7 +345,9 @@ macro_rules! impl_reflect_inner_mutability { Some(Box::new($clone)) } - + fn try_compare(&$self, $other: &dyn Reflect) -> Option { + $compare + } fn fields_ref(&$self, func: &mut dyn FnMut(&[FieldRef])) { let guard = $acquire_lock_guard; @@ -371,63 +384,103 @@ macro_rules! impl_reflect_inner_mutability { }; } -impl Reflect for parking_lot::Mutex { - impl_reflect_inner_mutability!(self, { self.safe_lock() }, { - parking_lot::Mutex::new(self.safe_lock().clone()) - }); +impl Reflect for parking_lot::Mutex { + impl_reflect_inner_mutability!( + self, + { self.safe_lock() }, + { parking_lot::Mutex::new(self.safe_lock().clone()) }, + other, + { Some(*self.safe_lock() == *other.downcast_ref::()?.safe_lock()) } + ); } -impl Reflect for parking_lot::RwLock { - impl_reflect_inner_mutability!(self, { self.write() }, { - parking_lot::RwLock::new(self.read().clone()) - }); +impl Reflect for parking_lot::RwLock { + impl_reflect_inner_mutability!( + self, + { self.write() }, + { parking_lot::RwLock::new(self.read().clone()) }, + other, + { Some(*self.read() == *other.downcast_ref::()?.read()) } + ); } #[allow(clippy::mut_mutex_lock)] -impl Reflect for std::sync::Mutex { - impl_reflect_inner_mutability!(self, { self.safe_lock().unwrap() }, { - std::sync::Mutex::new(self.safe_lock().unwrap().clone()) - }); -} - -impl Reflect for std::sync::RwLock { - impl_reflect_inner_mutability!(self, { self.write().unwrap() }, { - std::sync::RwLock::new(self.read().unwrap().clone()) - }); +impl Reflect for std::sync::Mutex { + impl_reflect_inner_mutability!( + self, + { self.safe_lock().unwrap() }, + { std::sync::Mutex::new(self.safe_lock().unwrap().clone()) }, + other, + { Some(*self.safe_lock().ok()? == *other.downcast_ref::()?.safe_lock().ok()?) } + ); +} + +impl Reflect for std::sync::RwLock { + impl_reflect_inner_mutability!( + self, + { self.write().unwrap() }, + { std::sync::RwLock::new(self.read().unwrap().clone()) }, + other, + { Some(*self.read().ok()? == *other.downcast_ref::()?.read().ok()?) } + ); } impl Reflect for Arc> { - impl_reflect_inner_mutability!(self, { self.safe_lock() }, { - Arc::new(parking_lot::Mutex::new(self.safe_lock().clone())) - }); + impl_reflect_inner_mutability!( + self, + { self.safe_lock() }, + { Arc::new(parking_lot::Mutex::new(self.safe_lock().clone())) }, + other, + { Some(Arc::ptr_eq(self, other.downcast_ref::()?)) } + ); } impl Reflect for Arc> { - impl_reflect_inner_mutability!(self, { self.lock().unwrap() }, { - Arc::new(std::sync::Mutex::new(self.safe_lock().unwrap().clone())) - }); + impl_reflect_inner_mutability!( + self, + { self.lock().unwrap() }, + { Arc::new(std::sync::Mutex::new(self.safe_lock().unwrap().clone())) }, + other, + { Some(Arc::ptr_eq(self, other.downcast_ref::()?)) } + ); } impl Reflect for Arc> { - impl_reflect_inner_mutability!(self, { self.write().unwrap() }, { - Arc::new(std::sync::RwLock::new(self.read().unwrap().clone())) - }); + impl_reflect_inner_mutability!( + self, + { self.write().unwrap() }, + { Arc::new(std::sync::RwLock::new(self.read().unwrap().clone())) }, + other, + { Some(Arc::ptr_eq(self, other.downcast_ref::()?)) } + ); } impl Reflect for Arc> { - impl_reflect_inner_mutability!(self, { self.write() }, { - Arc::new(parking_lot::RwLock::new(self.read().clone())) - }); + impl_reflect_inner_mutability!( + self, + { self.write() }, + { Arc::new(parking_lot::RwLock::new(self.read().clone())) }, + other, + { Some(Arc::ptr_eq(self, other.downcast_ref::()?)) } + ); } -impl Reflect for RefCell { - impl_reflect_inner_mutability!(self, { self.borrow_mut() }, { - RefCell::new(self.borrow().clone()) - }); +impl Reflect for RefCell { + impl_reflect_inner_mutability!( + self, + { self.borrow_mut() }, + { RefCell::new(self.borrow().clone()) }, + other, + { Some(*self.borrow() == *other.downcast_ref::()?.borrow()) } + ); } impl Reflect for Rc> { - impl_reflect_inner_mutability!(self, { self.borrow_mut() }, { - Rc::new(RefCell::new(self.borrow().clone())) - }); + impl_reflect_inner_mutability!( + self, + { self.borrow_mut() }, + { Rc::new(RefCell::new(self.borrow().clone())) }, + other, + { Some(Rc::ptr_eq(self, other.downcast_ref::()?)) } + ); } diff --git a/fyrox-core/src/reflect/map.rs b/fyrox-core/src/reflect/map.rs index f275e1d40..25e7f661f 100644 --- a/fyrox-core/src/reflect/map.rs +++ b/fyrox-core/src/reflect/map.rs @@ -45,8 +45,8 @@ pub trait ReflectHashMap: Reflect { impl Reflect for HashMap where - K: Reflect + Eq + Hash + Clone + 'static, - V: Reflect + Clone, + K: Reflect + Eq + Hash + Clone + PartialEq + 'static, + V: Reflect + Clone + PartialEq, S: BuildHasher + Clone + 'static, { // TODO: combine uuids @@ -63,8 +63,8 @@ where impl ReflectHashMap for HashMap where - K: Reflect + Eq + Hash + Clone + 'static, - V: Reflect + Clone, + K: Reflect + Eq + Hash + Clone + PartialEq + 'static, + V: Reflect + Clone + PartialEq, S: BuildHasher + Clone + 'static, { fn reflect_insert( diff --git a/fyrox-core/src/reflect/mod.rs b/fyrox-core/src/reflect/mod.rs index af3c6cf27..0e48f768a 100644 --- a/fyrox-core/src/reflect/mod.rs +++ b/fyrox-core/src/reflect/mod.rs @@ -1100,7 +1100,7 @@ mod test { ); } - #[derive(Reflect, Clone, Debug)] + #[derive(Reflect, Clone, PartialEq, Debug)] #[reflect( derived_type = "Derived", type_uuid = "8c093dc1-fd18-45ff-97bc-8d2364b7ed30" diff --git a/fyrox-core/src/variable.rs b/fyrox-core/src/variable.rs index fac46f5e4..c75e286e1 100644 --- a/fyrox-core/src/variable.rs +++ b/fyrox-core/src/variable.rs @@ -438,6 +438,12 @@ where Some(Box::new(self.clone())) } + fn try_compare(&self, other: &dyn Reflect) -> Option { + (other as &dyn std::any::Any) + .downcast_ref::() + .map(|other| other == self) + } + fn fields_ref(&self, func: &mut dyn FnMut(&[FieldRef])) { func(&[{ FieldRef { @@ -800,7 +806,7 @@ mod test { assert!(va.value_equals(&vb)) } - #[derive(Reflect, Clone, Debug)] + #[derive(Reflect, PartialEq, Clone, Debug)] #[reflect(type_uuid = "17b55aac-57f2-42e6-82e0-ead9b40a8cce")] enum SomeEnum { Bar(InheritableVariable), From d35476c864aed91112726eb93c706afb7152dde2 Mon Sep 17 00:00:00 2001 From: Dmitry Stepanov Date: Sun, 7 Jun 2026 23:58:55 +0300 Subject: [PATCH 3/8] more `PartialEq` impls --- fyrox-core-derive/tests/it/reflect.rs | 2 +- fyrox-core/src/sparse.rs | 6 ++++++ fyrox-graph/src/lib.rs | 18 +++++++++++------ fyrox-material/src/lib.rs | 10 +++++----- fyrox-material/src/shader/mod.rs | 2 +- fyrox-resource/src/constructor.rs | 2 +- fyrox-resource/src/lib.rs | 12 ++++++------ fyrox-resource/src/manager.rs | 8 +++++++- fyrox-resource/src/state.rs | 28 +++++++++++++++++++++++++-- fyrox-resource/src/untyped.rs | 4 ++-- fyrox-sound/src/buffer/generic.rs | 4 ++-- fyrox-sound/src/buffer/loader.rs | 2 +- fyrox-sound/src/buffer/mod.rs | 2 +- fyrox-sound/src/buffer/streaming.rs | 6 ++++++ fyrox-sound/src/bus.rs | 6 +++--- fyrox-sound/src/context.rs | 4 ++-- fyrox-sound/src/listener.rs | 2 +- fyrox-sound/src/renderer/hrtf.rs | 22 ++++++++++++++++++--- fyrox-sound/src/renderer/mod.rs | 2 +- fyrox-sound/src/source.rs | 2 +- fyrox-texture/src/lib.rs | 20 ++++++++++++++----- fyrox-ui/src/font/mod.rs | 8 ++++---- 22 files changed, 123 insertions(+), 49 deletions(-) diff --git a/fyrox-core-derive/tests/it/reflect.rs b/fyrox-core-derive/tests/it/reflect.rs index c405e3b7c..be396f9ff 100644 --- a/fyrox-core-derive/tests/it/reflect.rs +++ b/fyrox-core-derive/tests/it/reflect.rs @@ -458,7 +458,7 @@ fn inspect_attributes() { #[test] fn inspect_struct() { - #[derive(Debug, Default, Clone, Reflect)] + #[derive(Debug, Default, Clone, PartialEq, Reflect)] #[reflect(type_uuid = "488c51be-b7d8-4d2b-ad70-fbfd688f372f")] struct Tuple(f32, f32); diff --git a/fyrox-core/src/sparse.rs b/fyrox-core/src/sparse.rs index 0e53bf144..2a3cb35e2 100644 --- a/fyrox-core/src/sparse.rs +++ b/fyrox-core/src/sparse.rs @@ -28,6 +28,12 @@ pub struct AtomicIndex { index: AtomicUsize, } +impl PartialEq for AtomicIndex { + fn eq(&self, other: &Self) -> bool { + self.get() == other.get() + } +} + impl Clone for AtomicIndex { fn clone(&self) -> Self { Self { diff --git a/fyrox-graph/src/lib.rs b/fyrox-graph/src/lib.rs index 20afcd639..bdb72113b 100644 --- a/fyrox-graph/src/lib.rs +++ b/fyrox-graph/src/lib.rs @@ -1629,7 +1629,7 @@ mod test { path::Path, }; - #[derive(Visit, Reflect, Debug, Clone)] + #[derive(Visit, Reflect, PartialEq, Debug, Clone)] #[reflect(type_uuid = "34f5e3ea-3008-45e9-9e6e-0b8fbff1ac28")] pub struct Base { name: String, @@ -1699,6 +1699,12 @@ mod test { } } + impl PartialEq for Node { + fn eq(&self, other: &Self) -> bool { + self.0.try_compare(other.0.deref()).unwrap_or_default() + } + } + impl Node { fn new(node: impl NodeTrait) -> Self { Self(Box::new(node)) @@ -1733,7 +1739,7 @@ mod test { /// A wrapper for node pool record that allows to define custom visit method to have full /// control over instantiation process at deserialization. - #[derive(Debug, Default, Clone, Reflect)] + #[derive(Debug, Default, Clone, PartialEq, Reflect)] #[reflect(type_uuid = "08052dac-c0c0-4df3-8005-1330827bf9c2")] pub struct NodeContainer(Option); @@ -1835,7 +1841,7 @@ mod test { } } - #[derive(Default, Clone, Visit, Reflect, Debug)] + #[derive(Default, Clone, Visit, Reflect, PartialEq, Debug)] #[reflect(type_uuid = "fc887063-7780-44af-8710-5e0bcf9a83fd")] pub struct Graph { root: Handle, @@ -2091,7 +2097,7 @@ mod test { } } - #[derive(Clone, Reflect, Visit, Default, Debug)] + #[derive(Clone, Reflect, Visit, PartialEq, Default, Debug)] #[reflect(derived_type = "Node")] #[reflect(type_uuid = "c7452fb6-78c1-4e77-a2f9-d9ae31f50327")] pub struct Pivot { @@ -2114,7 +2120,7 @@ mod test { } } - #[derive(Clone, Reflect, Visit, Default, Debug)] + #[derive(Clone, Reflect, Visit, PartialEq, Default, Debug)] #[reflect(derived_type = "Node")] #[reflect(type_uuid = "17cc2d25-6ba4-4e2d-a31e-867e429bc659")] pub struct RigidBody { @@ -2137,7 +2143,7 @@ mod test { } } - #[derive(Clone, Reflect, Visit, Default, Debug)] + #[derive(Clone, Reflect, Visit, PartialEq, Default, Debug)] #[reflect(derived_type = "Node")] #[reflect(type_uuid = "1f869298-37b1-4153-a2a9-6576daa0e8b3")] pub struct Joint { diff --git a/fyrox-material/src/lib.rs b/fyrox-material/src/lib.rs index 52d07eae9..b3975a5e6 100644 --- a/fyrox-material/src/lib.rs +++ b/fyrox-material/src/lib.rs @@ -36,7 +36,7 @@ pub mod loader; pub mod shader; /// A texture binding. -#[derive(Default, Debug, Visit, Clone, Reflect)] +#[derive(Default, Debug, Visit, PartialEq, Clone, Reflect)] #[reflect(type_uuid = "e1642a47-d372-4840-a8eb-f16350f436f8")] pub struct MaterialTextureBinding { /// Actual value of the texture binding. Could be [`None`], in this case fallback value of the @@ -50,7 +50,7 @@ pub struct MaterialTextureBinding { /// /// There is a limited set of possible types that can be passed to a shader, most of them are /// just simple data types. -#[derive(Debug, Visit, Clone, Reflect, AsRefStr, EnumString, VariantNames)] +#[derive(Debug, Visit, Clone, PartialEq, Reflect, AsRefStr, EnumString, VariantNames)] #[reflect(type_uuid = "2df8f1e5-0075-4d0d-9860-70fc27d3e165")] pub enum MaterialResourceBinding { /// A texture. @@ -78,7 +78,7 @@ impl MaterialResourceBinding { /// Property group stores a bunch of named values of a fixed set of types, that will be used for /// rendering with some shader. -#[derive(Default, Debug, Visit, Clone, Reflect)] +#[derive(Default, Debug, Visit, Clone, PartialEq, Reflect)] #[reflect(type_uuid = "f7bfc838-f115-463d-a714-ab48d309058a")] pub struct MaterialPropertyGroup { properties: FxHashMap, @@ -166,7 +166,7 @@ impl MaterialPropertyGroup { } /// A set of possible material property types. -#[derive(Debug, Visit, Clone, Reflect, AsRefStr, EnumString, VariantNames)] +#[derive(Debug, Visit, Clone, PartialEq, Reflect, AsRefStr, EnumString, VariantNames)] #[reflect(type_uuid = "1c25018d-ab6e-4dca-99a6-e3d9639bc33c")] pub enum MaterialProperty { /// Real number. @@ -600,7 +600,7 @@ impl Default for MaterialProperty { /// As you can see it is slightly more complex that with the standard shader. The main difference here is /// that we using resource manager to get shader instance, and then we just use the instance to create /// material instance. Then we populate properties as usual. -#[derive(Debug, Clone, Reflect)] +#[derive(Debug, Clone, PartialEq, Reflect)] #[reflect(type_uuid = "0e54fe44-0c58-4108-a681-d6eefc88c234")] pub struct Material { shader: ShaderResource, diff --git a/fyrox-material/src/shader/mod.rs b/fyrox-material/src/shader/mod.rs index 5a9974899..a6c530584 100644 --- a/fyrox-material/src/shader/mod.rs +++ b/fyrox-material/src/shader/mod.rs @@ -515,7 +515,7 @@ pub const STANDARD_WIDGET_SHADER_NAME: &str = "Widget Shader"; /// /// Usually you don't need to access internals of the shader, but there sometimes could be a need to /// read shader definition, to get supported passes and properties. -#[derive(Default, Debug, Clone, Reflect, Visit)] +#[derive(Default, Debug, Clone, Reflect, PartialEq, Visit)] #[reflect(type_uuid = "f1346417-b726-492a-b80f-c02096c6c019")] pub struct Shader { /// Shader definition contains description of properties and render passes. diff --git a/fyrox-resource/src/constructor.rs b/fyrox-resource/src/constructor.rs index 0535ffe91..5129980d5 100644 --- a/fyrox-resource/src/constructor.rs +++ b/fyrox-resource/src/constructor.rs @@ -113,7 +113,7 @@ mod test { use super::*; - #[derive(Debug, Default, Clone, Reflect, Visit)] + #[derive(Debug, Default, Clone, PartialEq, Reflect, Visit)] #[reflect(type_uuid = "ba5f1e9b-557f-4565-bbb1-c299a6510bb7")] struct Stub {} diff --git a/fyrox-resource/src/lib.rs b/fyrox-resource/src/lib.rs index 6c8cb9edf..7f6f5835d 100644 --- a/fyrox-resource/src/lib.rs +++ b/fyrox-resource/src/lib.rs @@ -91,9 +91,9 @@ pub trait ResourceData: Debug + Visit + Send + Reflect { /// such as: a way to get default state of the data (`Default` impl), a way to get data's type uuid. /// The trait has automatic implementation for any type that implements /// ` ResourceData + Default ` traits. -pub trait TypedResourceData: ResourceData + Default {} +pub trait TypedResourceData: ResourceData + Default + PartialEq {} -impl TypedResourceData for T where T: ResourceData + Default {} +impl TypedResourceData for T where T: ResourceData + Default + PartialEq {} /// A trait for resource load error. pub trait ResourceLoadError: 'static + Debug + Display + Send + Sync {} @@ -185,13 +185,13 @@ where into = "UntypedResource" )] #[reflect(type_uuid = "790b1a1c-a997-46c4-ac3b-8565501f0052")] -pub struct Resource { +pub struct Resource { untyped: UntypedResource, #[reflect(hidden)] phantom: PhantomData, } -impl Debug for Resource { +impl Debug for Resource { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!( f, @@ -404,7 +404,7 @@ where } } -impl Clone for Resource { +impl Clone for Resource { #[inline] fn clone(&self) -> Self { Self { @@ -702,7 +702,7 @@ mod tests { sync::Arc, }; - #[derive(Serialize, Deserialize, Default, Debug, Clone, Visit, Reflect)] + #[derive(Serialize, Deserialize, Default, Debug, Clone, Visit, PartialEq, Reflect)] #[reflect(type_uuid = "241d14c7-079e-4395-a63c-364f0fc3e6ea")] struct MyData { data: u32, diff --git a/fyrox-resource/src/manager.rs b/fyrox-resource/src/manager.rs index 9f46a1101..a0f1bc943 100644 --- a/fyrox-resource/src/manager.rs +++ b/fyrox-resource/src/manager.rs @@ -124,6 +124,12 @@ pub struct ResourceManager { state: Arc>, } +impl PartialEq for ResourceManager { + fn eq(&self, other: &Self) -> bool { + Arc::ptr_eq(&self.state, &other.state) + } +} + impl Debug for ResourceManager { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "ResourceManager") @@ -2090,7 +2096,7 @@ mod test { }; use std::{error::Error, fs::File, time::Duration}; - #[derive(Debug, Default, Clone, Reflect, Visit)] + #[derive(Debug, Default, Clone, PartialEq, Reflect, Visit)] #[reflect(type_uuid = "2c729b8e-93d3-4bcc-a3a7-2d89e77947e5")] struct Stub {} diff --git a/fyrox-resource/src/state.rs b/fyrox-resource/src/state.rs index e16eb0d10..115f562eb 100644 --- a/fyrox-resource/src/state.rs +++ b/fyrox-resource/src/state.rs @@ -35,6 +35,12 @@ use std::{ #[reflect(hide_all, type_uuid = "238a5490-6627-48ef-8035-4b589497293b")] pub struct WakersList(Vec); +impl PartialEq for WakersList { + fn eq(&self, other: &Self) -> bool { + self.0.len() == other.0.len() + } +} + impl Deref for WakersList { type Target = Vec; @@ -64,6 +70,16 @@ impl DerefMut for WakersList { #[reflect(hide_all, type_uuid = "cb2257dc-b344-49e6-972e-cd99be4c3615")] pub struct LoadError(pub Option>); +impl PartialEq for LoadError { + fn eq(&self, other: &Self) -> bool { + if let (Some(a), Some(b)) = (&self.0, &other.0) { + Arc::ptr_eq(a, b) + } else { + false + } + } +} + impl std::error::Error for LoadError {} impl LoadError { @@ -99,6 +115,14 @@ impl ResourceDataWrapper { } } +impl PartialEq for ResourceDataWrapper { + fn eq(&self, other: &Self) -> bool { + self.0 + .try_compare(other.0.deref() as &dyn Reflect) + .unwrap_or_default() + } +} + impl Clone for ResourceDataWrapper { fn clone(&self) -> Self { Self(ResourceData::try_clone_box(&*self.0).unwrap()) @@ -131,7 +155,7 @@ impl Clone for ResourceDataWrapper { /// to get the UUID earlier: the UUID is stored in a metadata file which exists only if the resource /// is present. It is somewhat possible to get a UUID when a resource is failed to load, but not in /// 100% cases. -#[derive(Clone, Reflect)] +#[derive(Clone, PartialEq, Reflect)] #[reflect(type_uuid = "3d49c715-4a48-4b41-b8c6-45bcb8b3fd17")] pub enum ResourceState { /// Resource is not loaded. In some situations, having a handle to a resource @@ -337,7 +361,7 @@ mod test { use super::*; - #[derive(Debug, Default, Clone, Reflect, Visit)] + #[derive(Debug, Default, Clone, Reflect, PartialEq, Visit)] #[reflect(type_uuid = "96a59120-b174-4b2c-9069-1770ec495011")] struct Stub {} diff --git a/fyrox-resource/src/untyped.rs b/fyrox-resource/src/untyped.rs index 4d185a905..06df93828 100644 --- a/fyrox-resource/src/untyped.rs +++ b/fyrox-resource/src/untyped.rs @@ -110,7 +110,7 @@ impl Display for ResourceKind { /// Header of a resource, it contains a common data about the resource, such as its data type uuid, /// its kind, etc. -#[derive(Reflect, Clone, Debug)] +#[derive(Reflect, PartialEq, Clone, Debug)] #[reflect(type_uuid = "2a41dd3e-bb8f-4654-ad0b-d8b7ca0cc9f2")] pub struct ResourceHeader { /// The unique identifier of this resource. @@ -641,7 +641,7 @@ mod test { use super::*; - #[derive(Debug, Default, Reflect, Visit, Clone, Copy)] + #[derive(Debug, Default, PartialEq, Reflect, Visit, Clone, Copy)] #[reflect(type_uuid = "7130e63a-8aa3-44f7-b264-bc19072a70ba")] struct Stub {} diff --git a/fyrox-sound/src/buffer/generic.rs b/fyrox-sound/src/buffer/generic.rs index 691353f11..4279845e0 100644 --- a/fyrox-sound/src/buffer/generic.rs +++ b/fyrox-sound/src/buffer/generic.rs @@ -51,7 +51,7 @@ use std::time::Duration; use super::SoundBufferResourceLoadError; /// Samples container. -#[derive(Debug, Default, Visit, Clone, Reflect)] +#[derive(Debug, Default, PartialEq, Visit, Clone, Reflect)] #[reflect(type_uuid = "7b0ba106-9ed5-41e1-a8c7-82c609d6f74e")] pub struct Samples(pub Vec); @@ -70,7 +70,7 @@ impl DerefMut for Samples { } /// Generic sound buffer that contains decoded samples and allows random access. -#[derive(Debug, Clone, Default, Visit, Reflect)] +#[derive(Debug, Clone, Default, PartialEq, Visit, Reflect)] #[reflect(type_uuid = "e5bf74a5-13d9-4518-96f2-0e4f3413966e")] pub struct GenericBuffer { /// Interleaved decoded samples (mono sounds: L..., stereo sounds: LR...) diff --git a/fyrox-sound/src/buffer/loader.rs b/fyrox-sound/src/buffer/loader.rs index 1ecec3da0..7849b8a9c 100644 --- a/fyrox-sound/src/buffer/loader.rs +++ b/fyrox-sound/src/buffer/loader.rs @@ -34,7 +34,7 @@ use serde::{Deserialize, Serialize}; use std::{path::PathBuf, sync::Arc}; /// Defines sound buffer resource import options. -#[derive(Clone, Deserialize, Serialize, Default, Debug, Reflect)] +#[derive(Clone, Deserialize, Serialize, Default, Debug, PartialEq, Reflect)] #[reflect(type_uuid = "032e333a-f0bd-41f2-a7e5-79207f6064ce")] pub struct SoundBufferImportOptions { /// Whether the buffer is streaming or not. diff --git a/fyrox-sound/src/buffer/mod.rs b/fyrox-sound/src/buffer/mod.rs index ee01e6a0c..1f8e4e7ac 100644 --- a/fyrox-sound/src/buffer/mod.rs +++ b/fyrox-sound/src/buffer/mod.rs @@ -236,7 +236,7 @@ impl std::fmt::Display for SoundBufferResourceLoadError { impl std::error::Error for SoundBufferResourceLoadError {} /// Sound buffer is a data source for sound sources. See module documentation for more info. -#[derive(Debug, Visit, Reflect)] +#[derive(Debug, Visit, PartialEq, Reflect)] #[reflect(non_cloneable)] #[reflect(type_uuid = "f6a077b7-c8ff-4473-a95b-0289441ea9d8")] pub enum SoundBuffer { diff --git a/fyrox-sound/src/buffer/streaming.rs b/fyrox-sound/src/buffer/streaming.rs index 217e2ae52..7e2aae95d 100644 --- a/fyrox-sound/src/buffer/streaming.rs +++ b/fyrox-sound/src/buffer/streaming.rs @@ -75,6 +75,12 @@ pub struct StreamingBuffer { streaming_source: StreamingSource, } +impl PartialEq for StreamingBuffer { + fn eq(&self, other: &Self) -> bool { + self.generic == other.generic + } +} + #[derive(Debug, Default)] enum StreamingSource { #[default] diff --git a/fyrox-sound/src/bus.rs b/fyrox-sound/src/bus.rs index 4eb27c4be..c10909ea4 100644 --- a/fyrox-sound/src/bus.rs +++ b/fyrox-sound/src/bus.rs @@ -30,7 +30,7 @@ use fyrox_core::{ }; use std::fmt::{Debug, Formatter}; -#[derive(Default, Clone)] +#[derive(Default, PartialEq, Clone)] struct PingPongBuffer { buffer1: Vec<(f32, f32)>, buffer2: Vec<(f32, f32)>, @@ -101,7 +101,7 @@ impl PingPongBuffer { /// samples through a chain of effects. Output signal is then can be either sent to an audio playback device or /// to some other audio bus and be processed again, but with different sound effects (this can be done via /// [`AudioBusGraph`]. -#[derive(Debug, Reflect, Visit, Clone)] +#[derive(Debug, PartialEq, Reflect, Visit, Clone)] #[reflect(type_uuid = "de4c1709-c9ac-4823-8f77-22199bb53645")] pub struct AudioBus { pub(crate) name: String, @@ -309,7 +309,7 @@ impl AudioBus { /// ``` /// /// If you delete an audio bus to which a bunch of sound sources is bound, then they will simply stop playing. -#[derive(Default, Debug, Clone, Visit, Reflect)] +#[derive(Default, Debug, PartialEq, Clone, Visit, Reflect)] #[reflect(type_uuid = "417d2cff-e699-4396-bd90-a57b5564372a")] pub struct AudioBusGraph { buses: Pool, diff --git a/fyrox-sound/src/context.rs b/fyrox-sound/src/context.rs index dfd524413..f24dc7363 100644 --- a/fyrox-sound/src/context.rs +++ b/fyrox-sound/src/context.rs @@ -113,7 +113,7 @@ impl PartialEq for SoundContext { /// A set of flags, that can be used to define what should be skipped during the /// serialization of a sound context. -#[derive(Default, Debug, Clone)] +#[derive(Default, Debug, PartialEq, Clone)] pub struct SerializationOptions { /// All sources won't be serialized, if set. pub skip_sources: bool, @@ -122,7 +122,7 @@ pub struct SerializationOptions { } /// Internal state of context. -#[derive(Default, Debug, Clone, Reflect)] +#[derive(Default, Debug, Clone, PartialEq, Reflect)] #[reflect(type_uuid = "10f5a7ce-efe4-4bcc-aabc-c399e8fd1a3c")] pub struct State { sources: Pool, diff --git a/fyrox-sound/src/listener.rs b/fyrox-sound/src/listener.rs index c153535f9..234d753b8 100644 --- a/fyrox-sound/src/listener.rs +++ b/fyrox-sound/src/listener.rs @@ -33,7 +33,7 @@ use fyrox_core::{ }; /// See module docs. -#[derive(Debug, Clone, Visit, Reflect)] +#[derive(Debug, Clone, Visit, PartialEq, Reflect)] #[reflect(type_uuid = "fc52e441-d1ec-4881-937c-9e2e53a6d621")] pub struct Listener { basis: Matrix3, diff --git a/fyrox-sound/src/renderer/hrtf.rs b/fyrox-sound/src/renderer/hrtf.rs index 9a8605fa5..34fbadf85 100644 --- a/fyrox-sound/src/renderer/hrtf.rs +++ b/fyrox-sound/src/renderer/hrtf.rs @@ -142,13 +142,19 @@ impl Display for HrtfError { /// See module docs. #[derive(Clone, Debug, Default, Reflect)] -#[reflect(type_uuid = "c6149a3b-7992-44a8-9b9f-16651a5d2b15")] +#[reflect(type_uuid = "c6149a3b-7992-44a8-9b9f-16651a5d2b15", non_comparable)] pub struct HrtfRenderer { hrir_resource: Option, #[reflect(hidden)] processor: Option, } +impl PartialEq for HrtfRenderer { + fn eq(&self, other: &Self) -> bool { + self.hrir_resource == other.hrir_resource + } +} + impl Visit for HrtfRenderer { fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult { let mut region = visitor.enter_region(name)?; @@ -243,6 +249,16 @@ enum HrirSource { RawData(Vec), } +impl PartialEq for HrirSource { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::Preloaded(a), Self::Preloaded(b)) => a.source() == b.source(), + (Self::RawData(a), Self::RawData(b)) => a == b, + _ => false, + } + } +} + impl Default for HrirSource { fn default() -> Self { Self::RawData(Default::default()) @@ -251,8 +267,8 @@ impl Default for HrirSource { /// Wrapper for [`HrirSphere`] to be able to use it in the resource manager, that will handle async resource /// loading automatically. -#[derive(Reflect, Default, Clone, Visit)] -#[reflect(type_uuid = "c92a0fa3-0ed3-49a9-be44-8f06271c6be2")] +#[derive(Reflect, Default, PartialEq, Clone, Visit)] +#[reflect(type_uuid = "c92a0fa3-0ed3-49a9-be44-8f06271c6be2", non_comparable)] pub struct HrirSphereResourceData { #[reflect(hidden)] #[visit(skip)] diff --git a/fyrox-sound/src/renderer/mod.rs b/fyrox-sound/src/renderer/mod.rs index 9f29c33bb..ec9766b11 100644 --- a/fyrox-sound/src/renderer/mod.rs +++ b/fyrox-sound/src/renderer/mod.rs @@ -44,7 +44,7 @@ pub mod hrtf; // This "large size difference" is not a problem because renderer // can be only one at a time on context. #[allow(clippy::large_enum_variant)] -#[derive(Debug, Clone, AsRefStr, EnumString, VariantNames, Visit, Reflect, Default)] +#[derive(Debug, Clone, AsRefStr, EnumString, VariantNames, Visit, PartialEq, Reflect, Default)] #[reflect(type_uuid = "13bf8432-987a-4216-b6aa-f5c0e8914a31")] pub enum Renderer { /// Stateless default renderer. diff --git a/fyrox-sound/src/source.rs b/fyrox-sound/src/source.rs index 3923d324e..6bb8939d5 100644 --- a/fyrox-sound/src/source.rs +++ b/fyrox-sound/src/source.rs @@ -81,7 +81,7 @@ pub enum Status { } /// See module info. -#[derive(Debug, Clone, Reflect, Visit)] +#[derive(Debug, Clone, PartialEq, Reflect, Visit)] #[reflect(type_uuid = "1beb0bbc-72fb-42a1-9e78-5d246c84fdfe")] pub struct SoundSource { name: String, diff --git a/fyrox-texture/src/lib.rs b/fyrox-texture/src/lib.rs index a65564f3e..abd7de69f 100644 --- a/fyrox-texture/src/lib.rs +++ b/fyrox-texture/src/lib.rs @@ -76,7 +76,7 @@ use strum_macros::{AsRefStr, EnumString, VariantNames}; pub mod loader; /// Texture kind. -#[derive(Copy, Clone, Debug, Reflect, AsRefStr, EnumString, VariantNames)] +#[derive(Copy, Clone, Debug, PartialEq, Reflect, AsRefStr, EnumString, VariantNames)] #[reflect(type_uuid = "542eb785-875b-43ce-b73a-a25024535f48")] pub enum TextureKind { /// 1D texture. @@ -222,7 +222,7 @@ impl Visit for TextureKind { } /// Data storage of a texture. -#[derive(Default, Clone, Reflect)] +#[derive(Default, PartialEq, Clone, Reflect)] #[reflect(type_uuid = "4b9c2b23-46cd-4f7f-bf13-07b0bebe5538")] pub struct TextureBytes(Vec); @@ -253,7 +253,7 @@ impl DerefMut for TextureBytes { } /// Actual texture data. -#[derive(Debug, Clone, Reflect)] +#[derive(Debug, Clone, PartialEq, Reflect)] #[reflect(type_uuid = "02c23a44-55fa-411a-bc39-eb7a5eadf15c")] pub struct Texture { kind: TextureKind, @@ -396,7 +396,17 @@ impl Default for Texture { /// A filter for mip-map generation. #[derive( - Default, Copy, Clone, Deserialize, Serialize, Debug, Reflect, AsRefStr, EnumString, VariantNames, + Default, + Copy, + Clone, + Deserialize, + Serialize, + PartialEq, + Debug, + Reflect, + AsRefStr, + EnumString, + VariantNames, )] #[reflect(type_uuid = "8fa17c0e-6889-4540-b396-97db4dc952aa")] pub enum MipFilter { @@ -446,7 +456,7 @@ impl MipFilter { /// compression: NoCompression, /// ) /// ``` -#[derive(Clone, Deserialize, Serialize, Debug, Reflect)] +#[derive(Clone, Deserialize, Serialize, Debug, PartialEq, Reflect)] #[reflect(type_uuid = "c70e89c9-2245-4736-99d9-f3fe9c1c5d3c")] pub struct TextureImportOptions { #[serde(default)] diff --git a/fyrox-ui/src/font/mod.rs b/fyrox-ui/src/font/mod.rs index f0f6d3c31..f199a7ed4 100644 --- a/fyrox-ui/src/font/mod.rs +++ b/fyrox-ui/src/font/mod.rs @@ -62,7 +62,7 @@ enum FontError { /// The geometric data specifying where to find a glyph on a font atlas /// texture for rendering text. -#[derive(Debug, Clone)] +#[derive(Debug, PartialEq, Clone)] pub struct FontGlyph { /// The vertical position of the glyph relative to other glyphs on the line, measured in font pixels. /// This would be 0 for a glyph with its bottom directly on the baseline, but may be @@ -92,7 +92,7 @@ pub struct FontGlyph { } /// Page is a storage for rasterized glyphs. -#[derive(Clone)] +#[derive(PartialEq, Clone)] pub struct Page { /// The texture data for rendering some glyphs. /// When new glyphs are required, this data may be modified if space @@ -123,7 +123,7 @@ impl Debug for Page { /// Atlas is a storage for glyphs of a particular size, each atlas could have any number of pages to /// store the rasterized glyphs. -#[derive(Default, Clone, Debug)] +#[derive(Default, Clone, PartialEq, Debug)] pub struct Atlas { /// The geometric data used for rendering glyphs from the pages of this atlas, /// such as the size of each glyph, the index of its page, and the UVs of the corners @@ -330,7 +330,7 @@ impl Atlas { } /// A font resource and the associated data required for rendering glyphs from the font. -#[derive(Default, Clone, Debug, Reflect, Visit)] +#[derive(Default, Clone, Debug, Reflect, PartialEq, Visit)] #[reflect(type_uuid = "692fec79-103a-483c-bb0b-9fc3a349cb48")] pub struct Font { /// The source font data, such as might come from a ttf file. From c0978db579e5930efed9a57c0fcee1f3dcbac23a Mon Sep 17 00:00:00 2001 From: Dmitry Stepanov Date: Tue, 9 Jun 2026 23:15:40 +0300 Subject: [PATCH 4/8] continue with `PartialEq` impls --- fyrox-core/src/reflect/macros.rs | 4 ++++ fyrox-math/Cargo.toml | 2 +- fyrox-ui/src/absm.rs | 4 ++-- fyrox-ui/src/animation.rs | 2 +- fyrox-ui/src/bit.rs | 2 +- fyrox-ui/src/border.rs | 2 +- fyrox-ui/src/button.rs | 2 +- fyrox-ui/src/canvas.rs | 2 +- fyrox-ui/src/check_box.rs | 2 +- fyrox-ui/src/color/gradient.rs | 8 ++++---- fyrox-ui/src/color/mod.rs | 10 +++++----- fyrox-ui/src/curve/key.rs | 4 ++-- fyrox-ui/src/curve/mod.rs | 18 ++++++++++++------ fyrox-ui/src/decorator.rs | 2 +- fyrox-ui/src/dock/mod.rs | 2 +- fyrox-ui/src/dock/tile.rs | 2 +- fyrox-ui/src/draw.rs | 12 ++++++------ fyrox-ui/src/dropdown_list.rs | 2 +- fyrox-ui/src/dropdown_menu.rs | 2 +- fyrox-ui/src/expander.rs | 2 +- fyrox-ui/src/file_browser/dialog.rs | 2 +- fyrox-ui/src/file_browser/field.rs | 2 +- fyrox-ui/src/file_browser/menu.rs | 2 +- fyrox-ui/src/file_browser/mod.rs | 3 +-- fyrox-ui/src/file_browser/selector.rs | 2 +- fyrox-ui/src/font/mod.rs | 13 ++++++++++++- fyrox-ui/src/formatted_text.rs | 6 +++--- fyrox-ui/src/grid.rs | 4 ++-- fyrox-ui/src/image.rs | 2 +- fyrox-ui/src/input.rs | 2 +- fyrox-ui/src/inspector/editors/array.rs | 2 +- fyrox-ui/src/inspector/editors/collection.rs | 6 +++--- fyrox-ui/src/inspector/editors/enumeration.rs | 6 +++--- fyrox-ui/src/inspector/editors/inherit.rs | 2 +- fyrox-ui/src/inspector/editors/style.rs | 4 ++-- .../src/inspector/editors/texture_slice.rs | 6 +++--- fyrox-ui/src/inspector/mod.rs | 2 +- fyrox-ui/src/key.rs | 4 ++-- fyrox-ui/src/lib.rs | 2 +- fyrox-ui/src/list_view.rs | 4 ++-- fyrox-ui/src/matrix.rs | 2 +- fyrox-ui/src/menu.rs | 8 ++++---- fyrox-ui/src/messagebox.rs | 2 +- fyrox-ui/src/navigation.rs | 2 +- fyrox-ui/src/nine_patch.rs | 2 +- fyrox-ui/src/node/container.rs | 2 +- fyrox-ui/src/node/mod.rs | 6 ++++++ fyrox-ui/src/numeric.rs | 6 ++++-- fyrox-ui/src/path.rs | 2 +- fyrox-ui/src/popup.rs | 2 +- fyrox-ui/src/progress_bar.rs | 2 +- fyrox-ui/src/range.rs | 2 +- fyrox-ui/src/rect.rs | 2 +- fyrox-ui/src/screen.rs | 2 +- fyrox-ui/src/scroll_bar.rs | 2 +- fyrox-ui/src/scroll_panel.rs | 2 +- fyrox-ui/src/scroll_viewer.rs | 2 +- fyrox-ui/src/searchbar.rs | 2 +- fyrox-ui/src/selector.rs | 2 +- fyrox-ui/src/stack_panel.rs | 2 +- fyrox-ui/src/style/mod.rs | 10 +++++----- fyrox-ui/src/tab_control.rs | 2 +- fyrox-ui/src/text.rs | 2 +- fyrox-ui/src/text_box.rs | 2 +- fyrox-ui/src/thumb.rs | 2 +- fyrox-ui/src/toggle.rs | 2 +- fyrox-ui/src/tree.rs | 4 ++-- fyrox-ui/src/uuid.rs | 2 +- fyrox-ui/src/vec.rs | 2 +- fyrox-ui/src/vector_image.rs | 2 +- fyrox-ui/src/widget.rs | 4 ++-- fyrox-ui/src/window.rs | 6 +++--- fyrox-ui/src/wrap_panel.rs | 4 ++-- 73 files changed, 144 insertions(+), 116 deletions(-) diff --git a/fyrox-core/src/reflect/macros.rs b/fyrox-core/src/reflect/macros.rs index c99ace23a..eb234b30a 100644 --- a/fyrox-core/src/reflect/macros.rs +++ b/fyrox-core/src/reflect/macros.rs @@ -213,6 +213,10 @@ macro_rules! blank_reflect_ref { None } + fn try_compare(&self, other: &dyn Reflect) -> Option { + None + } + fn fields_ref(&self, func: &mut dyn FnMut(&[$crate::reflect::FieldRef])) { func(&[]) } diff --git a/fyrox-math/Cargo.toml b/fyrox-math/Cargo.toml index d744c6a68..83fa8a38c 100644 --- a/fyrox-math/Cargo.toml +++ b/fyrox-math/Cargo.toml @@ -14,7 +14,7 @@ repository = "https://github.com/FyroxEngine/Fyrox" rust-version = "1.87" [dependencies] -rectutils = "0.5.0" +rectutils = "0.6.0" nalgebra = { version = "0.34", features = ["bytemuck", "convert-glam030"] } arrayvec = "0.7.4" num-traits = "0.2.18" diff --git a/fyrox-ui/src/absm.rs b/fyrox-ui/src/absm.rs index 98a1496a8..9812ef7fa 100644 --- a/fyrox-ui/src/absm.rs +++ b/fyrox-ui/src/absm.rs @@ -118,7 +118,7 @@ pub mod prelude { /// /// The node does **not** contain any animations, instead it just takes animations from an animation /// player node and mixes them. -#[derive(Visit, Reflect, Clone, Debug, Default)] +#[derive(Visit, PartialEq, Reflect, Clone, Debug, Default)] #[reflect(type_uuid = "4b08c753-2a10-41e3-8fb2-4fd0517e86bc")] #[reflect(derived_type = "UiNode")] pub struct AnimationBlendingStateMachine { @@ -276,7 +276,7 @@ pub struct EventAction { } /// A widget that listens for particular events and sets parameters in an ABSM accordingly. -#[derive(Visit, Reflect, Clone, Debug, Default)] +#[derive(Visit, PartialEq, Reflect, Clone, Debug, Default)] #[reflect(type_uuid = "15f306b8-3bb8-4b35-87bd-6e9e5d748455")] #[reflect(derived_type = "UiNode")] pub struct AbsmEventProvider { diff --git a/fyrox-ui/src/animation.rs b/fyrox-ui/src/animation.rs index 32effeb9f..37adc865a 100644 --- a/fyrox-ui/src/animation.rs +++ b/fyrox-ui/src/animation.rs @@ -142,7 +142,7 @@ impl BoundValueCollectionExt for BoundValueCollection { /// Animation player is a node that contains multiple animations. It updates and plays all the animations. /// The node could be a source of animations for animation blending state machines. To learn more about /// animations, see [`Animation`] docs. -#[derive(Visit, Reflect, Clone, Debug)] +#[derive(Visit, PartialEq, Reflect, Clone, Debug)] #[reflect( derived_type = "UiNode", type_uuid = "44d1c94e-354f-4f9a-b918-9d31c28aa16a" diff --git a/fyrox-ui/src/bit.rs b/fyrox-ui/src/bit.rs index 49c812d1c..995129b81 100644 --- a/fyrox-ui/src/bit.rs +++ b/fyrox-ui/src/bit.rs @@ -113,7 +113,7 @@ impl ConstructorProvider for BitField } } -#[derive(Default, Clone, Reflect, Visit, Debug)] +#[derive(Default, Clone, PartialEq, Reflect, Visit, Debug)] #[reflect( derived_type = "UiNode", type_uuid = "6c19b266-18be-46d2-bfd3-f1dc9cb3f36c" diff --git a/fyrox-ui/src/border.rs b/fyrox-ui/src/border.rs index 194be02e5..014e020ea 100644 --- a/fyrox-ui/src/border.rs +++ b/fyrox-ui/src/border.rs @@ -99,7 +99,7 @@ use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor}; /// .with_stroke_thickness(Thickness {left: 2.0, right: 2.0, top: 2.0, bottom: 2.0}.into()) /// .build(&mut ui.build_ctx()); /// ``` -#[derive(Default, Clone, Visit, Reflect, Debug)] +#[derive(Default, Clone, Visit, PartialEq, Reflect, Debug)] #[reflect(type_uuid = "6aba3dc5-831d-481a-bc83-ec10b2b2bf12")] #[reflect(derived_type = "UiNode")] pub struct Border { diff --git a/fyrox-ui/src/button.rs b/fyrox-ui/src/button.rs index 7e75ffe65..f0883566d 100644 --- a/fyrox-ui/src/button.rs +++ b/fyrox-ui/src/button.rs @@ -90,7 +90,7 @@ impl MessageData for ButtonMessage {} /// } /// } /// ``` -#[derive(Default, Clone, Visit, Reflect, Debug)] +#[derive(Default, Clone, Visit, PartialEq, Reflect, Debug)] #[reflect(type_uuid = "2abcf12b-2f19-46da-b900-ae8890f7c9c6")] #[reflect(derived_type = "UiNode")] pub struct Button { diff --git a/fyrox-ui/src/canvas.rs b/fyrox-ui/src/canvas.rs index 28276108c..35f1e6ed8 100644 --- a/fyrox-ui/src/canvas.rs +++ b/fyrox-ui/src/canvas.rs @@ -66,7 +66,7 @@ use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor}; /// .build(ctx) /// } /// ``` -#[derive(Default, Clone, Visit, Reflect, Debug)] +#[derive(Default, Clone, Visit, PartialEq, Reflect, Debug)] #[reflect(type_uuid = "6b843a36-53da-467b-b85e-2380fe891ca1")] #[reflect(derived_type = "UiNode")] pub struct Canvas { diff --git a/fyrox-ui/src/check_box.rs b/fyrox-ui/src/check_box.rs index d4f4395b8..939ec40d9 100644 --- a/fyrox-ui/src/check_box.rs +++ b/fyrox-ui/src/check_box.rs @@ -148,7 +148,7 @@ impl MessageData for CheckBoxMessage {} /// 2) [`CheckBoxBuilder::with_check_mark`] - sets the widget that will be used as checked icon. /// 3) [`CheckBoxBuilder::with_uncheck_mark`] - sets the widget that will be used as unchecked icon. /// 4) [`CheckBoxBuilder::with_undefined_mark`] - sets the widget that will be used as undefined icon. -#[derive(Default, Clone, Debug, Visit, Reflect)] +#[derive(Default, Clone, Debug, Visit, PartialEq, Reflect)] #[reflect(type_uuid = "3a866ba8-7682-4ce7-954a-46360f5837dc")] #[reflect(derived_type = "UiNode")] pub struct CheckBox { diff --git a/fyrox-ui/src/color/gradient.rs b/fyrox-ui/src/color/gradient.rs index 295ca2cc3..5ac5975f6 100644 --- a/fyrox-ui/src/color/gradient.rs +++ b/fyrox-ui/src/color/gradient.rs @@ -56,7 +56,7 @@ pub enum ColorGradientEditorMessage { } impl MessageData for ColorGradientEditorMessage {} -#[derive(Default, Clone, Debug, Visit, Reflect)] +#[derive(Default, Clone, Debug, Visit, PartialEq, Reflect)] #[reflect(type_uuid = "50d00eb7-f30b-4973-8a36-03d6b8f007ec")] #[reflect(derived_type = "UiNode")] pub struct ColorGradientField { @@ -182,7 +182,7 @@ impl ColorGradientFieldBuilder { } } -#[derive(Default, Clone, Debug, Visit, Reflect)] +#[derive(Default, Clone, Debug, Visit, PartialEq, Reflect)] #[reflect(type_uuid = "82843d8b-1972-46e6-897c-9619b74059cc")] #[reflect(derived_type = "UiNode")] pub struct ColorGradientEditor { @@ -469,7 +469,7 @@ pub enum ColorPointMessage { } impl MessageData for ColorPointMessage {} -#[derive(Default, Clone, Debug, Visit, Reflect)] +#[derive(Default, Clone, Debug, Visit, PartialEq, Reflect)] #[reflect(type_uuid = "a493a603-3451-4005-8c80-559707729e70")] #[reflect(derived_type = "UiNode")] pub struct ColorPoint { @@ -602,7 +602,7 @@ impl ColorPointBuilder { } } -#[derive(Clone, Visit, Reflect, Debug)] +#[derive(Clone, Visit, PartialEq, Reflect, Debug)] #[reflect(type_uuid = "2608955a-4095-4fd1-af71-99bcdf2600f0")] #[reflect(derived_type = "UiNode")] pub struct ColorPointsCanvas { diff --git a/fyrox-ui/src/color/mod.rs b/fyrox-ui/src/color/mod.rs index da38737d2..91a0c7804 100644 --- a/fyrox-ui/src/color/mod.rs +++ b/fyrox-ui/src/color/mod.rs @@ -103,7 +103,7 @@ pub enum ColorFieldMessage { } impl MessageData for ColorFieldMessage {} -#[derive(Default, Clone, Debug, Visit, Reflect)] +#[derive(Default, Clone, Debug, Visit, PartialEq, Reflect)] #[reflect( derived_type = "UiNode", type_uuid = "956d4cae-7953-486b-99da-a9b852c2e144" @@ -384,7 +384,7 @@ impl AlphaBarBuilder { } } -#[derive(Default, Clone, Debug, Visit, Reflect)] +#[derive(Default, Clone, Debug, Visit, PartialEq, Reflect)] #[reflect( derived_type = "UiNode", type_uuid = "af28f977-85e7-4c9e-9a61-7f208844acb5" @@ -547,7 +547,7 @@ impl HueBarBuilder { } } -#[derive(Default, Clone, Debug, Visit, Reflect)] +#[derive(Default, Clone, Debug, Visit, PartialEq, Reflect)] #[reflect( derived_type = "UiNode", type_uuid = "ab6bfad5-0c4b-42a5-8da5-fc5687b1afc7" @@ -764,7 +764,7 @@ impl SaturationBrightnessFieldBuilder { } } -#[derive(Default, Clone, Debug, Visit, Reflect)] +#[derive(Default, Clone, Debug, Visit, PartialEq, Reflect)] #[reflect( derived_type = "UiNode", type_uuid = "b7a5d650-5b77-4938-83c1-37f3fe107885" @@ -1154,7 +1154,7 @@ impl ColorPickerBuilder { } } -#[derive(Default, Clone, Debug, Visit, Reflect)] +#[derive(Default, Clone, Debug, Visit, PartialEq, Reflect)] #[reflect( derived_type = "UiNode", type_uuid = "68dec1ac-23c6-41df-bc85-499f2a82e908" diff --git a/fyrox-ui/src/curve/key.rs b/fyrox-ui/src/curve/key.rs index 9a59148ec..953087a38 100644 --- a/fyrox-ui/src/curve/key.rs +++ b/fyrox-ui/src/curve/key.rs @@ -30,7 +30,7 @@ use crate::{ }; use std::cmp::Ordering; -#[derive(Default, Clone, Debug, Visit, Reflect)] +#[derive(Default, Clone, Debug, Visit, PartialEq, Reflect)] #[reflect(type_uuid = "ae6110cd-f1dd-45b5-98e1-d8ae8bf3d0cc")] pub struct CurveKeyView { pub position: Vector2, @@ -48,7 +48,7 @@ impl From<&CurveKey> for CurveKeyView { } } -#[derive(Default, Clone, Visit, Reflect, Debug)] +#[derive(Default, Clone, Visit, PartialEq, Reflect, Debug)] #[reflect(type_uuid = "866c6360-2c6a-4218-aebc-530036b59a87")] pub struct CurveKeyViewContainer { id: Uuid, diff --git a/fyrox-ui/src/curve/mod.rs b/fyrox-ui/src/curve/mod.rs index 630aa567d..72578e2bd 100644 --- a/fyrox-ui/src/curve/mod.rs +++ b/fyrox-ui/src/curve/mod.rs @@ -110,6 +110,12 @@ pub struct HighlightZone { #[derive(Debug, Default)] pub struct CurveTransformCell(Mutex); +impl PartialEq for CurveTransformCell { + fn eq(&self, other: &Self) -> bool { + *self.0.safe_lock() == *other.0.safe_lock() + } +} + impl Clone for CurveTransformCell { fn clone(&self) -> Self { Self(Mutex::new(self.0.safe_lock().clone())) @@ -211,7 +217,7 @@ fn standardize_step(step: f32) -> f32 { /// /// Since widgets are not mutable during layout and rendering, a CurveTransform /// is intended to be used within a [CurveTransformCell] which provides interior mutability. -#[derive(Clone, Debug)] +#[derive(Clone, PartialEq, Debug)] pub struct CurveTransform { /// Position of the center of the curve editor in the curve coordinate space. pub position: Vector2, @@ -358,7 +364,7 @@ impl Iterator for StepIterator { } } -#[derive(Default, Clone, Visit, Reflect, Debug)] +#[derive(Default, Clone, Visit, PartialEq, Reflect, Debug)] #[reflect(type_uuid = "4b640057-639e-4f47-9a08-c08d94eca68e")] pub struct CurvesContainer { curves: Vec, @@ -412,7 +418,7 @@ impl CurvesContainer { } } -#[derive(Default, Clone, Visit, Reflect, Debug)] +#[derive(Default, Clone, Visit, PartialEq, Reflect, Debug)] #[reflect( derived_type = "UiNode", type_uuid = "5c7b087e-871e-498d-b064-187b604a37d8" @@ -471,7 +477,7 @@ impl ConstructorProvider for CurveEditor { crate::define_widget_deref!(CurveEditor); -#[derive(Default, Clone, Visit, Reflect, Debug)] +#[derive(Default, Clone, Visit, PartialEq, Reflect, Debug)] #[reflect(type_uuid = "c81d942c-394d-498d-b460-1dc508288ed3")] struct ContextMenu { widget: RcUiNodeHandle, @@ -495,7 +501,7 @@ struct DragEntry { initial_position: Vector2, } -#[derive(Clone, Debug)] +#[derive(Clone, PartialEq, Debug)] enum OperationContext { DragKeys { // In local coordinates. @@ -527,7 +533,7 @@ impl OperationContext { } } -#[derive(Clone, Debug)] +#[derive(Clone,PartialEq, Debug)] enum Selection { Keys { keys: FxHashSet }, LeftTangent { key_id: Uuid }, diff --git a/fyrox-ui/src/decorator.rs b/fyrox-ui/src/decorator.rs index f63a55cbf..1afe78d15 100644 --- a/fyrox-ui/src/decorator.rs +++ b/fyrox-ui/src/decorator.rs @@ -86,7 +86,7 @@ impl MessageData for DecoratorMessage {} /// .build(ctx) /// } /// ``` -#[derive(Default, Clone, Visit, Reflect, Debug)] +#[derive(Default, Clone, Visit, PartialEq, Reflect, Debug)] #[reflect( derived_type = "UiNode", type_uuid = "bb4b60aa-c657-4ed6-8db6-d7f374397c73" diff --git a/fyrox-ui/src/dock/mod.rs b/fyrox-ui/src/dock/mod.rs index e481124e1..ad68224eb 100644 --- a/fyrox-ui/src/dock/mod.rs +++ b/fyrox-ui/src/dock/mod.rs @@ -160,7 +160,7 @@ impl MessageData for DockingManagerMessage {} /// To be able to restore the layout to its defaults, just create a desired layout from code, /// save the layout and use the returned layout descriptor when you need to restore the layout /// to its defaults. -#[derive(Default, Clone, Visit, Reflect, Debug)] +#[derive(Default, Clone, Visit, PartialEq, Reflect, Debug)] #[reflect( derived_type = "UiNode", type_uuid = "b04299f7-3f6b-45f1-89a6-0dce4ad929e1" diff --git a/fyrox-ui/src/dock/tile.rs b/fyrox-ui/src/dock/tile.rs index 06f9cdcfd..1c67c9917 100644 --- a/fyrox-ui/src/dock/tile.rs +++ b/fyrox-ui/src/dock/tile.rs @@ -256,7 +256,7 @@ fn deminimize_other_window( } } -#[derive(Default, Clone, Debug, Visit, Reflect)] +#[derive(Default, Clone, Debug, Visit, PartialEq, Reflect)] #[reflect( derived_type = "UiNode", type_uuid = "8ed17fa9-890e-4dd7-b4f9-a24660882234" diff --git a/fyrox-ui/src/draw.rs b/fyrox-ui/src/draw.rs index 186f18e1b..2597a5fc6 100644 --- a/fyrox-ui/src/draw.rs +++ b/fyrox-ui/src/draw.rs @@ -40,7 +40,7 @@ use fyrox_texture::TextureResource; use std::fmt::{Display, Formatter}; use std::ops::Range; -#[derive(Clone, Copy, Debug, Pod, Zeroable)] +#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)] #[repr(C)] pub struct Vertex { pub pos: Vector2, @@ -58,7 +58,7 @@ impl Vertex { } } -#[derive(Clone, Debug)] +#[derive(Clone, PartialEq, Debug)] pub enum CommandTexture { None, Texture(TextureResource), @@ -70,7 +70,7 @@ pub enum CommandTexture { } /// A set of triangles that will be used for clipping. -#[derive(Clone, Debug)] +#[derive(Clone, PartialEq, Debug)] pub struct ClippingGeometry { pub vertex_buffer: Vec, pub triangle_buffer: Vec, @@ -126,7 +126,7 @@ impl ClippingGeometry { } } -#[derive(Clone, Debug)] +#[derive(Clone, PartialEq, Debug)] pub struct Command { /// Clipping bounds, should be used for scissor-test. Screen-space. pub clip_bounds: Rect, @@ -753,7 +753,7 @@ pub trait Draw { } } -#[derive(Clone, Debug)] +#[derive(Clone, PartialEq, Debug)] pub struct TransformStack { transform: Matrix3, stack: Vec>, @@ -806,7 +806,7 @@ impl TransformStack { } } -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone, PartialEq, Default)] pub struct RenderData { pub vertex_buffer: Vec, pub triangle_buffer: Vec, diff --git a/fyrox-ui/src/dropdown_list.rs b/fyrox-ui/src/dropdown_list.rs index d204937c0..777bf29e7 100644 --- a/fyrox-ui/src/dropdown_list.rs +++ b/fyrox-ui/src/dropdown_list.rs @@ -167,7 +167,7 @@ impl MessageData for DropdownListMessage {} /// /// A dropdown list could be opened and closed manually using [`DropdownListMessage::Open`] and /// [`DropdownListMessage::Close`] messages. -#[derive(Default, Clone, Debug, Visit, Reflect)] +#[derive(Default, Clone, Debug, Visit, PartialEq, Reflect)] #[reflect( derived_type = "UiNode", type_uuid = "1da2f69a-c8b4-4ae2-a2ad-4afe61ee2a32" diff --git a/fyrox-ui/src/dropdown_menu.rs b/fyrox-ui/src/dropdown_menu.rs index 1292c01db..ce1b2b8aa 100644 --- a/fyrox-ui/src/dropdown_menu.rs +++ b/fyrox-ui/src/dropdown_menu.rs @@ -34,7 +34,7 @@ use std::sync::mpsc::Sender; /// A simple widget that opens a popup when clicked. It could be used to create dropdown menus that /// consolidates content of a group. -#[derive(Default, Clone, Visit, Reflect, Debug)] +#[derive(Default, Clone, Visit, PartialEq, Reflect, Debug)] #[reflect(type_uuid = "c0a4c51b-f041-453b-a89d-7ceb5394e321")] #[reflect(derived_type = "UiNode")] pub struct DropdownMenu { diff --git a/fyrox-ui/src/expander.rs b/fyrox-ui/src/expander.rs index c28435fb7..ce44bad00 100644 --- a/fyrox-ui/src/expander.rs +++ b/fyrox-ui/src/expander.rs @@ -151,7 +151,7 @@ impl MessageData for ExpanderMessage {} /// /// To switch expander state at runtime, send [`ExpanderMessage::Expand`] to your Expander widget instance with /// [`crate::message::MessageDirection::ToWidget`]. -#[derive(Default, Clone, Visit, Reflect, Debug)] +#[derive(Default, Clone, Visit, PartialEq, Reflect, Debug)] #[reflect( derived_type = "UiNode", type_uuid = "24976179-b338-4c55-84c3-72d21663efd2" diff --git a/fyrox-ui/src/file_browser/dialog.rs b/fyrox-ui/src/file_browser/dialog.rs index 965ae95d6..50ba47b87 100644 --- a/fyrox-ui/src/file_browser/dialog.rs +++ b/fyrox-ui/src/file_browser/dialog.rs @@ -41,7 +41,7 @@ pub enum FolderNameDialogMessage { } impl MessageData for FolderNameDialogMessage {} -#[derive(Clone, Visit, Reflect, Default, Debug)] +#[derive(Clone, Visit, PartialEq, Reflect, Default, Debug)] #[reflect(type_uuid = "832f63b8-1372-49b8-8ce5-7564920343a8")] #[reflect(derived_type = "UiNode")] pub struct FolderNameDialog { diff --git a/fyrox-ui/src/file_browser/field.rs b/fyrox-ui/src/file_browser/field.rs index 2da1caf04..d32ea55d4 100644 --- a/fyrox-ui/src/file_browser/field.rs +++ b/fyrox-ui/src/file_browser/field.rs @@ -46,7 +46,7 @@ impl MessageData for FileSelectorFieldMessage {} define_widget_deref!(FileSelectorField); -#[derive(Default, Clone, Visit, Reflect, Debug)] +#[derive(Default, Clone, Visit, PartialEq, Reflect, Debug)] #[reflect( derived_type = "UiNode", type_uuid = "2dbda730-8a60-4f62-aee8-2ff0ccd15bf2" diff --git a/fyrox-ui/src/file_browser/menu.rs b/fyrox-ui/src/file_browser/menu.rs index 44629377f..fc4a9c412 100644 --- a/fyrox-ui/src/file_browser/menu.rs +++ b/fyrox-ui/src/file_browser/menu.rs @@ -43,7 +43,7 @@ use std::{ sync::mpsc::Sender, }; -#[derive(Clone, Visit, Reflect, Debug)] +#[derive(Clone, Visit, PartialEq, Reflect, Debug)] #[reflect( derived_type = "UiNode", type_uuid = "6a9d597f-6a9f-4bad-b569-4cff1a6deff7" diff --git a/fyrox-ui/src/file_browser/mod.rs b/fyrox-ui/src/file_browser/mod.rs index 9be1d9354..20bbe35a8 100644 --- a/fyrox-ui/src/file_browser/mod.rs +++ b/fyrox-ui/src/file_browser/mod.rs @@ -100,7 +100,7 @@ enum FsEventMessage { } impl MessageData for FsEventMessage {} -#[derive(Default, Visit, Reflect)] +#[derive(Default, Visit, PartialEq, Reflect)] #[reflect(type_uuid = "b7f4610e-4b0c-4671-9b4a-60bb45268928")] #[reflect(derived_type = "UiNode")] pub struct FileBrowser { @@ -120,7 +120,6 @@ pub struct FileBrowser { #[visit(skip)] #[reflect(hidden)] pub item_context_menu: RcUiNodeHandle, - #[allow(clippy::type_complexity)] #[visit(skip)] #[reflect(hidden)] pub watcher: Option, diff --git a/fyrox-ui/src/file_browser/selector.rs b/fyrox-ui/src/file_browser/selector.rs index afc208886..70e5aed11 100644 --- a/fyrox-ui/src/file_browser/selector.rs +++ b/fyrox-ui/src/file_browser/selector.rs @@ -73,7 +73,7 @@ impl MessageData for FileSelectorMessage {} /// File selector is a modal window that allows you to select a file (or directory) and commit or /// cancel selection. -#[derive(Default, Clone, Debug, Visit, Reflect)] +#[derive(Default, Clone, Debug, Visit, PartialEq, Reflect)] #[reflect( derived_type = "UiNode", type_uuid = "878b2220-03e6-4a50-a97d-3a8e5397b6cb" diff --git a/fyrox-ui/src/font/mod.rs b/fyrox-ui/src/font/mod.rs index f199a7ed4..447ee5e95 100644 --- a/fyrox-ui/src/font/mod.rs +++ b/fyrox-ui/src/font/mod.rs @@ -330,7 +330,7 @@ impl Atlas { } /// A font resource and the associated data required for rendering glyphs from the font. -#[derive(Default, Clone, Debug, Reflect, PartialEq, Visit)] +#[derive(Default, Clone, Debug, Reflect, Visit)] #[reflect(type_uuid = "692fec79-103a-483c-bb0b-9fc3a349cb48")] pub struct Font { /// The source font data, such as might come from a ttf file. @@ -361,6 +361,17 @@ pub struct Font { pub fallbacks: Vec>, } +impl PartialEq for Font { + fn eq(&self, other: &Self) -> bool { + self.atlases == other.atlases + && self.page_size == other.page_size + && self.bold == other.bold + && self.italic == other.italic + && self.bold_italic == other.bold_italic + && self.fallbacks == other.fallbacks + } +} + impl ResourceData for Font { fn save(&mut self, _path: &Path) -> Result<(), Box> { Ok(()) diff --git a/fyrox-ui/src/formatted_text.rs b/fyrox-ui/src/formatted_text.rs index baecda4b9..a441eff07 100644 --- a/fyrox-ui/src/formatted_text.rs +++ b/fyrox-ui/src/formatted_text.rs @@ -55,7 +55,7 @@ pub struct Position { pub offset: usize, } -#[derive(Debug, Clone, Default)] +#[derive(Debug, PartialEq, Clone, Default)] pub struct TextGlyph { pub bounds: Rect, pub tex_coords: [Vector2; 4], @@ -63,7 +63,7 @@ pub struct TextGlyph { pub source_char_index: usize, } -#[derive(Copy, Clone, Debug, Default)] +#[derive(Copy, Clone, PartialEq, Debug, Default)] pub struct TextLine { /// Index of starting symbol in text array. pub begin: usize, @@ -256,7 +256,7 @@ impl LineSink for WrapSink<'_> { } } -#[derive(Default, Clone, Debug, Visit, Reflect)] +#[derive(Default, Clone, Debug, Visit, PartialEq, Reflect)] #[reflect(type_uuid = "a48f1f1d-24ce-4a84-a45d-706ac541cf0a")] pub struct FormattedText { font: InheritableVariable>, diff --git a/fyrox-ui/src/grid.rs b/fyrox-ui/src/grid.rs index 7ed68b666..be6b5fcfe 100644 --- a/fyrox-ui/src/grid.rs +++ b/fyrox-ui/src/grid.rs @@ -217,7 +217,7 @@ pub type Row = GridDimension; /// You can add any number of rows and columns to a grid widget, and each grid cell does **not** need to have a UI widget /// in it to be valid. For example, you can add a column and set it to a specific size via strict to provide spacing between /// two other columns. -#[derive(Default, Clone, Visit, Reflect, Debug)] +#[derive(Default, Clone, Visit, PartialEq, Reflect, Debug)] #[reflect( derived_type = "UiNode", type_uuid = "98ce15e2-bd62-497d-a37b-9b1cb4a1918c" @@ -262,7 +262,7 @@ crate::define_widget_deref!(Grid); /// Cell of the grid, that contains additional information for layout purposes. It does not have any /// particular use outside of grid's internals. -#[derive(Clone, Debug)] +#[derive(Clone, PartialEq, Debug)] pub struct Cell { /// A set of nodes of the cell. pub nodes: Vec>, diff --git a/fyrox-ui/src/image.rs b/fyrox-ui/src/image.rs index 2c7539343..4a1fb1a34 100644 --- a/fyrox-ui/src/image.rs +++ b/fyrox-ui/src/image.rs @@ -157,7 +157,7 @@ impl MessageData for ImageMessage {} /// It is useful if you have many custom UI elements packed in a single texture atlas. Drawing using atlases is much more /// efficient and faster. This could also be used for animations when you have multiple frames packed in a single atlas /// and changing texture coordinates over time. -#[derive(Default, Clone, Visit, Reflect, Debug)] +#[derive(Default, Clone, Visit, PartialEq, Reflect, Debug)] #[reflect(type_uuid = "18e18d0f-cb84-4ac1-8050-3480a2ec3de5")] #[visit(optional)] #[reflect(derived_type = "UiNode")] diff --git a/fyrox-ui/src/input.rs b/fyrox-ui/src/input.rs index 2006053e6..b5e396c96 100644 --- a/fyrox-ui/src/input.rs +++ b/fyrox-ui/src/input.rs @@ -88,7 +88,7 @@ pub enum InputBoxResult { /// There's no way to change the style of the input box, nor add some widgets to it. If you need a /// custom input box, then you need to create your own widget. This input box is meant to be used as /// a standard dialog box for standard situations in the UI. -#[derive(Default, Clone, Visit, Reflect, Debug)] +#[derive(Default, Clone, Visit, PartialEq, Reflect, Debug)] #[reflect(type_uuid = "6b7b6b82-939b-4f98-9bb9-9bd19ce68b21")] #[reflect(derived_type = "UiNode")] pub struct InputBox { diff --git a/fyrox-ui/src/inspector/editors/array.rs b/fyrox-ui/src/inspector/editors/array.rs index bc929f166..68735761a 100644 --- a/fyrox-ui/src/inspector/editors/array.rs +++ b/fyrox-ui/src/inspector/editors/array.rs @@ -53,7 +53,7 @@ pub enum ArrayEditorMessage { } impl MessageData for ArrayEditorMessage {} -#[derive(Clone, Debug, Visit, Reflect)] +#[derive(Clone, Debug, Visit, PartialEq, Reflect)] #[reflect( derived_type = "UiNode", type_uuid = "5c6e4785-8e2d-441f-8478-523900394b93" diff --git a/fyrox-ui/src/inspector/editors/collection.rs b/fyrox-ui/src/inspector/editors/collection.rs index c134a7785..00402c498 100644 --- a/fyrox-ui/src/inspector/editors/collection.rs +++ b/fyrox-ui/src/inspector/editors/collection.rs @@ -57,11 +57,11 @@ pub struct Item { remove: Handle