Reflection cleanup (#1536)

This is an effort to provide the correct `#[reflect_value(...)]` attributes where they are needed.  

Supersedes #1533 and resolves #1528.

---

I am working under the following assumptions (thanks to @bjorn3 and @Davier for advice here):

- Any `enum` that derives `Reflect` and one or more of { `Serialize`, `Deserialize`, `PartialEq`, `Hash` } needs a `#[reflect_value(...)]` attribute containing the same subset of { `Serialize`, `Deserialize`, `PartialEq`, `Hash` } that is present on the derive.
- Same as above for `struct` and `#[reflect(...)]`, respectively.
- If a `struct` is used as a component, it should also have `#[reflect(Component)]`
- All reflected types should be registered in their plugins

I treated the following as components (added `#[reflect(Component)]` if necessary):
- `bevy_render`
  - `struct RenderLayers`
- `bevy_transform`
  - `struct GlobalTransform`
  - `struct Parent`
  - `struct Transform`
- `bevy_ui`
  - `struct Style`

Not treated as components:
- `bevy_math`
  - `struct Size<T>`
  - `struct Rect<T>`
  - Note: The updates for `Size<T>` and `Rect<T>` in `bevy::math::geometry` required using @Davier's suggestion to add `+ PartialEq` to the trait bound. I then registered the specific types used over in `bevy_ui` such as `Size<Val>`, etc. in `bevy_ui`'s plugin, since `bevy::math` does not contain a plugin.
- `bevy_render`
  - `struct Color`
  - `struct PipelineSpecialization`
  - `struct ShaderSpecialization`
  - `enum PrimitiveTopology`
  - `enum IndexFormat`

Not Addressed:
- I am not searching for components in Bevy that are _not_ reflected. So if there are components that are not reflected that should be reflected, that will need to be figured out in another PR.
- I only added `#[reflect(...)]` or `#[reflect_value(...)]` entries for the set of four traits { `Serialize`, `Deserialize`, `PartialEq`, `Hash` } _if they were derived via `#[derive(...)]`_. I did not look for manual trait implementations of the same set of four, nor did I consider any traits outside the four.  Are those other possibilities something that needs to be looked into?
This commit is contained in:
Nathan Stocks 2021-03-09 23:39:41 +00:00
parent 514723295e
commit faeccd7a09
15 changed files with 91 additions and 26 deletions

View File

@ -18,6 +18,7 @@ pub mod prelude {
use bevy_app::prelude::*; use bevy_app::prelude::*;
use bevy_ecs::{entity::Entity, system::IntoSystem}; use bevy_ecs::{entity::Entity, system::IntoSystem};
use bevy_utils::HashSet;
use std::ops::Range; use std::ops::Range;
/// Adds core functionality to Apps. /// Adds core functionality to Apps.
@ -36,6 +37,8 @@ impl Plugin for CorePlugin {
app.init_resource::<Time>() app.init_resource::<Time>()
.init_resource::<EntityLabels>() .init_resource::<EntityLabels>()
.init_resource::<FixedTimesteps>() .init_resource::<FixedTimesteps>()
.register_type::<HashSet<String>>()
.register_type::<Option<String>>()
.register_type::<Entity>() .register_type::<Entity>()
.register_type::<Name>() .register_type::<Name>()
.register_type::<Labels>() .register_type::<Labels>()

View File

@ -4,18 +4,19 @@ use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
/// A two dimensional "size" as defined by a width and height /// A two dimensional "size" as defined by a width and height
#[derive(Copy, Clone, PartialEq, Debug, Reflect)] #[derive(Copy, Clone, PartialEq, Debug, Reflect)]
pub struct Size<T: Reflect = f32> { #[reflect(PartialEq)]
pub struct Size<T: Reflect + PartialEq = f32> {
pub width: T, pub width: T,
pub height: T, pub height: T,
} }
impl<T: Reflect> Size<T> { impl<T: Reflect + PartialEq> Size<T> {
pub fn new(width: T, height: T) -> Self { pub fn new(width: T, height: T) -> Self {
Size { width, height } Size { width, height }
} }
} }
impl<T: Default + Reflect> Default for Size<T> { impl<T: Default + Reflect + PartialEq> Default for Size<T> {
fn default() -> Self { fn default() -> Self {
Self { Self {
width: Default::default(), width: Default::default(),
@ -26,14 +27,15 @@ impl<T: Default + Reflect> Default for Size<T> {
/// A rect, as defined by its "side" locations /// A rect, as defined by its "side" locations
#[derive(Copy, Clone, PartialEq, Debug, Reflect)] #[derive(Copy, Clone, PartialEq, Debug, Reflect)]
pub struct Rect<T: Reflect> { #[reflect(PartialEq)]
pub struct Rect<T: Reflect + PartialEq> {
pub left: T, pub left: T,
pub right: T, pub right: T,
pub top: T, pub top: T,
pub bottom: T, pub bottom: T,
} }
impl<T: Reflect> Rect<T> { impl<T: Reflect + PartialEq> Rect<T> {
pub fn all(value: T) -> Self pub fn all(value: T) -> Self
where where
T: Clone, T: Clone,
@ -47,7 +49,7 @@ impl<T: Reflect> Rect<T> {
} }
} }
impl<T: Default + Reflect> Default for Rect<T> { impl<T: Default + Reflect + PartialEq> Default for Rect<T> {
fn default() -> Self { fn default() -> Self {
Self { Self {
left: Default::default(), left: Default::default(),
@ -58,7 +60,7 @@ impl<T: Default + Reflect> Default for Rect<T> {
} }
} }
impl<T: Reflect> Add<Vec2> for Size<T> impl<T: Reflect + PartialEq> Add<Vec2> for Size<T>
where where
T: Add<f32, Output = T>, T: Add<f32, Output = T>,
{ {
@ -72,7 +74,7 @@ where
} }
} }
impl<T: Reflect> AddAssign<Vec2> for Size<T> impl<T: Reflect + PartialEq> AddAssign<Vec2> for Size<T>
where where
T: AddAssign<f32>, T: AddAssign<f32>,
{ {
@ -82,7 +84,7 @@ where
} }
} }
impl<T: Reflect> Sub<Vec2> for Size<T> impl<T: Reflect + PartialEq> Sub<Vec2> for Size<T>
where where
T: Sub<f32, Output = T>, T: Sub<f32, Output = T>,
{ {
@ -96,7 +98,7 @@ where
} }
} }
impl<T: Reflect> SubAssign<Vec2> for Size<T> impl<T: Reflect + PartialEq> SubAssign<Vec2> for Size<T>
where where
T: SubAssign<f32>, T: SubAssign<f32>,
{ {
@ -106,7 +108,7 @@ where
} }
} }
impl<T: Reflect> Mul<f32> for Size<T> impl<T: Reflect + PartialEq> Mul<f32> for Size<T>
where where
T: Mul<f32, Output = T>, T: Mul<f32, Output = T>,
{ {
@ -120,7 +122,7 @@ where
} }
} }
impl<T: Reflect> MulAssign<f32> for Size<T> impl<T: Reflect + PartialEq> MulAssign<f32> for Size<T>
where where
T: MulAssign<f32>, T: MulAssign<f32>,
{ {
@ -130,7 +132,7 @@ where
} }
} }
impl<T: Reflect> Div<f32> for Size<T> impl<T: Reflect + PartialEq> Div<f32> for Size<T>
where where
T: Div<f32, Output = T>, T: Div<f32, Output = T>,
{ {
@ -144,7 +146,7 @@ where
} }
} }
impl<T: Reflect> DivAssign<f32> for Size<T> impl<T: Reflect + PartialEq> DivAssign<f32> for Size<T>
where where
T: DivAssign<f32>, T: DivAssign<f32>,
{ {

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
map_partial_eq, serde::Serializable, DynamicMap, List, ListIter, Map, MapIter, Reflect, map_partial_eq, serde::Serializable, DynamicMap, FromType, GetTypeRegistration, List, ListIter,
ReflectDeserialize, ReflectMut, ReflectRef, Map, MapIter, Reflect, ReflectDeserialize, ReflectMut, ReflectRef, TypeRegistration,
}; };
use bevy_reflect_derive::impl_reflect_value; use bevy_reflect_derive::impl_reflect_value;
@ -112,6 +112,14 @@ impl<T: Reflect> Reflect for Vec<T> {
} }
} }
impl<T: Reflect + for<'de> Deserialize<'de>> GetTypeRegistration for Vec<T> {
fn get_type_registration() -> TypeRegistration {
let mut registration = TypeRegistration::of::<Vec<T>>();
registration.insert::<ReflectDeserialize>(FromType::<Vec<T>>::from_type());
registration
}
}
impl<K: Reflect + Clone + Eq + Hash, V: Reflect + Clone> Map for HashMap<K, V> { impl<K: Reflect + Clone + Eq + Hash, V: Reflect + Clone> Map for HashMap<K, V> {
fn get(&self, key: &dyn Reflect) -> Option<&dyn Reflect> { fn get(&self, key: &dyn Reflect) -> Option<&dyn Reflect> {
key.downcast_ref::<K>() key.downcast_ref::<K>()
@ -207,6 +215,18 @@ impl<K: Reflect + Clone + Eq + Hash, V: Reflect + Clone> Reflect for HashMap<K,
} }
} }
impl<K, V> GetTypeRegistration for HashMap<K, V>
where
K: Reflect + Clone + Eq + Hash + for<'de> Deserialize<'de>,
V: Reflect + Clone + for<'de> Deserialize<'de>,
{
fn get_type_registration() -> TypeRegistration {
let mut registration = TypeRegistration::of::<HashMap<K, V>>();
registration.insert::<ReflectDeserialize>(FromType::<HashMap<K, V>>::from_type());
registration
}
}
impl Reflect for Cow<'static, str> { impl Reflect for Cow<'static, str> {
fn type_name(&self) -> &str { fn type_name(&self) -> &str {
std::any::type_name::<Self>() std::any::type_name::<Self>()
@ -266,3 +286,11 @@ impl Reflect for Cow<'static, str> {
Some(Serializable::Borrowed(self)) Some(Serializable::Borrowed(self))
} }
} }
impl GetTypeRegistration for Cow<'static, str> {
fn get_type_registration() -> TypeRegistration {
let mut registration = TypeRegistration::of::<Cow<'static, str>>();
registration.insert::<ReflectDeserialize>(FromType::<Cow<'static, str>>::from_type());
registration
}
}

View File

@ -194,6 +194,7 @@ mod tests {
#[test] #[test]
fn reflect_complex_patch() { fn reflect_complex_patch() {
#[derive(Reflect, Eq, PartialEq, Debug)] #[derive(Reflect, Eq, PartialEq, Debug)]
#[reflect(PartialEq)]
struct Foo { struct Foo {
a: u32, a: u32,
#[reflect(ignore)] #[reflect(ignore)]
@ -205,6 +206,7 @@ mod tests {
} }
#[derive(Reflect, Eq, PartialEq, Debug)] #[derive(Reflect, Eq, PartialEq, Debug)]
#[reflect(PartialEq)]
struct Bar { struct Bar {
x: u32, x: u32,
} }
@ -317,6 +319,7 @@ mod tests {
#[test] #[test]
fn reflect_take() { fn reflect_take() {
#[derive(Reflect, Debug, PartialEq)] #[derive(Reflect, Debug, PartialEq)]
#[reflect(PartialEq)]
struct Bar { struct Bar {
x: u32, x: u32,
} }

View File

@ -43,7 +43,7 @@ pub type Layer = u8;
/// ///
/// Entities without this component belong to layer `0`. /// Entities without this component belong to layer `0`.
#[derive(Copy, Clone, Reflect, PartialEq, Eq, PartialOrd, Ord)] #[derive(Copy, Clone, Reflect, PartialEq, Eq, PartialOrd, Ord)]
#[reflect(Component)] #[reflect(Component, PartialEq)]
pub struct RenderLayers(LayerMask); pub struct RenderLayers(LayerMask);
impl std::fmt::Debug for RenderLayers { impl std::fmt::Debug for RenderLayers {

View File

@ -7,7 +7,7 @@ use crate::{
use bevy_asset::Handle; use bevy_asset::Handle;
use bevy_core::{Byteable, Bytes}; use bevy_core::{Byteable, Bytes};
use bevy_math::{Vec3, Vec4}; use bevy_math::{Vec3, Vec4};
use bevy_reflect::Reflect; use bevy_reflect::{Reflect, ReflectDeserialize};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::ops::{Add, AddAssign, Mul, MulAssign}; use std::ops::{Add, AddAssign, Mul, MulAssign};
@ -16,6 +16,7 @@ use std::ops::{Add, AddAssign, Mul, MulAssign};
/// RGBA color in the Linear sRGB colorspace (often colloquially referred to as "linear", "RGB", or "linear RGB"). /// RGBA color in the Linear sRGB colorspace (often colloquially referred to as "linear", "RGB", or "linear RGB").
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Reflect)] #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Reflect)]
#[reflect(PartialEq, Serialize, Deserialize)]
pub struct Color { pub struct Color {
red: f32, red: f32,
green: f32, green: f32,

View File

@ -39,11 +39,12 @@ use bevy_app::prelude::*;
use bevy_asset::{AddAsset, AssetStage}; use bevy_asset::{AddAsset, AssetStage};
use bevy_ecs::schedule::StageLabel; use bevy_ecs::schedule::StageLabel;
use camera::{ use camera::{
ActiveCameras, Camera, OrthographicProjection, PerspectiveProjection, VisibleEntities, ActiveCameras, Camera, DepthCalculation, OrthographicProjection, PerspectiveProjection,
RenderLayers, ScalingMode, VisibleEntities, WindowOrigin,
}; };
use pipeline::{ use pipeline::{
IndexFormat, PipelineCompiler, PipelineDescriptor, PipelineSpecialization, PrimitiveTopology, IndexFormat, PipelineCompiler, PipelineDescriptor, PipelineSpecialization, PrimitiveTopology,
ShaderSpecialization, ShaderSpecialization, VertexBufferLayout,
}; };
use render_graph::{ use render_graph::{
base::{self, BaseRenderGraphConfig, MainPass}, base::{self, BaseRenderGraphConfig, MainPass},
@ -125,6 +126,7 @@ impl Plugin for RenderPlugin {
.add_asset::<Shader>() .add_asset::<Shader>()
.add_asset::<PipelineDescriptor>() .add_asset::<PipelineDescriptor>()
.register_type::<Camera>() .register_type::<Camera>()
.register_type::<DepthCalculation>()
.register_type::<Draw>() .register_type::<Draw>()
.register_type::<Visible>() .register_type::<Visible>()
.register_type::<RenderPipelines>() .register_type::<RenderPipelines>()
@ -137,6 +139,10 @@ impl Plugin for RenderPlugin {
.register_type::<PrimitiveTopology>() .register_type::<PrimitiveTopology>()
.register_type::<IndexFormat>() .register_type::<IndexFormat>()
.register_type::<PipelineSpecialization>() .register_type::<PipelineSpecialization>()
.register_type::<RenderLayers>()
.register_type::<ScalingMode>()
.register_type::<VertexBufferLayout>()
.register_type::<WindowOrigin>()
.init_resource::<ClearColor>() .init_resource::<ClearColor>()
.init_resource::<RenderGraph>() .init_resource::<RenderGraph>()
.init_resource::<PipelineCompiler>() .init_resource::<PipelineCompiler>()

View File

@ -5,12 +5,13 @@ use crate::{
shader::{Shader, ShaderError}, shader::{Shader, ShaderError},
}; };
use bevy_asset::{Assets, Handle}; use bevy_asset::{Assets, Handle};
use bevy_reflect::Reflect; use bevy_reflect::{Reflect, ReflectDeserialize};
use bevy_utils::{HashMap, HashSet}; use bevy_utils::{HashMap, HashSet};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Clone, Eq, PartialEq, Debug, Reflect)] #[derive(Clone, Eq, PartialEq, Debug, Reflect)]
#[reflect(PartialEq)]
pub struct PipelineSpecialization { pub struct PipelineSpecialization {
pub shader_specialization: ShaderSpecialization, pub shader_specialization: ShaderSpecialization,
pub primitive_topology: PrimitiveTopology, pub primitive_topology: PrimitiveTopology,
@ -41,6 +42,7 @@ impl PipelineSpecialization {
} }
#[derive(Clone, Eq, PartialEq, Debug, Default, Reflect, Serialize, Deserialize)] #[derive(Clone, Eq, PartialEq, Debug, Default, Reflect, Serialize, Deserialize)]
#[reflect(PartialEq, Serialize, Deserialize)]
pub struct ShaderSpecialization { pub struct ShaderSpecialization {
pub shader_defs: HashSet<String>, pub shader_defs: HashSet<String>,
} }

View File

@ -1,5 +1,5 @@
use crate::texture::TextureFormat; use crate::texture::TextureFormat;
use bevy_reflect::Reflect; use bevy_reflect::{Reflect, ReflectDeserialize};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -89,6 +89,7 @@ pub enum CompareFunction {
/// Describes how the VertexAttributes should be interpreted while rendering /// Describes how the VertexAttributes should be interpreted while rendering
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize, Reflect)] #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize, Reflect)]
#[reflect_value(Serialize, Deserialize, PartialEq, Hash)]
pub enum PrimitiveTopology { pub enum PrimitiveTopology {
PointList = 0, PointList = 0,
LineList = 1, LineList = 1,
@ -227,6 +228,7 @@ impl Default for BlendOperation {
} }
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize, Reflect)] #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize, Reflect)]
#[reflect_value(Hash, PartialEq, Serialize, Deserialize)]
pub enum IndexFormat { pub enum IndexFormat {
Uint16 = 0, Uint16 = 0,
Uint32 = 1, Uint32 = 1,

View File

@ -48,6 +48,7 @@ impl Plugin for SpritePlugin {
app.add_asset::<ColorMaterial>() app.add_asset::<ColorMaterial>()
.add_asset::<TextureAtlas>() .add_asset::<TextureAtlas>()
.register_type::<Sprite>() .register_type::<Sprite>()
.register_type::<SpriteResizeMode>()
.add_system_to_stage(CoreStage::PostUpdate, sprite_system.system()) .add_system_to_stage(CoreStage::PostUpdate, sprite_system.system())
.add_system_to_stage( .add_system_to_stage(
CoreStage::PostUpdate, CoreStage::PostUpdate,

View File

@ -5,7 +5,7 @@ use bevy_reflect::Reflect;
use std::ops::Mul; use std::ops::Mul;
#[derive(Debug, PartialEq, Clone, Copy, Reflect)] #[derive(Debug, PartialEq, Clone, Copy, Reflect)]
#[reflect(Component)] #[reflect(Component, PartialEq)]
pub struct GlobalTransform { pub struct GlobalTransform {
pub translation: Vec3, pub translation: Vec3,
pub rotation: Quat, pub rotation: Quat,

View File

@ -7,7 +7,7 @@ use bevy_reflect::Reflect;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
#[derive(Debug, Copy, Clone, Eq, PartialEq, Reflect)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Reflect)]
#[reflect(Component, MapEntities)] #[reflect(Component, MapEntities, PartialEq)]
pub struct Parent(pub Entity); pub struct Parent(pub Entity);
// TODO: We need to impl either FromWorld or Default so Parent can be registered as Properties. // TODO: We need to impl either FromWorld or Default so Parent can be registered as Properties.
@ -42,7 +42,7 @@ impl DerefMut for Parent {
} }
#[derive(Debug, Copy, Clone, Eq, PartialEq, Reflect)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Reflect)]
#[reflect(Component, MapEntities)] #[reflect(Component, MapEntities, PartialEq)]
pub struct PreviousParent(pub(crate) Entity); pub struct PreviousParent(pub(crate) Entity);
impl MapEntities for PreviousParent { impl MapEntities for PreviousParent {

View File

@ -5,7 +5,7 @@ use bevy_reflect::Reflect;
use std::ops::Mul; use std::ops::Mul;
#[derive(Debug, PartialEq, Clone, Copy, Reflect)] #[derive(Debug, PartialEq, Clone, Copy, Reflect)]
#[reflect(Component)] #[reflect(Component, PartialEq)]
pub struct Transform { pub struct Transform {
pub translation: Vec3, pub translation: Vec3,
pub rotation: Quat, pub rotation: Quat,

View File

@ -9,6 +9,7 @@ pub mod update;
pub mod widget; pub mod widget;
pub use anchors::*; pub use anchors::*;
use bevy_math::{Rect, Size};
use bevy_render::RenderStage; use bevy_render::RenderStage;
pub use flex::*; pub use flex::*;
pub use focus::*; pub use focus::*;
@ -47,6 +48,21 @@ pub mod system {
impl Plugin for UiPlugin { impl Plugin for UiPlugin {
fn build(&self, app: &mut AppBuilder) { fn build(&self, app: &mut AppBuilder) {
app.init_resource::<FlexSurface>() app.init_resource::<FlexSurface>()
.register_type::<AlignContent>()
.register_type::<AlignItems>()
.register_type::<AlignSelf>()
.register_type::<Direction>()
.register_type::<Display>()
.register_type::<FlexDirection>()
.register_type::<FlexWrap>()
.register_type::<JustifyContent>()
.register_type::<Node>()
.register_type::<PositionType>()
.register_type::<Size<f32>>()
.register_type::<Size<Val>>()
.register_type::<Rect<Val>>()
.register_type::<Style>()
.register_type::<Val>()
.add_stage_before(CoreStage::PostUpdate, UiStage::Ui, SystemStage::parallel()) .add_stage_before(CoreStage::PostUpdate, UiStage::Ui, SystemStage::parallel())
.add_system_to_stage(CoreStage::PreUpdate, ui_focus_system.system()) .add_system_to_stage(CoreStage::PreUpdate, ui_focus_system.system())
// add these stages to front because these must run before transform update systems // add these stages to front because these must run before transform update systems

View File

@ -50,6 +50,7 @@ impl AddAssign<f32> for Val {
} }
#[derive(Clone, PartialEq, Debug, Reflect)] #[derive(Clone, PartialEq, Debug, Reflect)]
#[reflect(Component, PartialEq)]
pub struct Style { pub struct Style {
pub display: Display, pub display: Display,
pub position_type: PositionType, pub position_type: PositionType,