From 411f0f609e4acc3945ddda53ee4bd893d0c4b5fd Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Mon, 6 May 2024 11:08:10 +0200 Subject: [PATCH] Support more glam types (#145) ### Checklist * [x] I have read the [Contributor Guide](../../CONTRIBUTING.md) * [x] I have read and agree to the [Code of Conduct](../../CODE_OF_CONDUCT.md) * [x] I have added a description of my changes and why I'd like them included in the section below ### Description of Changes Does seem to actually be doable. ### TODO - [x] Fix `fields_mut` for `Quat` - [x] Fix `fields_mut` for `Mat2` ### Related Issues https://github.com/EmbarkStudios/mirror-mirror/issues/134 --- .../mirror-mirror/src/foreign_impls/glam.rs | 22 ++- .../src/foreign_impls/glam/mat2.rs | 154 +++++++++++++++ .../src/foreign_impls/glam/quat.rs | 180 +++++++++++++++++ .../src/foreign_impls/glam/vec4.rs | 182 ++++++++++++++++++ crates/mirror-mirror/src/lib.rs | 2 +- crates/mirror-mirror/src/tests/value.rs | 2 +- 6 files changed, 533 insertions(+), 9 deletions(-) create mode 100644 crates/mirror-mirror/src/foreign_impls/glam/mat2.rs create mode 100644 crates/mirror-mirror/src/foreign_impls/glam/quat.rs create mode 100644 crates/mirror-mirror/src/foreign_impls/glam/vec4.rs diff --git a/crates/mirror-mirror/src/foreign_impls/glam.rs b/crates/mirror-mirror/src/foreign_impls/glam.rs index 6815fe9..b653cfe 100644 --- a/crates/mirror-mirror/src/foreign_impls/glam.rs +++ b/crates/mirror-mirror/src/foreign_impls/glam.rs @@ -1,6 +1,10 @@ -use glam::{Mat3, Vec2, Vec3}; +use glam::{Mat3, Mat4, Vec2, Vec3, Vec4}; use mirror_mirror_macros::__private_derive_reflect_foreign; +mod mat2; +mod quat; +mod vec4; + __private_derive_reflect_foreign! { #[reflect(crate_name(crate))] pub struct Vec2 { @@ -18,12 +22,6 @@ __private_derive_reflect_foreign! { } } -// `Vec4`, `Quat`, and `Mat2` are left out because glam uses bad hacks which changes the struct -// definitions for different architectures (simd vs no simd) and cargo features. So we'd have -// to use the same hacks in mirror-mirror which I'd like to avoid. - -// `Mat4` is left out because it contains `Vec4` which we don't support. - __private_derive_reflect_foreign! { #[reflect(crate_name(crate))] pub struct Mat3 { @@ -32,3 +30,13 @@ __private_derive_reflect_foreign! { pub z_axis: Vec3, } } + +__private_derive_reflect_foreign! { + #[reflect(crate_name(crate))] + pub struct Mat4 { + pub x_axis: Vec4, + pub y_axis: Vec4, + pub z_axis: Vec4, + pub w_axis: Vec4, + } +} diff --git a/crates/mirror-mirror/src/foreign_impls/glam/mat2.rs b/crates/mirror-mirror/src/foreign_impls/glam/mat2.rs new file mode 100644 index 0000000..ab73d9b --- /dev/null +++ b/crates/mirror-mirror/src/foreign_impls/glam/mat2.rs @@ -0,0 +1,154 @@ +use glam::{Mat2, Vec2}; +use kollect::LinearMap; +use std::any::Any; + +use crate::{ + struct_::{FieldsIter, FieldsIterMut, StructValue}, + type_info::graph::*, + DefaultValue, DescribeType, FromReflect, Reflect, ReflectMut, ReflectOwned, ReflectRef, Struct, + Value, +}; + +impl Reflect for Mat2 { + trivial_reflect_methods!(); + + fn reflect_owned(self: Box) -> ReflectOwned { + ReflectOwned::Struct(self) + } + + fn reflect_ref(&self) -> ReflectRef<'_> { + ReflectRef::Struct(self) + } + + fn reflect_mut(&mut self) -> ReflectMut<'_> { + ReflectMut::Struct(self) + } + + fn patch(&mut self, value: &dyn Reflect) { + if let Some(struct_) = value.as_struct() { + if let Some(x_axis) = struct_.field("x_axis").and_then(<_>::from_reflect) { + self.x_axis = x_axis; + } + if let Some(y_axis) = struct_.field("y_axis").and_then(<_>::from_reflect) { + self.y_axis = y_axis; + } + } + } + + fn to_value(&self) -> Value { + StructValue::with_capacity(2) + .with_field("x_axis", self.x_axis) + .with_field("y_axis", self.y_axis) + .to_value() + } + + fn clone_reflect(&self) -> Box { + Box::new(*self) + } + + fn debug(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + write!(f, "{self:#?}") + } else { + write!(f, "{self:?}") + } + } +} + +impl Struct for Mat2 { + fn field(&self, name: &str) -> Option<&dyn Reflect> { + match name { + "x_axis" => Some(&self.x_axis), + "y_axis" => Some(&self.y_axis), + _ => None, + } + } + + fn field_mut(&mut self, name: &str) -> Option<&mut dyn Reflect> { + match name { + "x_axis" => Some(&mut self.x_axis), + "y_axis" => Some(&mut self.y_axis), + _ => None, + } + } + + fn field_at(&self, index: usize) -> Option<&dyn Reflect> { + match index { + 0 => Some(&self.x_axis), + 1 => Some(&self.y_axis), + _ => None, + } + } + + fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> { + match index { + 0 => Some(&mut self.x_axis), + 1 => Some(&mut self.y_axis), + _ => None, + } + } + + fn name_at(&self, index: usize) -> Option<&str> { + match index { + 0 => Some("x_axis"), + 1 => Some("y_axis"), + _ => None, + } + } + + fn fields(&self) -> FieldsIter<'_> { + Box::new( + [ + ("x_axis", self.x_axis.as_reflect()), + ("y_axis", self.y_axis.as_reflect()), + ] + .into_iter(), + ) + } + + fn fields_mut(&mut self) -> FieldsIterMut<'_> { + let repr = &mut **self; + Box::new( + [ + ("x_axis", repr.x_axis.as_reflect_mut()), + ("y_axis", repr.y_axis.as_reflect_mut()), + ] + .into_iter(), + ) + } + + fn fields_len(&self) -> usize { + 2 + } +} + +impl FromReflect for Mat2 { + fn from_reflect(reflect: &dyn Reflect) -> Option { + if let Some(mat) = reflect.downcast_ref() { + Some(*mat) + } else { + let struct_ = reflect.as_struct()?; + let x_axis = <_>::from_reflect(struct_.field("x_axis")?)?; + let y_axis = <_>::from_reflect(struct_.field("y_axis")?)?; + Some(Self::from_cols(x_axis, y_axis)) + } + } +} + +impl DefaultValue for Mat2 { + fn default_value() -> Option { + Some(Self::default().to_value()) + } +} + +impl DescribeType for Mat2 { + fn build(graph: &mut TypeGraph) -> NodeId { + graph.get_or_build_node_with::(|graph| { + let fields = &[ + NamedFieldNode::new::("x_axis", LinearMap::from([]), &[], graph), + NamedFieldNode::new::("y_axis", LinearMap::from([]), &[], graph), + ]; + StructNode::new::(fields, LinearMap::from([]), &[]) + }) + } +} diff --git a/crates/mirror-mirror/src/foreign_impls/glam/quat.rs b/crates/mirror-mirror/src/foreign_impls/glam/quat.rs new file mode 100644 index 0000000..dbb9aa6 --- /dev/null +++ b/crates/mirror-mirror/src/foreign_impls/glam/quat.rs @@ -0,0 +1,180 @@ +use glam::Quat; +use kollect::LinearMap; +use std::any::Any; + +use crate::{ + struct_::{FieldsIter, FieldsIterMut, StructValue}, + type_info::graph::*, + DefaultValue, DescribeType, FromReflect, Reflect, ReflectMut, ReflectOwned, ReflectRef, Struct, + Value, +}; + +impl Reflect for Quat { + trivial_reflect_methods!(); + + fn reflect_owned(self: Box) -> ReflectOwned { + ReflectOwned::Struct(self) + } + + fn reflect_ref(&self) -> ReflectRef<'_> { + ReflectRef::Struct(self) + } + + fn reflect_mut(&mut self) -> ReflectMut<'_> { + ReflectMut::Struct(self) + } + + fn patch(&mut self, value: &dyn Reflect) { + if let Some(struct_) = value.as_struct() { + if let Some(x) = struct_.field("x").and_then(<_>::from_reflect) { + self.x = x; + } + if let Some(y) = struct_.field("y").and_then(<_>::from_reflect) { + self.y = y; + } + if let Some(z) = struct_.field("z").and_then(<_>::from_reflect) { + self.z = z; + } + if let Some(w) = struct_.field("w").and_then(<_>::from_reflect) { + self.w = w; + } + } + } + + fn to_value(&self) -> Value { + StructValue::with_capacity(4) + .with_field("x", self.x) + .with_field("y", self.y) + .with_field("z", self.z) + .with_field("w", self.w) + .to_value() + } + + fn clone_reflect(&self) -> Box { + Box::new(*self) + } + + fn debug(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + write!(f, "{self:#?}") + } else { + write!(f, "{self:?}") + } + } +} + +impl Struct for Quat { + fn field(&self, name: &str) -> Option<&dyn Reflect> { + match name { + "x" => Some(&self.x), + "y" => Some(&self.y), + "z" => Some(&self.z), + "w" => Some(&self.w), + _ => None, + } + } + + fn field_mut(&mut self, name: &str) -> Option<&mut dyn Reflect> { + match name { + "x" => Some(&mut self.x), + "y" => Some(&mut self.y), + "z" => Some(&mut self.z), + "w" => Some(&mut self.w), + _ => None, + } + } + + fn field_at(&self, index: usize) -> Option<&dyn Reflect> { + match index { + 0 => Some(&self.x), + 1 => Some(&self.y), + 2 => Some(&self.z), + 3 => Some(&self.w), + _ => None, + } + } + + fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> { + match index { + 0 => Some(&mut self.x), + 1 => Some(&mut self.y), + 2 => Some(&mut self.z), + 3 => Some(&mut self.w), + _ => None, + } + } + + fn name_at(&self, index: usize) -> Option<&str> { + match index { + 0 => Some("x"), + 1 => Some("y"), + 2 => Some("z"), + 3 => Some("w"), + _ => None, + } + } + + fn fields(&self) -> FieldsIter<'_> { + Box::new( + [ + ("x", self.x.as_reflect()), + ("y", self.y.as_reflect()), + ("z", self.z.as_reflect()), + ("w", self.w.as_reflect()), + ] + .into_iter(), + ) + } + + fn fields_mut(&mut self) -> FieldsIterMut<'_> { + let repr = &mut **self; + Box::new( + [ + ("x", repr.x.as_reflect_mut()), + ("y", repr.y.as_reflect_mut()), + ("z", repr.z.as_reflect_mut()), + ("w", repr.w.as_reflect_mut()), + ] + .into_iter(), + ) + } + + fn fields_len(&self) -> usize { + 4 + } +} + +impl FromReflect for Quat { + fn from_reflect(reflect: &dyn Reflect) -> Option { + if let Some(quat) = reflect.downcast_ref() { + Some(*quat) + } else { + let struct_ = reflect.as_struct()?; + let x = <_>::from_reflect(struct_.field("x")?)?; + let y = <_>::from_reflect(struct_.field("y")?)?; + let z = <_>::from_reflect(struct_.field("z")?)?; + let w = <_>::from_reflect(struct_.field("w")?)?; + Some(Self::from_xyzw(x, y, z, w)) + } + } +} + +impl DefaultValue for Quat { + fn default_value() -> Option { + Some(Self::default().to_value()) + } +} + +impl DescribeType for Quat { + fn build(graph: &mut TypeGraph) -> NodeId { + graph.get_or_build_node_with::(|graph| { + let fields = &[ + NamedFieldNode::new::("x", LinearMap::from([]), &[], graph), + NamedFieldNode::new::("y", LinearMap::from([]), &[], graph), + NamedFieldNode::new::("z", LinearMap::from([]), &[], graph), + NamedFieldNode::new::("w", LinearMap::from([]), &[], graph), + ]; + StructNode::new::(fields, LinearMap::from([]), &[]) + }) + } +} diff --git a/crates/mirror-mirror/src/foreign_impls/glam/vec4.rs b/crates/mirror-mirror/src/foreign_impls/glam/vec4.rs new file mode 100644 index 0000000..7b3f23c --- /dev/null +++ b/crates/mirror-mirror/src/foreign_impls/glam/vec4.rs @@ -0,0 +1,182 @@ +use glam::Vec4; +use kollect::LinearMap; +use std::any::Any; + +use crate::{ + struct_::{FieldsIter, FieldsIterMut, StructValue}, + type_info::graph::*, + DefaultValue, DescribeType, FromReflect, Reflect, ReflectMut, ReflectOwned, ReflectRef, Struct, + Value, +}; + +impl Reflect for Vec4 { + trivial_reflect_methods!(); + + fn reflect_owned(self: Box) -> ReflectOwned { + ReflectOwned::Struct(self) + } + + fn reflect_ref(&self) -> ReflectRef<'_> { + ReflectRef::Struct(self) + } + + fn reflect_mut(&mut self) -> ReflectMut<'_> { + ReflectMut::Struct(self) + } + + fn patch(&mut self, value: &dyn Reflect) { + if let Some(struct_) = value.as_struct() { + if let Some(x) = struct_.field("x").and_then(<_>::from_reflect) { + self.x = x; + } + if let Some(y) = struct_.field("y").and_then(<_>::from_reflect) { + self.y = y; + } + if let Some(z) = struct_.field("z").and_then(<_>::from_reflect) { + self.z = z; + } + if let Some(w) = struct_.field("w").and_then(<_>::from_reflect) { + self.w = w; + } + } + } + + fn to_value(&self) -> Value { + StructValue::with_capacity(4) + .with_field("x", self.x) + .with_field("y", self.y) + .with_field("z", self.z) + .with_field("w", self.w) + .to_value() + } + + fn clone_reflect(&self) -> Box { + Box::new(*self) + } + + fn debug(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + write!(f, "{self:#?}") + } else { + write!(f, "{self:?}") + } + } +} + +impl Struct for Vec4 { + fn field(&self, name: &str) -> Option<&dyn Reflect> { + match name { + "x" => Some(&self.x), + "y" => Some(&self.y), + "z" => Some(&self.z), + "w" => Some(&self.w), + _ => None, + } + } + + fn field_mut(&mut self, name: &str) -> Option<&mut dyn Reflect> { + match name { + "x" => Some(&mut self.x), + "y" => Some(&mut self.y), + "z" => Some(&mut self.z), + "w" => Some(&mut self.w), + _ => None, + } + } + + fn field_at(&self, index: usize) -> Option<&dyn Reflect> { + match index { + 0 => Some(&self.x), + 1 => Some(&self.y), + 2 => Some(&self.z), + 3 => Some(&self.w), + _ => None, + } + } + + fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> { + match index { + 0 => Some(&mut self.x), + 1 => Some(&mut self.y), + 2 => Some(&mut self.z), + 3 => Some(&mut self.w), + _ => None, + } + } + + fn name_at(&self, index: usize) -> Option<&str> { + match index { + 0 => Some("x"), + 1 => Some("y"), + 2 => Some("z"), + 3 => Some("w"), + _ => None, + } + } + + fn fields(&self) -> FieldsIter<'_> { + Box::new( + [ + ("x", self.x.as_reflect()), + ("y", self.y.as_reflect()), + ("z", self.z.as_reflect()), + ("w", self.w.as_reflect()), + ] + .into_iter(), + ) + } + + fn fields_mut(&mut self) -> FieldsIterMut<'_> { + let [x, y, z, w] = self.as_mut(); + Box::new( + [ + ("x", x.as_reflect_mut()), + ("y", y.as_reflect_mut()), + ("z", z.as_reflect_mut()), + ("w", w.as_reflect_mut()), + ] + .into_iter(), + ) + } + + fn fields_len(&self) -> usize { + 4 + } +} + +impl FromReflect for Vec4 { + fn from_reflect(reflect: &dyn Reflect) -> Option { + if let Some(vec) = reflect.downcast_ref() { + Some(*vec) + } else { + let struct_ = reflect.as_struct()?; + let components = ( + <_>::from_reflect(struct_.field("x")?)?, + <_>::from_reflect(struct_.field("y")?)?, + <_>::from_reflect(struct_.field("z")?)?, + <_>::from_reflect(struct_.field("w")?)?, + ); + Some(components.into()) + } + } +} + +impl DefaultValue for Vec4 { + fn default_value() -> Option { + Some(Self::default().to_value()) + } +} + +impl DescribeType for Vec4 { + fn build(graph: &mut TypeGraph) -> NodeId { + graph.get_or_build_node_with::(|graph| { + let fields = &[ + NamedFieldNode::new::("x", LinearMap::from([]), &[], graph), + NamedFieldNode::new::("y", LinearMap::from([]), &[], graph), + NamedFieldNode::new::("z", LinearMap::from([]), &[], graph), + NamedFieldNode::new::("w", LinearMap::from([]), &[], graph), + ]; + StructNode::new::(fields, LinearMap::from([]), &[]) + }) + } +} diff --git a/crates/mirror-mirror/src/lib.rs b/crates/mirror-mirror/src/lib.rs index bc9480f..0856a0f 100644 --- a/crates/mirror-mirror/src/lib.rs +++ b/crates/mirror-mirror/src/lib.rs @@ -747,7 +747,7 @@ impl Reflect for String { fn patch(&mut self, value: &dyn Reflect) { if let Some(value) = value.as_any().downcast_ref::() { - *self = value.clone(); + self.clone_from(value); } } diff --git a/crates/mirror-mirror/src/tests/value.rs b/crates/mirror-mirror/src/tests/value.rs index e739557..602cd59 100644 --- a/crates/mirror-mirror/src/tests/value.rs +++ b/crates/mirror-mirror/src/tests/value.rs @@ -27,5 +27,5 @@ fn hash() { assert_eq!(map.get(&1_i32.to_value()).unwrap(), &"one"); assert_eq!(map.get(&"foo".to_owned().to_value()).unwrap(), &"two"); - assert!(map.get(&true.to_value()).is_none()); + assert!(!map.contains_key(&true.to_value())); }