Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Merged by Bors] - Make reflect_partial_eq return more accurate results #5210

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions crates/bevy_reflect/src/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,13 +327,16 @@ pub fn array_apply<A: Array>(array: &mut A, reflect: &dyn Reflect) {

/// Compares two [arrays](Array) (one concrete and one reflected) to see if they
/// are equal.
///
/// Returns [`None`] if the comparison couldn't even be performed.
#[inline]
pub fn array_partial_eq<A: Array>(array: &A, reflect: &dyn Reflect) -> Option<bool> {
match reflect.reflect_ref() {
ReflectRef::Array(reflect_array) if reflect_array.len() == array.len() => {
for (a, b) in array.iter().zip(reflect_array.iter()) {
if let Some(false) | None = a.reflect_partial_eq(b) {
return Some(false);
let eq_result = a.reflect_partial_eq(b);
if let failed @ (Some(false) | None) = eq_result {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Woah, what's this @ syntax called?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

@nicopap nicopap Jul 5, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reference doesn't mention the name. It just specifies it as a subset of identifier patterns. The rust book call them "@ bindings".

In traditional functional languages (Haskell, Ocaml), they usually use the as keyword. In rust this wouldn't work since it's the explicit casting operator. Looks like the Ocaml reference calls them "alias patterns", which I think is pretty descriptive https://v2.ocaml.org/manual/patterns.html#sss:pat-alias

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was new to me too. I had to check docs when I saw the @(at) pattern bindings. I'm glad I learn something new and useful.

return failed;
}
}
}
Expand Down
7 changes: 5 additions & 2 deletions crates/bevy_reflect/src/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,8 @@ pub fn list_apply<L: List>(a: &mut L, b: &dyn Reflect) {
/// - `b` is a list;
/// - `b` is the same length as `a`;
/// - [`Reflect::reflect_partial_eq`] returns `Some(true)` for pairwise elements of `a` and `b`.
///
/// Returns [`None`] if the comparison couldn't even be performed.
#[inline]
pub fn list_partial_eq<L: List>(a: &L, b: &dyn Reflect) -> Option<bool> {
let list = if let ReflectRef::List(list) = b.reflect_ref() {
Expand All @@ -306,8 +308,9 @@ pub fn list_partial_eq<L: List>(a: &L, b: &dyn Reflect) -> Option<bool> {
}

for (a_value, b_value) in a.iter().zip(list.iter()) {
if let Some(false) | None = a_value.reflect_partial_eq(b_value) {
return Some(false);
let eq_result = a_value.reflect_partial_eq(b_value);
if let failed @ (Some(false) | None) = eq_result {
return failed;
}
}

Expand Down
7 changes: 5 additions & 2 deletions crates/bevy_reflect/src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,8 @@ impl<'a> ExactSizeIterator for MapIter<'a> {}
/// - `b` is the same length as `a`;
/// - For each key-value pair in `a`, `b` contains a value for the given key,
/// and [`Reflect::reflect_partial_eq`] returns `Some(true)` for the two values.
///
/// Returns [`None`] if the comparison couldn't even be performed.
#[inline]
pub fn map_partial_eq<M: Map>(a: &M, b: &dyn Reflect) -> Option<bool> {
let map = if let ReflectRef::Map(map) = b.reflect_ref() {
Expand All @@ -358,8 +360,9 @@ pub fn map_partial_eq<M: Map>(a: &M, b: &dyn Reflect) -> Option<bool> {

for (key, value) in a.iter() {
if let Some(map_value) = map.get(key) {
if let Some(false) | None = value.reflect_partial_eq(map_value) {
return Some(false);
let eq_result = value.reflect_partial_eq(map_value);
if let failed @ (Some(false) | None) = eq_result {
return failed;
}
} else {
return Some(false);
Expand Down
7 changes: 5 additions & 2 deletions crates/bevy_reflect/src/struct_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,8 @@ impl Typed for DynamicStruct {
/// - For each field in `a`, `b` contains a field with the same name and
/// [`Reflect::reflect_partial_eq`] returns `Some(true)` for the two field
/// values.
///
/// Returns [`None`] if the comparison couldn't even be performed.
#[inline]
pub fn struct_partial_eq<S: Struct>(a: &S, b: &dyn Reflect) -> Option<bool> {
let struct_value = if let ReflectRef::Struct(struct_value) = b.reflect_ref() {
Expand All @@ -452,8 +454,9 @@ pub fn struct_partial_eq<S: Struct>(a: &S, b: &dyn Reflect) -> Option<bool> {
for (i, value) in struct_value.iter_fields().enumerate() {
let name = struct_value.name_at(i).unwrap();
if let Some(field_value) = a.field(name) {
if let Some(false) | None = field_value.reflect_partial_eq(value) {
return Some(false);
let eq_result = field_value.reflect_partial_eq(value);
if let failed @ (Some(false) | None) = eq_result {
return failed;
}
} else {
return Some(false);
Expand Down
8 changes: 5 additions & 3 deletions crates/bevy_reflect/src/tuple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,8 @@ pub fn tuple_apply<T: Tuple>(a: &mut T, b: &dyn Reflect) {
/// - `b` is a tuple;
/// - `b` has the same number of elements as `a`;
/// - [`Reflect::reflect_partial_eq`] returns `Some(true)` for pairwise elements of `a` and `b`.
///
/// Returns [`None`] if the comparison couldn't even be performed.
#[inline]
pub fn tuple_partial_eq<T: Tuple>(a: &T, b: &dyn Reflect) -> Option<bool> {
let b = if let ReflectRef::Tuple(tuple) = b.reflect_ref() {
Expand All @@ -382,9 +384,9 @@ pub fn tuple_partial_eq<T: Tuple>(a: &T, b: &dyn Reflect) -> Option<bool> {
}

for (a_field, b_field) in a.iter_fields().zip(b.iter_fields()) {
match a_field.reflect_partial_eq(b_field) {
Some(false) | None => return Some(false),
Some(true) => {}
let eq_result = a_field.reflect_partial_eq(b_field);
if let failed @ (Some(false) | None) = eq_result {
return failed;
}
}

Expand Down
7 changes: 5 additions & 2 deletions crates/bevy_reflect/src/tuple_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,8 @@ impl Typed for DynamicTupleStruct {
/// - `b` is a tuple struct;
/// - `b` has the same number of fields as `a`;
/// - [`Reflect::reflect_partial_eq`] returns `Some(true)` for pairwise fields of `a` and `b`.
///
/// Returns [`None`] if the comparison couldn't even be performed.
#[inline]
pub fn tuple_struct_partial_eq<S: TupleStruct>(a: &S, b: &dyn Reflect) -> Option<bool> {
let tuple_struct = if let ReflectRef::TupleStruct(tuple_struct) = b.reflect_ref() {
Expand All @@ -363,8 +365,9 @@ pub fn tuple_struct_partial_eq<S: TupleStruct>(a: &S, b: &dyn Reflect) -> Option

for (i, value) in tuple_struct.iter_fields().enumerate() {
if let Some(field_value) = a.field(i) {
if let Some(false) | None = field_value.reflect_partial_eq(value) {
return Some(false);
let eq_result = field_value.reflect_partial_eq(value);
if let failed @ (Some(false) | None) = eq_result {
return failed;
}
} else {
return Some(false);
Expand Down