bevy/crates/bevy_reflect/src/impls/glam.rs
Gino Valente 1a41c736b3
bevy_reflect: Update EulerRot to match glam 0.29 (#15402)
# Objective

#15349 added an `impl_reflect!` for `glam::EulerRot`. This was done by
copying and pasting the enum definition from `glam` into `bevy_reflect`
so that the macro could interpret the variants.

However, as mentioned in the description for that PR, this would need to
be updated for `glam` 0.29, as it had not been updated yet.

#15249 came and updated `glam` to 0.29, but did not change these impls.
This is understandable as failing to do so doesn't cause any compile
errors.

This PR updates the definition and aims to make this silent breakage a
little less silent.

## Solution

Firstly, I updated the definition for `EulerRot` to match the one from
`glam`.

Secondly, I added the `assert_type_match` crate, which I created
specifically to solve this problem. By using this crate, we'll get a
compile time error if `glam` ever decides to change `EulerRot` again.

In the future we can consider using it for other types with this
problem, including in other crates (I'm pretty sure `bevy_window` and/or
`bevy_winit` also copy+paste some types). I made sure to use as few
dependencies as possible so everything should already be in-tree (it's
just `quote`, `proc-macro2`, and `syn` with default features).

## Testing

No tests added. CI should pass.

---

## Migration Guide

The reflection implementation for `EulerRot` has been updated to align
with `glam` 0.29. Please update any reflection-based usages accordingly.
2024-09-23 22:50:12 +00:00

445 lines
9.3 KiB
Rust

use crate as bevy_reflect;
use crate::{std_traits::ReflectDefault, ReflectDeserialize, ReflectSerialize};
use assert_type_match::assert_type_match;
use bevy_reflect_derive::{impl_reflect, impl_reflect_opaque};
use glam::*;
/// Reflects the given foreign type as an enum and asserts that the variants/fields match up.
macro_rules! reflect_enum {
($(#[$meta:meta])* enum $ident:ident { $($ty:tt)* } ) => {
impl_reflect!($(#[$meta])* enum $ident { $($ty)* });
#[assert_type_match($ident, test_only)]
#[allow(clippy::upper_case_acronyms)]
enum $ident { $($ty)* }
};
}
impl_reflect!(
#[reflect(Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct IVec2 {
x: i32,
y: i32,
}
);
impl_reflect!(
#[reflect(Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct IVec3 {
x: i32,
y: i32,
z: i32,
}
);
impl_reflect!(
#[reflect(Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct IVec4 {
x: i32,
y: i32,
z: i32,
w: i32,
}
);
impl_reflect!(
#[reflect(Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct I64Vec2 {
x: i64,
y: i64,
}
);
impl_reflect!(
#[reflect(Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct I64Vec3 {
x: i64,
y: i64,
z: i64,
}
);
impl_reflect!(
#[reflect(Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct I64Vec4 {
x: i64,
y: i64,
z: i64,
w: i64,
}
);
impl_reflect!(
#[reflect(Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct UVec2 {
x: u32,
y: u32,
}
);
impl_reflect!(
#[reflect(Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct UVec3 {
x: u32,
y: u32,
z: u32,
}
);
impl_reflect!(
#[reflect(Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct UVec4 {
x: u32,
y: u32,
z: u32,
w: u32,
}
);
impl_reflect!(
#[reflect(Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct U64Vec2 {
x: u64,
y: u64,
}
);
impl_reflect!(
#[reflect(Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct U64Vec3 {
x: u64,
y: u64,
z: u64,
}
);
impl_reflect!(
#[reflect(Debug, Hash, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct U64Vec4 {
x: u64,
y: u64,
z: u64,
w: u64,
}
);
impl_reflect!(
#[reflect(Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Vec2 {
x: f32,
y: f32,
}
);
impl_reflect!(
#[reflect(Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Vec3 {
x: f32,
y: f32,
z: f32,
}
);
impl_reflect!(
#[reflect(Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Vec3A {
x: f32,
y: f32,
z: f32,
}
);
impl_reflect!(
#[reflect(Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Vec4 {
x: f32,
y: f32,
z: f32,
w: f32,
}
);
impl_reflect!(
#[reflect(Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct BVec2 {
x: bool,
y: bool,
}
);
impl_reflect!(
#[reflect(Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct BVec3 {
x: bool,
y: bool,
z: bool,
}
);
impl_reflect!(
#[reflect(Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct BVec4 {
x: bool,
y: bool,
z: bool,
w: bool,
}
);
impl_reflect!(
#[reflect(Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct DVec2 {
x: f64,
y: f64,
}
);
impl_reflect!(
#[reflect(Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct DVec3 {
x: f64,
y: f64,
z: f64,
}
);
impl_reflect!(
#[reflect(Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct DVec4 {
x: f64,
y: f64,
z: f64,
w: f64,
}
);
impl_reflect!(
#[reflect(Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Mat2 {
x_axis: Vec2,
y_axis: Vec2,
}
);
impl_reflect!(
#[reflect(Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Mat3 {
x_axis: Vec3,
y_axis: Vec3,
z_axis: Vec3,
}
);
impl_reflect!(
#[reflect(Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Mat3A {
x_axis: Vec3A,
y_axis: Vec3A,
z_axis: Vec3A,
}
);
impl_reflect!(
#[reflect(Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Mat4 {
x_axis: Vec4,
y_axis: Vec4,
z_axis: Vec4,
w_axis: Vec4,
}
);
impl_reflect!(
#[reflect(Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct DMat2 {
x_axis: DVec2,
y_axis: DVec2,
}
);
impl_reflect!(
#[reflect(Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct DMat3 {
x_axis: DVec3,
y_axis: DVec3,
z_axis: DVec3,
}
);
impl_reflect!(
#[reflect(Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct DMat4 {
x_axis: DVec4,
y_axis: DVec4,
z_axis: DVec4,
w_axis: DVec4,
}
);
impl_reflect!(
#[reflect(Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Affine2 {
matrix2: Mat2,
translation: Vec2,
}
);
impl_reflect!(
#[reflect(Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Affine3A {
matrix3: Mat3A,
translation: Vec3A,
}
);
impl_reflect!(
#[reflect(Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct DAffine2 {
matrix2: DMat2,
translation: DVec2,
}
);
impl_reflect!(
#[reflect(Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct DAffine3 {
matrix3: DMat3,
translation: DVec3,
}
);
impl_reflect!(
#[reflect(Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct Quat {
x: f32,
y: f32,
z: f32,
w: f32,
}
);
impl_reflect!(
#[reflect(Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
struct DQuat {
x: f64,
y: f64,
z: f64,
w: f64,
}
);
reflect_enum!(
#[reflect(Debug, PartialEq, Default, Deserialize, Serialize)]
#[type_path = "glam"]
enum EulerRot {
ZYX,
ZXY,
YXZ,
YZX,
XYZ,
XZY,
ZYZ,
ZXZ,
YXY,
YZY,
XYX,
XZX,
ZYXEx,
ZXYEx,
YXZEx,
YZXEx,
XYZEx,
XZYEx,
ZYZEx,
ZXZEx,
YXYEx,
YZYEx,
XYXEx,
XZXEx,
}
);
impl_reflect_opaque!(::glam::BVec3A(Debug, Default, Deserialize, Serialize));
impl_reflect_opaque!(::glam::BVec4A(Debug, Default, Deserialize, Serialize));
#[cfg(test)]
mod tests {
use ron::{
ser::{to_string_pretty, PrettyConfig},
Deserializer,
};
use serde::de::DeserializeSeed;
use static_assertions::assert_impl_all;
use crate::{
prelude::*,
serde::{ReflectDeserializer, ReflectSerializer},
Enum, GetTypeRegistration, TypeRegistry,
};
use super::*;
assert_impl_all!(EulerRot: Enum);
#[test]
fn euler_rot_serialization() {
let v = EulerRot::YXZ;
let mut registry = TypeRegistry::default();
registry.register::<EulerRot>();
let ser = ReflectSerializer::new(&v, &registry);
let config = PrettyConfig::default()
.new_line(String::from("\n"))
.indentor(String::from(" "));
let output = to_string_pretty(&ser, config).unwrap();
let expected = r#"
{
"glam::EulerRot": YXZ,
}"#;
assert_eq!(expected, format!("\n{output}"));
}
#[test]
fn euler_rot_deserialization() {
let data = r#"
{
"glam::EulerRot": XZY,
}"#;
let mut registry = TypeRegistry::default();
registry.add_registration(EulerRot::get_type_registration());
let de = ReflectDeserializer::new(&registry);
let mut deserializer =
Deserializer::from_str(data).expect("Failed to acquire deserializer");
let dynamic_struct = de
.deserialize(&mut deserializer)
.expect("Failed to deserialize");
let mut result = EulerRot::default();
result.apply(dynamic_struct.as_partial_reflect());
assert_eq!(result, EulerRot::XZY);
}
}