Skip to content

Commit bca8398

Browse files
Trashtalk217525c1e21-bd67-4735-ac99-b4b0e5262290alice-i-cecile
authored and
Thomas Wilgenbus
committed
Migrate Quat reflection strategy from "value" to "struct" (bevyengine#10068)
Adopted from bevyengine#8954, co-authored by @pyrotechnick # Objective The Bevy ecosystem currently reflects `Quat` via "value" rather than the more appropriate "struct" strategy. This behaviour is inconsistent to that of similar types, i.e. `Vec3`. Additionally, employing the "value" strategy causes instances of `Quat` to be serialised as a sequence `[x, y, z, w]` rather than structures of shape `{ x, y, z, w }`. The [comments surrounding the applicable code](https://github.com/bevyengine/bevy/blob/bec299fa6e727a59d973fc8ca8f468732d40cb14/crates/bevy_reflect/src/impls/glam.rs#L254) give context and historical reasons for this discrepancy: ``` // Quat fields are read-only (as of now), and reflection is currently missing // mechanisms for read-only fields. I doubt those mechanisms would be added, // so for now quaternions will remain as values. They are represented identically // to Vec4 and DVec4, so you may use those instead and convert between. ``` This limitation has [since been lifted by the upstream crate](bitshifter/glam-rs@3746251), glam. ## Solution Migrating the reflect strategy of Quat from "value" to "struct" via replacing `impl_reflect_value` with `impl_reflect_struct` resolves the issue. ## Changelog Migrated `Quat` reflection strategy to "struct" from "value" Migration Guide Changed Quat serialization/deserialization from sequences `[x, y, z, w]` to structures `{ x, y, z, w }`. --------- Co-authored-by: pyrotechnick <[email protected]> Co-authored-by: Alice Cecile <[email protected]>
1 parent 8ada9d8 commit bca8398

File tree

2 files changed

+80
-20
lines changed

2 files changed

+80
-20
lines changed

crates/bevy_reflect/src/impls/glam.rs

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use crate as bevy_reflect;
22
use crate::prelude::ReflectDefault;
3-
use crate::{ReflectDeserialize, ReflectSerialize};
43
use bevy_reflect_derive::{impl_reflect_struct, impl_reflect_value};
54
use glam::*;
65

@@ -310,24 +309,26 @@ impl_reflect_struct!(
310309
}
311310
);
312311

313-
// Quat fields are read-only (as of now), and reflection is currently missing
314-
// mechanisms for read-only fields. I doubt those mechanisms would be added,
315-
// so for now quaternions will remain as values. They are represented identically
316-
// to Vec4 and DVec4, so you may use those instead and convert between.
317-
impl_reflect_value!(::glam::Quat(
318-
Debug,
319-
PartialEq,
320-
Serialize,
321-
Deserialize,
322-
Default
323-
));
324-
impl_reflect_value!(::glam::DQuat(
325-
Debug,
326-
PartialEq,
327-
Serialize,
328-
Deserialize,
329-
Default
330-
));
312+
impl_reflect_struct!(
313+
#[reflect(Debug, PartialEq, Default)]
314+
#[type_path = "glam"]
315+
struct Quat {
316+
x: f32,
317+
y: f32,
318+
z: f32,
319+
w: f32,
320+
}
321+
);
322+
impl_reflect_struct!(
323+
#[reflect(Debug, PartialEq, Default)]
324+
#[type_path = "glam"]
325+
struct DQuat {
326+
x: f64,
327+
y: f64,
328+
z: f64,
329+
w: f64,
330+
}
331+
);
331332

332333
impl_reflect_value!(::glam::EulerRot(Debug, Default));
333334
impl_reflect_value!(::glam::BVec3A(Debug, Default));

crates/bevy_reflect/src/lib.rs

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,7 @@ pub mod __macro_exports {
575575
#[allow(clippy::disallowed_types, clippy::approx_constant)]
576576
mod tests {
577577
#[cfg(feature = "glam")]
578-
use ::glam::{vec3, Vec3};
578+
use ::glam::{quat, vec3, Quat, Vec3};
579579
use ::serde::{de::DeserializeSeed, Deserialize, Serialize};
580580
use bevy_utils::HashMap;
581581
use ron::{
@@ -1937,6 +1937,65 @@ bevy_reflect::tests::Test {
19371937
mod glam {
19381938
use super::*;
19391939

1940+
#[test]
1941+
fn quat_serialization() {
1942+
let q = quat(1.0, 2.0, 3.0, 4.0);
1943+
1944+
let mut registry = TypeRegistry::default();
1945+
registry.register::<f32>();
1946+
registry.register::<Quat>();
1947+
1948+
let ser = ReflectSerializer::new(&q, &registry);
1949+
1950+
let config = PrettyConfig::default()
1951+
.new_line(String::from("\n"))
1952+
.indentor(String::from(" "));
1953+
let output = to_string_pretty(&ser, config).unwrap();
1954+
let expected = r#"
1955+
{
1956+
"glam::Quat": (
1957+
x: 1.0,
1958+
y: 2.0,
1959+
z: 3.0,
1960+
w: 4.0,
1961+
),
1962+
}"#;
1963+
1964+
assert_eq!(expected, format!("\n{output}"));
1965+
}
1966+
1967+
#[test]
1968+
fn quat_deserialization() {
1969+
let data = r#"
1970+
{
1971+
"glam::Quat": (
1972+
x: 1.0,
1973+
y: 2.0,
1974+
z: 3.0,
1975+
w: 4.0,
1976+
),
1977+
}"#;
1978+
1979+
let mut registry = TypeRegistry::default();
1980+
registry.register::<Quat>();
1981+
registry.register::<f32>();
1982+
1983+
let de = UntypedReflectDeserializer::new(&registry);
1984+
1985+
let mut deserializer =
1986+
ron::de::Deserializer::from_str(data).expect("Failed to acquire deserializer");
1987+
1988+
let dynamic_struct = de
1989+
.deserialize(&mut deserializer)
1990+
.expect("Failed to deserialize");
1991+
1992+
let mut result = Quat::default();
1993+
1994+
result.apply(&*dynamic_struct);
1995+
1996+
assert_eq!(result, quat(1.0, 2.0, 3.0, 4.0));
1997+
}
1998+
19401999
#[test]
19412000
fn vec3_serialization() {
19422001
let v = vec3(12.0, 3.0, -6.9);

0 commit comments

Comments
 (0)