diff --git a/crates/bevy_asset/src/handle.rs b/crates/bevy_asset/src/handle.rs index 06fdee6907a37..590dce8ce3ff2 100644 --- a/crates/bevy_asset/src/handle.rs +++ b/crates/bevy_asset/src/handle.rs @@ -10,7 +10,7 @@ use crate::{ Asset, Assets, }; use bevy_ecs::{component::Component, reflect::ReflectComponent}; -use bevy_reflect::{FromReflect, Reflect, ReflectDeserialize}; +use bevy_reflect::{FromReflect, Reflect, ReflectDeserialize, ReflectFromReflect}; use bevy_utils::Uuid; use crossbeam_channel::{Receiver, Sender}; use serde::{Deserialize, Serialize}; @@ -95,7 +95,7 @@ impl HandleId { /// collisions no longer being detected for that entity. /// #[derive(Component, Reflect, FromReflect)] -#[reflect(Component)] +#[reflect(Component, FromReflect)] pub struct Handle where T: Asset, diff --git a/crates/bevy_reflect/src/from_reflect.rs b/crates/bevy_reflect/src/from_reflect.rs new file mode 100644 index 0000000000000..7e8cc5a8ea723 --- /dev/null +++ b/crates/bevy_reflect/src/from_reflect.rs @@ -0,0 +1,37 @@ +use crate::{FromType, Reflect}; + +/// A trait for types which can be constructed from a reflected type. +/// +/// This trait can be derived on types which implement [`Reflect`]. Some complex +/// types (such as `Vec`) may only be reflected if their element types +/// implement this trait. +/// +/// For structs and tuple structs, fields marked with the `#[reflect(ignore)]` +/// attribute will be constructed using the `Default` implementation of the +/// field type, rather than the corresponding field value (if any) of the +/// reflected value. +pub trait FromReflect: Reflect + Sized { + /// Constructs a concrete instance of `Self` from a reflected value. + fn from_reflect(reflect: &dyn Reflect) -> Option; +} + +#[derive(Clone)] +pub struct ReflectFromReflect { + from_reflect: fn(&dyn Reflect) -> Option>, +} + +impl ReflectFromReflect { + pub fn from_reflect(&self, reflect_value: &dyn Reflect) -> Option> { + (self.from_reflect)(reflect_value) + } +} + +impl FromType for ReflectFromReflect { + fn from_type() -> Self { + Self { + from_reflect: |reflect_value| { + T::from_reflect(reflect_value).map(|value| Box::new(value) as Box) + }, + } + } +} diff --git a/crates/bevy_reflect/src/impls/glam.rs b/crates/bevy_reflect/src/impls/glam.rs index 077a202fbb872..3b83e22e406b5 100644 --- a/crates/bevy_reflect/src/impls/glam.rs +++ b/crates/bevy_reflect/src/impls/glam.rs @@ -1,27 +1,27 @@ use crate as bevy_reflect; -use crate::ReflectDeserialize; +use crate::{ReflectDeserialize, ReflectFromReflect}; use bevy_reflect_derive::{impl_from_reflect_value, impl_reflect_value}; use glam::*; -impl_reflect_value!(IVec2(PartialEq, Serialize, Deserialize)); -impl_reflect_value!(IVec3(PartialEq, Serialize, Deserialize)); -impl_reflect_value!(IVec4(PartialEq, Serialize, Deserialize)); -impl_reflect_value!(UVec2(PartialEq, Serialize, Deserialize)); -impl_reflect_value!(UVec3(PartialEq, Serialize, Deserialize)); -impl_reflect_value!(UVec4(PartialEq, Serialize, Deserialize)); -impl_reflect_value!(Vec2(PartialEq, Serialize, Deserialize)); -impl_reflect_value!(Vec3(PartialEq, Serialize, Deserialize)); -impl_reflect_value!(Vec3A(PartialEq, Serialize, Deserialize)); -impl_reflect_value!(Vec4(PartialEq, Serialize, Deserialize)); -impl_reflect_value!(DVec2(PartialEq, Serialize, Deserialize)); -impl_reflect_value!(DVec3(PartialEq, Serialize, Deserialize)); -impl_reflect_value!(DVec4(PartialEq, Serialize, Deserialize)); -impl_reflect_value!(Mat3(PartialEq, Serialize, Deserialize)); -impl_reflect_value!(Mat4(PartialEq, Serialize, Deserialize)); -impl_reflect_value!(Quat(PartialEq, Serialize, Deserialize)); -impl_reflect_value!(DMat3(PartialEq, Serialize, Deserialize)); -impl_reflect_value!(DMat4(PartialEq, Serialize, Deserialize)); -impl_reflect_value!(DQuat(PartialEq, Serialize, Deserialize)); +impl_reflect_value!(IVec2(PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(IVec3(PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(IVec4(PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(UVec2(PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(UVec3(PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(UVec4(PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(Vec2(PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(Vec3(PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(Vec3A(PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(Vec4(PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(DVec2(PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(DVec3(PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(DVec4(PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(Mat3(PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(Mat4(PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(Quat(PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(DMat3(PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(DMat4(PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(DQuat(PartialEq, Serialize, Deserialize, FromReflect)); impl_from_reflect_value!(IVec2); impl_from_reflect_value!(IVec3); diff --git a/crates/bevy_reflect/src/impls/std.rs b/crates/bevy_reflect/src/impls/std.rs index 0b1d4097e1e11..9a953d060cbf2 100644 --- a/crates/bevy_reflect/src/impls/std.rs +++ b/crates/bevy_reflect/src/impls/std.rs @@ -1,8 +1,8 @@ use crate as bevy_reflect; use crate::{ map_partial_eq, serde::Serializable, DynamicMap, FromReflect, FromType, GetTypeRegistration, - List, ListIter, Map, MapIter, Reflect, ReflectDeserialize, ReflectMut, ReflectRef, - TypeRegistration, + List, ListIter, Map, MapIter, Reflect, ReflectDeserialize, ReflectFromReflect, ReflectMut, + ReflectRef, TypeRegistration, }; use bevy_reflect_derive::{impl_from_reflect_value, impl_reflect_value}; @@ -15,26 +15,32 @@ use std::{ ops::Range, }; -impl_reflect_value!(bool(Hash, PartialEq, Serialize, Deserialize)); -impl_reflect_value!(u8(Hash, PartialEq, Serialize, Deserialize)); -impl_reflect_value!(u16(Hash, PartialEq, Serialize, Deserialize)); -impl_reflect_value!(u32(Hash, PartialEq, Serialize, Deserialize)); -impl_reflect_value!(u64(Hash, PartialEq, Serialize, Deserialize)); -impl_reflect_value!(u128(Hash, PartialEq, Serialize, Deserialize)); -impl_reflect_value!(usize(Hash, PartialEq, Serialize, Deserialize)); -impl_reflect_value!(i8(Hash, PartialEq, Serialize, Deserialize)); -impl_reflect_value!(i16(Hash, PartialEq, Serialize, Deserialize)); -impl_reflect_value!(i32(Hash, PartialEq, Serialize, Deserialize)); -impl_reflect_value!(i64(Hash, PartialEq, Serialize, Deserialize)); -impl_reflect_value!(i128(Hash, PartialEq, Serialize, Deserialize)); -impl_reflect_value!(isize(Hash, PartialEq, Serialize, Deserialize)); -impl_reflect_value!(f32(Serialize, Deserialize)); -impl_reflect_value!(f64(Serialize, Deserialize)); -impl_reflect_value!(String(Hash, PartialEq, Serialize, Deserialize)); -impl_reflect_value!(Option Deserialize<'de> + Reflect + 'static>(Serialize, Deserialize)); -impl_reflect_value!(HashSet Deserialize<'de> + Send + Sync + 'static>(Serialize, Deserialize)); -impl_reflect_value!(Range Deserialize<'de> + Send + Sync + 'static>(Serialize, Deserialize)); -impl_reflect_value!(Duration(Hash, PartialEq, Serialize, Deserialize)); +impl_reflect_value!(bool(Hash, PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(u8(Hash, PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(u16(Hash, PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(u32(Hash, PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(u64(Hash, PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(u128(Hash, PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(usize(Hash, PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(i8(Hash, PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(i16(Hash, PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(i32(Hash, PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(i64(Hash, PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(i128(Hash, PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(isize(Hash, PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(f32(Serialize, Deserialize, FromReflect)); +impl_reflect_value!(f64(Serialize, Deserialize, FromReflect)); +impl_reflect_value!(String(Hash, PartialEq, Serialize, Deserialize, FromReflect)); +impl_reflect_value!(Option Deserialize<'de> + Reflect + 'static>(Serialize, Deserialize, FromReflect)); +impl_reflect_value!(HashSet Deserialize<'de> + Send + Sync + 'static>(Serialize, Deserialize, FromReflect)); +impl_reflect_value!(Range Deserialize<'de> + Send + Sync + 'static>(Serialize, Deserialize, FromReflect)); +impl_reflect_value!(Duration( + Hash, + PartialEq, + Serialize, + Deserialize, + FromReflect +)); impl_from_reflect_value!(bool); impl_from_reflect_value!(u8); @@ -148,6 +154,7 @@ impl Deserialize<'de>> GetTypeRegistration for Vec fn get_type_registration() -> TypeRegistration { let mut registration = TypeRegistration::of::>(); registration.insert::(FromType::>::from_type()); + registration.insert::(FromType::>::from_type()); registration } } @@ -355,6 +362,7 @@ impl GetTypeRegistration for Cow<'static, str> { fn get_type_registration() -> TypeRegistration { let mut registration = TypeRegistration::of::>(); registration.insert::(FromType::>::from_type()); + registration.insert::(FromType::>::from_type()); registration } } diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index cd479d1e07dec..e5dff7417dff3 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -1,5 +1,6 @@ #![doc = include_str!("../README.md")] +mod from_reflect; mod list; mod map; mod path; @@ -24,6 +25,7 @@ mod impls { } pub mod serde; + pub mod prelude { #[doc(hidden)] pub use crate::{ @@ -32,6 +34,7 @@ pub mod prelude { }; } +pub use from_reflect::*; pub use impls::*; pub use list::*; pub use map::*; @@ -55,6 +58,7 @@ mod tests { ser::{to_string_pretty, PrettyConfig}, Deserializer, }; + use std::any::TypeId; use super::*; use crate as bevy_reflect; @@ -423,4 +427,113 @@ mod tests { std::any::type_name::() ); } + + #[test] + fn should_reflect_from_type_id() { + #[derive(Reflect, FromReflect)] + #[reflect(FromReflect, MyTrait)] + struct MyStruct { + foo: usize, + } + + #[reflect_trait] + trait MyTrait { + fn foo(&self) -> usize; + } + + impl MyTrait for MyStruct { + fn foo(&self) -> usize { + self.foo + } + } + + // === Struct === // + // Register + let mut registry = TypeRegistry::default(); + registry.register::(); + + // Get type data + let type_id = TypeId::of::(); + let rfr = registry + .get_type_data::(type_id) + .expect("the FromReflect trait should be registered"); + + // Call from_reflect + let mut dynamic_struct = DynamicStruct::default(); + dynamic_struct.insert("foo", 123usize); + let reflected = rfr + .from_reflect(&dynamic_struct) + .expect("the type should be properly reflected"); + + // Assert + let expected = MyStruct { foo: 123 }; + assert!(expected + .reflect_partial_eq(reflected.as_ref()) + .unwrap_or_default()); + let unexpected = MyStruct { foo: 321 }; + assert!(!unexpected + .reflect_partial_eq(reflected.as_ref()) + .unwrap_or_default()); + + // --- Traits --- // + let my_trait = registry + .get_type_data::(type_id) + .expect("the trait should be registered"); + let trait_obj = my_trait + .get(reflected.as_ref()) + .expect("the reflected value should be convertable to trait object"); + + assert_eq!(expected.foo, trait_obj.foo()); + + // === Vec === // + // Register + registry.register::>(); + + // Get type data + let type_id = TypeId::of::>(); + let rfr = registry + .get_type_data::(type_id) + .expect("the FromReflect trait should be registered"); + + // Call from_reflect + let mut dynamic_list = DynamicList::default(); + dynamic_list.push(1usize); + dynamic_list.push(2usize); + dynamic_list.push(3usize); + let reflected = rfr + .from_reflect(&dynamic_list) + .expect("the type should be properly reflected"); + + // Assert + let expected = vec![1usize, 2usize, 3usize]; + assert!(expected + .reflect_partial_eq(reflected.as_ref()) + .unwrap_or_default()); + let unexpected = vec![1usize, 2usize, 3usize, 4usize]; + assert!(!unexpected + .reflect_partial_eq(reflected.as_ref()) + .unwrap_or_default()); + + // === Value === // + // Register + registry.register::(); + + // Get type data + let type_id = TypeId::of::(); + let rfr = registry + .get_type_data::(type_id) + .expect("the FromReflect trait should be registered"); + + // Call from_reflect + let dynamic_value: i32 = 123; + let reflected = rfr + .from_reflect(&dynamic_value) + .expect("the type should be properly reflected"); + + // Assert + let expected: i32 = 123; + assert!(expected + .reflect_partial_eq(reflected.as_ref()) + .unwrap_or_default()); + } } diff --git a/crates/bevy_reflect/src/reflect.rs b/crates/bevy_reflect/src/reflect.rs index 4362068df918e..d029feb0ba377 100644 --- a/crates/bevy_reflect/src/reflect.rs +++ b/crates/bevy_reflect/src/reflect.rs @@ -135,21 +135,6 @@ pub unsafe trait Reflect: Any + Send + Sync { fn serializable(&self) -> Option; } -/// A trait for types which can be constructed from a reflected type. -/// -/// This trait can be derived on types which implement [`Reflect`]. Some complex -/// types (such as `Vec`) may only be reflected if their element types -/// implement this trait. -/// -/// For structs and tuple structs, fields marked with the `#[reflect(ignore)]` -/// attribute will be constructed using the `Default` implementation of the -/// field type, rather than the corresponding field value (if any) of the -/// reflected value. -pub trait FromReflect: Reflect + Sized { - /// Constructs a concrete instance of `Self` from a reflected value. - fn from_reflect(reflect: &dyn Reflect) -> Option; -} - impl Debug for dyn Reflect { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "Reflect({})", self.type_name()) diff --git a/crates/bevy_render/src/color/mod.rs b/crates/bevy_render/src/color/mod.rs index b1aaa66079a9a..207e99480d884 100644 --- a/crates/bevy_render/src/color/mod.rs +++ b/crates/bevy_render/src/color/mod.rs @@ -4,12 +4,12 @@ pub use colorspace::*; use crate::color::{HslRepresentation, SrgbColorSpace}; use bevy_math::{Vec3, Vec4}; -use bevy_reflect::{FromReflect, Reflect, ReflectDeserialize}; +use bevy_reflect::{FromReflect, Reflect, ReflectDeserialize, ReflectFromReflect}; use serde::{Deserialize, Serialize}; use std::ops::{Add, AddAssign, Mul, MulAssign}; #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Reflect, FromReflect)] -#[reflect(PartialEq, Serialize, Deserialize)] +#[reflect(PartialEq, Serialize, Deserialize, FromReflect)] pub enum Color { /// sRGBA color Rgba { diff --git a/crates/bevy_text/src/text.rs b/crates/bevy_text/src/text.rs index 95a9fa7ee54ff..d96a0a449fbf2 100644 --- a/crates/bevy_text/src/text.rs +++ b/crates/bevy_text/src/text.rs @@ -1,6 +1,6 @@ use bevy_asset::Handle; use bevy_ecs::{prelude::Component, reflect::ReflectComponent}; -use bevy_reflect::{FromReflect, Reflect, ReflectDeserialize}; +use bevy_reflect::{FromReflect, Reflect, ReflectDeserialize, ReflectFromReflect}; use bevy_render::color::Color; use serde::{Deserialize, Serialize}; @@ -65,6 +65,7 @@ impl Text { } #[derive(Debug, Default, Clone, FromReflect, Reflect)] +#[reflect(FromReflect)] pub struct TextSection { pub value: String, pub style: TextStyle, @@ -134,6 +135,7 @@ impl From for glyph_brush_layout::VerticalAlign { } #[derive(Clone, Debug, Reflect, FromReflect)] +#[reflect(FromReflect)] pub struct TextStyle { pub font: Handle, pub font_size: f32,