From 6f291a037f68cb9149d544f0a2c421e121fdcdcc Mon Sep 17 00:00:00 2001 From: Nicola Papale Date: Tue, 25 Apr 2023 12:11:11 +0200 Subject: [PATCH 01/21] Fix panic when using debug_asset_server (#8485) # Objective - Fixes #8484 ## Solution Since #8445 fonts need to register a debug asset, otherwise the `debug_asset_server` feature doesn't work. This adds the debug asset registration --- crates/bevy_text/src/font.rs | 2 +- crates/bevy_text/src/lib.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/bevy_text/src/font.rs b/crates/bevy_text/src/font.rs index 56fe1e60fc..4b80d74ffa 100644 --- a/crates/bevy_text/src/font.rs +++ b/crates/bevy_text/src/font.rs @@ -5,7 +5,7 @@ use bevy_render::{ texture::Image, }; -#[derive(Debug, TypeUuid)] +#[derive(Debug, TypeUuid, Clone)] #[uuid = "97059ac6-c9ba-4da9-95b6-bed82c3ce198"] pub struct Font { pub font: FontArc, diff --git a/crates/bevy_text/src/lib.rs b/crates/bevy_text/src/lib.rs index 4f9ab2497d..ed7825adbb 100644 --- a/crates/bevy_text/src/lib.rs +++ b/crates/bevy_text/src/lib.rs @@ -76,6 +76,7 @@ pub const DEFAULT_FONT_HANDLE: HandleUntyped = impl Plugin for TextPlugin { fn build(&self, app: &mut App) { app.add_asset::() + .add_debug_asset::() .add_asset::() .register_type::() .register_type::() From dea91e94d6909133332d729381cef06a4bb1a33d Mon Sep 17 00:00:00 2001 From: Michael Johnson Date: Tue, 25 Apr 2023 15:56:05 +0100 Subject: [PATCH 02/21] Re-add the "frame" span for tracy comparisons (#8362) # Objective In https://github.com/bevyengine/bevy/pull/6503 there were two changes to the top level tracing span "frame. Firstly it was renamed to "main app" and secondly the scope was reduced to *only* the main app. This means that there is no longer a top level span that can be used to compare frame times. In addition to making it easier to compare across versions again, it also helps when running without the render feature. Previously the "frame" span was present in both cases but now to compare "headless" and render the comparison is between "main app" and "winit event_handler" and Tracy doesn't handle comparing non-matching frames well. Before (0.9) ![image](https://user-images.githubusercontent.com/1353401/231454801-5690fb40-f9c1-4c64-b7b3-cebb15f1d16a.png) After (0.10) ![image](https://user-images.githubusercontent.com/1353401/231454926-df76e7d3-b5fa-49bc-a56c-67301d2a9e8a.png) ## Solution This PR reintroduces the "frame" span so comparisons across versions and features is again easy. ![image](https://user-images.githubusercontent.com/1353401/231455114-94f86d22-64de-48fc-9a0f-a5c607d3f350.png) ![image](https://user-images.githubusercontent.com/1353401/231455182-fe27a646-b55e-4bfb-8e05-c4690f52c550.png) ### Alternative As an alternative route, the `tracy-client` crate that is used by `tracing-tracy` supports the ability to set multiple "Frame" markers using the `secondary_mark_frame` function. It may be possible to create a PR for `tracing-tracy` that exposes that functionality and then publish an "update" frame marker instead. This might have additional benefits in the future as it could be used for other systems we might want to track as frames without endless nesting. --- crates/bevy_app/src/app.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index 404ed09a49..780b1ada97 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -236,9 +236,11 @@ impl App { /// /// The active schedule of the app must be set before this method is called. pub fn update(&mut self) { + #[cfg(feature = "trace")] + let _bevy_update_span = info_span!("update").entered(); { #[cfg(feature = "trace")] - let _bevy_frame_update_span = info_span!("main app").entered(); + let _bevy_main_update_span = info_span!("main app").entered(); self.world.run_schedule(&*self.main_schedule_label); } for (_label, sub_app) in self.sub_apps.iter_mut() { From 949487d92c1fde8735ded143c791f94c8117f5b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Tue, 25 Apr 2023 21:30:48 +0200 Subject: [PATCH 03/21] make glsl and spirv support optional (#8491) # Objective - Reduce compilation time ## Solution - Make `spirv` and `glsl` shader format support optional. They are not needed for Bevy shaders. - on my mac (where shaders are compiled to `msl`), this reduces the total build time by 2 to 5 seconds, improvement should be even better with less cores There is a big reduction in compile time for `naga`, and small improvements on `wgpu` and `bevy_render` This PR with optional shader formats enabled timings: current main This PR: this pr --- ## Migration Guide - If you want to use shaders in `spirv`, enable the `shader_format_spirv` feature - If you want to use shaders in `glsl`, enable the `shader_format_glsl` feature --- Cargo.toml | 6 +++ crates/bevy_internal/Cargo.toml | 4 ++ crates/bevy_render/Cargo.toml | 7 +++- .../src/render_resource/pipeline_cache.rs | 4 ++ .../bevy_render/src/render_resource/shader.rs | 40 ++++++++++++++++--- docs/cargo_features.md | 2 + 6 files changed, 56 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ae769ee50f..4e25ee76b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -229,6 +229,12 @@ glam_assert = ["bevy_internal/glam_assert"] # Include a default font, containing only ASCII characters, at the cost of a 20kB binary size increase default_font = ["bevy_internal/default_font"] +# Enable support for shaders in GLSL +shader_format_glsl = ["bevy_internal/shader_format_glsl"] + +# Enable support for shaders in SPIR-V +shader_format_spirv = ["bevy_internal/shader_format_spirv"] + [dependencies] bevy_dylib = { path = "crates/bevy_dylib", version = "0.11.0-dev", default-features = false, optional = true } bevy_internal = { path = "crates/bevy_internal", version = "0.11.0-dev", default-features = false } diff --git a/crates/bevy_internal/Cargo.toml b/crates/bevy_internal/Cargo.toml index 51fe644c92..4c828dd848 100644 --- a/crates/bevy_internal/Cargo.toml +++ b/crates/bevy_internal/Cargo.toml @@ -57,6 +57,10 @@ symphonia-isomp4 = ["bevy_audio/symphonia-isomp4"] symphonia-vorbis = ["bevy_audio/symphonia-vorbis"] symphonia-wav = ["bevy_audio/symphonia-wav"] +# Shader formats +shader_format_glsl = ["bevy_render/shader_format_glsl"] +shader_format_spirv = ["bevy_render/shader_format_spirv"] + # Enable watching file system for asset hot reload filesystem_watcher = ["bevy_asset/filesystem_watcher"] diff --git a/crates/bevy_render/Cargo.toml b/crates/bevy_render/Cargo.toml index e10f7f6da5..a75130c133 100644 --- a/crates/bevy_render/Cargo.toml +++ b/crates/bevy_render/Cargo.toml @@ -18,6 +18,9 @@ bmp = ["image/bmp"] webp = ["image/webp"] dds = ["ddsfile"] +shader_format_glsl = ["naga/glsl-in", "naga/wgsl-out"] +shader_format_spirv = ["wgpu/spirv", "naga/spv-in", "naga/spv-out"] + # For ktx2 supercompression zlib = ["flate2"] zstd = ["ruzstd"] @@ -52,10 +55,10 @@ bevy_tasks = { path = "../bevy_tasks", version = "0.11.0-dev" } image = { version = "0.24", default-features = false } # misc -wgpu = { version = "0.15.0", features = ["spirv"] } +wgpu = { version = "0.15.0" } wgpu-hal = "0.15.1" codespan-reporting = "0.11.0" -naga = { version = "0.11.0", features = ["glsl-in", "spv-in", "spv-out", "wgsl-in", "wgsl-out"] } +naga = { version = "0.11.0", features = ["wgsl-in"] } serde = { version = "1", features = ["derive"] } bitflags = "1.2.1" smallvec = { version = "1.6", features = ["union", "const_generics"] } diff --git a/crates/bevy_render/src/render_resource/pipeline_cache.rs b/crates/bevy_render/src/render_resource/pipeline_cache.rs index 783d35abb2..f958ee443b 100644 --- a/crates/bevy_render/src/render_resource/pipeline_cache.rs +++ b/crates/bevy_render/src/render_resource/pipeline_cache.rs @@ -752,6 +752,7 @@ fn log_shader_error(source: &ProcessedShader, error: &AsModuleDescriptorError) { let msg = error.emit_to_string(source); error!("failed to process shader:\n{}", msg); } + #[cfg(feature = "shader_format_glsl")] ShaderReflectError::GlslParse(errors) => { let source = source .get_glsl_source() @@ -776,6 +777,7 @@ fn log_shader_error(source: &ProcessedShader, error: &AsModuleDescriptorError) { error!("failed to process shader: \n{}", msg); } + #[cfg(feature = "shader_format_spirv")] ShaderReflectError::SpirVParse(error) => { error!("failed to process shader:\n{}", error); } @@ -818,9 +820,11 @@ fn log_shader_error(source: &ProcessedShader, error: &AsModuleDescriptorError) { error!("failed to process shader: \n{}", msg); } }, + #[cfg(feature = "shader_format_glsl")] AsModuleDescriptorError::WgslConversion(error) => { error!("failed to convert shader to wgsl: \n{}", error); } + #[cfg(feature = "shader_format_spirv")] AsModuleDescriptorError::SpirVConversion(error) => { error!("failed to convert shader to spirv: \n{}", error); } diff --git a/crates/bevy_render/src/render_resource/shader.rs b/crates/bevy_render/src/render_resource/shader.rs index a0b874c092..95116432b2 100644 --- a/crates/bevy_render/src/render_resource/shader.rs +++ b/crates/bevy_render/src/render_resource/shader.rs @@ -3,12 +3,16 @@ use crate::define_atomic_id; use bevy_asset::{AssetLoader, AssetPath, Handle, LoadContext, LoadedAsset}; use bevy_reflect::TypeUuid; use bevy_utils::{tracing::error, BoxedFuture, HashMap}; -use naga::{back::wgsl::WriterFlags, valid::Capabilities, valid::ModuleInfo, Module}; +#[cfg(feature = "shader_format_glsl")] +use naga::back::wgsl::WriterFlags; +use naga::{valid::Capabilities, valid::ModuleInfo, Module}; use once_cell::sync::Lazy; use regex::Regex; use std::{borrow::Cow, marker::Copy, ops::Deref, path::PathBuf, str::FromStr}; use thiserror::Error; -use wgpu::{util::make_spirv, Features, ShaderModuleDescriptor, ShaderSource}; +#[cfg(feature = "shader_format_spirv")] +use wgpu::util::make_spirv; +use wgpu::{Features, ShaderModuleDescriptor, ShaderSource}; define_atomic_id!(ShaderId); @@ -16,8 +20,10 @@ define_atomic_id!(ShaderId); pub enum ShaderReflectError { #[error(transparent)] WgslParse(#[from] naga::front::wgsl::ParseError), + #[cfg(feature = "shader_format_glsl")] #[error("GLSL Parse Error: {0:?}")] GlslParse(Vec), + #[cfg(feature = "shader_format_spirv")] #[error(transparent)] SpirVParse(#[from] naga::front::spv::Error), #[error(transparent)] @@ -120,12 +126,18 @@ impl ProcessedShader { let module = match &self { // TODO: process macros here ProcessedShader::Wgsl(source) => naga::front::wgsl::parse_str(source)?, + #[cfg(feature = "shader_format_glsl")] ProcessedShader::Glsl(source, shader_stage) => { let mut parser = naga::front::glsl::Parser::default(); parser .parse(&naga::front::glsl::Options::from(*shader_stage), source) .map_err(ShaderReflectError::GlslParse)? } + #[cfg(not(feature = "shader_format_glsl"))] + ProcessedShader::Glsl(_source, _shader_stage) => { + unimplemented!("Enable feature \"shader_format_glsl\" to use GLSL shaders") + } + #[cfg(feature = "shader_format_spirv")] ProcessedShader::SpirV(source) => naga::front::spv::parse_u8_slice( source, &naga::front::spv::Options { @@ -133,6 +145,10 @@ impl ProcessedShader { ..naga::front::spv::Options::default() }, )?, + #[cfg(not(feature = "shader_format_spirv"))] + ProcessedShader::SpirV(_source) => { + unimplemented!("Enable feature \"shader_format_spirv\" to use SPIR-V shaders") + } }; const CAPABILITIES: &[(Features, Capabilities)] = &[ (Features::PUSH_CONSTANTS, Capabilities::PUSH_CONSTANT), @@ -172,7 +188,7 @@ impl ProcessedShader { pub fn get_module_descriptor( &self, - features: Features, + _features: Features, ) -> Result { Ok(ShaderModuleDescriptor { label: None, @@ -182,18 +198,28 @@ impl ProcessedShader { // Parse and validate the shader early, so that (e.g. while hot reloading) we can // display nicely formatted error messages instead of relying on just displaying the error string // returned by wgpu upon creating the shader module. - let _ = self.reflect(features)?; + let _ = self.reflect(_features)?; ShaderSource::Wgsl(source.clone()) } + #[cfg(feature = "shader_format_glsl")] ProcessedShader::Glsl(_source, _stage) => { - let reflection = self.reflect(features)?; + let reflection = self.reflect(_features)?; // TODO: it probably makes more sense to convert this to spirv, but as of writing // this comment, naga's spirv conversion is broken let wgsl = reflection.get_wgsl()?; ShaderSource::Wgsl(wgsl.into()) } + #[cfg(not(feature = "shader_format_glsl"))] + ProcessedShader::Glsl(_source, _stage) => { + unimplemented!("Enable feature \"shader_format_glsl\" to use GLSL shaders") + } + #[cfg(feature = "shader_format_spirv")] ProcessedShader::SpirV(source) => make_spirv(source), + #[cfg(not(feature = "shader_format_spirv"))] + ProcessedShader::SpirV(_source) => { + unimplemented!() + } }, }) } @@ -203,8 +229,10 @@ impl ProcessedShader { pub enum AsModuleDescriptorError { #[error(transparent)] ShaderReflectError(#[from] ShaderReflectError), + #[cfg(feature = "shader_format_glsl")] #[error(transparent)] WgslConversion(#[from] naga::back::wgsl::Error), + #[cfg(feature = "shader_format_spirv")] #[error(transparent)] SpirVConversion(#[from] naga::back::spv::Error), } @@ -215,6 +243,7 @@ pub struct ShaderReflection { } impl ShaderReflection { + #[cfg(feature = "shader_format_spirv")] pub fn get_spirv(&self) -> Result, naga::back::spv::Error> { naga::back::spv::write_vec( &self.module, @@ -227,6 +256,7 @@ impl ShaderReflection { ) } + #[cfg(feature = "shader_format_glsl")] pub fn get_wgsl(&self) -> Result { naga::back::wgsl::write_string(&self.module, &self.module_info, WriterFlags::EXPLICIT_TYPES) } diff --git a/docs/cargo_features.md b/docs/cargo_features.md index d2a876d10f..28d4b205d9 100644 --- a/docs/cargo_features.md +++ b/docs/cargo_features.md @@ -57,6 +57,8 @@ The default feature set enables most of the expected features of a game engine, |minimp3|MP3 audio format support (through minimp3)| |mp3|MP3 audio format support| |serialize|Enable serialization support through serde| +|shader_format_glsl|Enable support for shaders in GLSL| +|shader_format_spirv|Enable support for shaders in SPIR-V| |subpixel_glyph_atlas|Enable rendering of font glyphs using subpixel accuracy| |symphonia-aac|AAC audio format support (through symphonia)| |symphonia-all|AAC, FLAC, MP3, MP4, OGG/VORBIS, and WAV audio formats support (through symphonia)| From 6df65a2aa8e1ca28314f9f428650e17a4fa3bf16 Mon Sep 17 00:00:00 2001 From: Gino Valente <49806985+MrGVSV@users.noreply.github.com> Date: Tue, 25 Apr 2023 12:32:34 -0700 Subject: [PATCH 04/21] bevy_asset: Add `LoadContext::get_handle_untyped` (#8470) # Objective Currently, there isn't a clean way of getting an untyped handle to an asset during asset loading. This is useful for when an asset needs to reference other assets, but may not know the concrete type of each asset. We could "hack" this together by just using some random asset: ```rust // We don't care what `bar.baz` is, so we "pretend" it's an `Image` let handle: Handle = load_context.get_handle("foo/bar.baz"); ``` This should work since we don't actually care about the underlying type in this case. However, we can do better. ## Solution Add the `LoadContext::get_handle_untyped` method to get untyped handles to assets. --- crates/bevy_asset/src/loader.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/crates/bevy_asset/src/loader.rs b/crates/bevy_asset/src/loader.rs index 2b76edadf8..55611b6a18 100644 --- a/crates/bevy_asset/src/loader.rs +++ b/crates/bevy_asset/src/loader.rs @@ -1,6 +1,6 @@ use crate::{ path::AssetPath, AssetIo, AssetIoError, AssetMeta, AssetServer, Assets, Handle, HandleId, - RefChangeChannel, + HandleUntyped, RefChangeChannel, }; use anyhow::Error; use anyhow::Result; @@ -166,11 +166,16 @@ impl<'a> LoadContext<'a> { self.get_handle(AssetPath::new_ref(self.path(), Some(label))) } - /// Gets a handle to an asset of type `T` from its id. + /// Gets a strong handle to an asset of type `T` from its id. pub fn get_handle, T: Asset>(&self, id: I) -> Handle { Handle::strong(id.into(), self.ref_change_channel.sender.clone()) } + /// Gets an untyped strong handle for an asset with the provided id. + pub fn get_handle_untyped>(&self, id: I) -> HandleUntyped { + HandleUntyped::strong(id.into(), self.ref_change_channel.sender.clone()) + } + /// Reads the contents of the file at the specified path through the [`AssetIo`] associated /// with this context. pub async fn read_asset_bytes>(&self, path: P) -> Result, AssetIoError> { From 74d425263a77acd14576f24c5c08d70f797fd489 Mon Sep 17 00:00:00 2001 From: Gino Valente <49806985+MrGVSV@users.noreply.github.com> Date: Wed, 26 Apr 2023 05:16:17 -0700 Subject: [PATCH 05/21] bevy_reflect: Add `ReflectFromReflect` to the prelude (#8496) # Objective Considering that `FromReflect` is a very common trait to derive, it would make sense to include `ReflectFromReflect` in the `bevy_reflect` prelude so users don't need to import it separately. ## Solution Add `ReflectFromReflect` to the prelude. --- crates/bevy_reflect/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index 8b75615963..571fce022a 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -479,7 +479,7 @@ pub mod prelude { #[doc(hidden)] pub use crate::{ reflect_trait, FromReflect, GetField, GetTupleStructField, Reflect, ReflectDeserialize, - ReflectSerialize, Struct, TupleStruct, + ReflectFromReflect, ReflectSerialize, Struct, TupleStruct, }; } From 85c3251c109a810fce23688dffbb2869c9dd0f69 Mon Sep 17 00:00:00 2001 From: Gino Valente <49806985+MrGVSV@users.noreply.github.com> Date: Wed, 26 Apr 2023 05:17:23 -0700 Subject: [PATCH 06/21] bevy_ui: Add `FromReflect` derives (#8495) # Objective A lot of items in `bevy_ui` could be `FromReflect` but aren't. This prevents users and library authors from being able to convert from a `dyn Reflect` to one of these items. ## Solution Derive `FromReflect` where possible. Also register the `ReflectFromReflect` type data. --- crates/bevy_ui/src/camera_config.rs | 5 +- crates/bevy_ui/src/focus.rs | 19 ++++-- crates/bevy_ui/src/geometry.rs | 10 ++-- crates/bevy_ui/src/ui_node.rs | 91 +++++++++++++++-------------- crates/bevy_ui/src/widget/button.rs | 6 +- crates/bevy_ui/src/widget/label.rs | 6 +- 6 files changed, 74 insertions(+), 63 deletions(-) diff --git a/crates/bevy_ui/src/camera_config.rs b/crates/bevy_ui/src/camera_config.rs index 7be35d3fd7..69ce17705a 100644 --- a/crates/bevy_ui/src/camera_config.rs +++ b/crates/bevy_ui/src/camera_config.rs @@ -2,6 +2,8 @@ use bevy_ecs::component::Component; use bevy_ecs::prelude::With; +use bevy_ecs::reflect::ReflectComponent; +use bevy_reflect::{std_traits::ReflectDefault, FromReflect, Reflect, ReflectFromReflect}; use bevy_render::camera::Camera; use bevy_render::extract_component::ExtractComponent; @@ -10,8 +12,9 @@ use bevy_render::extract_component::ExtractComponent; /// When a [`Camera`] doesn't have the [`UiCameraConfig`] component, /// it will display the UI by default. /// -#[derive(Component, Clone, ExtractComponent)] +#[derive(Component, Clone, ExtractComponent, Reflect, FromReflect)] #[extract_component_filter(With)] +#[reflect(Component, FromReflect, Default)] pub struct UiCameraConfig { /// Whether to output UI to this camera view. /// diff --git a/crates/bevy_ui/src/focus.rs b/crates/bevy_ui/src/focus.rs index 71c3a6c8fa..c73ff172b3 100644 --- a/crates/bevy_ui/src/focus.rs +++ b/crates/bevy_ui/src/focus.rs @@ -10,7 +10,9 @@ use bevy_ecs::{ }; use bevy_input::{mouse::MouseButton, touch::Touches, Input}; use bevy_math::Vec2; -use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize}; +use bevy_reflect::{ + FromReflect, Reflect, ReflectDeserialize, ReflectFromReflect, ReflectSerialize, +}; use bevy_render::{camera::NormalizedRenderTarget, prelude::Camera, view::ComputedVisibility}; use bevy_transform::components::GlobalTransform; @@ -32,8 +34,10 @@ use smallvec::SmallVec; /// /// Note that you can also control the visibility of a node using the [`Display`](crate::ui_node::Display) property, /// which fully collapses it during layout calculations. -#[derive(Component, Copy, Clone, Eq, PartialEq, Debug, Reflect, Serialize, Deserialize)] -#[reflect(Component, Serialize, Deserialize, PartialEq)] +#[derive( + Component, Copy, Clone, Eq, PartialEq, Debug, Reflect, FromReflect, Serialize, Deserialize, +)] +#[reflect(Component, FromReflect, Serialize, Deserialize, PartialEq)] pub enum Interaction { /// The node has been clicked Clicked, @@ -68,10 +72,11 @@ impl Default for Interaction { PartialEq, Debug, Reflect, + FromReflect, Serialize, Deserialize, )] -#[reflect(Component, Serialize, Deserialize, PartialEq)] +#[reflect(Component, FromReflect, Serialize, Deserialize, PartialEq)] pub struct RelativeCursorPosition { /// Cursor position relative to size and position of the Node. pub normalized: Option, @@ -87,8 +92,10 @@ impl RelativeCursorPosition { } /// Describes whether the node should block interactions with lower nodes -#[derive(Component, Copy, Clone, Eq, PartialEq, Debug, Reflect, Serialize, Deserialize)] -#[reflect(Component, Serialize, Deserialize, PartialEq)] +#[derive( + Component, Copy, Clone, Eq, PartialEq, Debug, Reflect, FromReflect, Serialize, Deserialize, +)] +#[reflect(Component, FromReflect, Serialize, Deserialize, PartialEq)] pub enum FocusPolicy { /// Blocks interaction Block, diff --git a/crates/bevy_ui/src/geometry.rs b/crates/bevy_ui/src/geometry.rs index d58509ab53..363c8acf69 100644 --- a/crates/bevy_ui/src/geometry.rs +++ b/crates/bevy_ui/src/geometry.rs @@ -1,5 +1,5 @@ use crate::Val; -use bevy_reflect::Reflect; +use bevy_reflect::{FromReflect, Reflect, ReflectFromReflect}; use std::ops::{Div, DivAssign, Mul, MulAssign}; /// A type which is commonly used to define margins, paddings and borders. @@ -46,8 +46,8 @@ use std::ops::{Div, DivAssign, Mul, MulAssign}; /// bottom: Val::Px(40.0), /// }; /// ``` -#[derive(Copy, Clone, PartialEq, Debug, Reflect)] -#[reflect(PartialEq)] +#[derive(Copy, Clone, PartialEq, Debug, Reflect, FromReflect)] +#[reflect(FromReflect, PartialEq)] pub struct UiRect { /// The value corresponding to the left side of the UI rect. pub left: Val, @@ -285,8 +285,8 @@ impl Default for UiRect { /// A 2-dimensional area defined by a width and height. /// /// It is commonly used to define the size of a text or UI element. -#[derive(Copy, Clone, PartialEq, Debug, Reflect)] -#[reflect(PartialEq)] +#[derive(Copy, Clone, PartialEq, Debug, Reflect, FromReflect)] +#[reflect(FromReflect, PartialEq)] pub struct Size { /// The width of the 2-dimensional area. pub width: Val, diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index 494a7f3460..fd551d3d36 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -3,6 +3,7 @@ use bevy_asset::Handle; use bevy_ecs::{prelude::Component, reflect::ReflectComponent}; use bevy_math::{Rect, Vec2}; use bevy_reflect::prelude::*; +use bevy_reflect::ReflectFromReflect; use bevy_render::{ color::Color, texture::{Image, DEFAULT_IMAGE_HANDLE}, @@ -62,8 +63,8 @@ impl Default for Node { /// /// This enum allows specifying values for various [`Style`] properties in different units, /// such as logical pixels, percentages, or automatically determined values. -#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)] -#[reflect(PartialEq, Serialize, Deserialize)] +#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect)] +#[reflect(FromReflect, PartialEq, Serialize, Deserialize)] pub enum Val { /// Automatically determine the value based on the context and other `Style` properties. Auto, @@ -278,8 +279,8 @@ impl Val { /// - [A Complete Guide To CSS Grid](https://css-tricks.com/snippets/css/complete-guide-grid/) by CSS Tricks. This is detailed guide with illustrations and comphrehensive written explanation of the different CSS Grid properties and how they work. /// - [CSS Grid Garden](https://cssgridgarden.com/). An interactive tutorial/game that teaches the essential parts of CSS Grid in a fun engaging way. -#[derive(Component, Clone, PartialEq, Debug, Reflect)] -#[reflect(Component, Default, PartialEq)] +#[derive(Component, Clone, PartialEq, Debug, Reflect, FromReflect)] +#[reflect(Component, FromReflect, Default, PartialEq)] pub struct Style { /// Which layout algorithm to use when laying out this node's contents: /// - [`Display::Flex`]: Use the Flexbox layout algorithm @@ -598,8 +599,8 @@ impl Default for Style { } /// How items are aligned according to the cross axis -#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] -#[reflect(PartialEq, Serialize, Deserialize)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect, FromReflect)] +#[reflect(FromReflect, PartialEq, Serialize, Deserialize)] pub enum AlignItems { /// The items are packed in their default position as if no alignment was applied Default, @@ -632,8 +633,8 @@ impl Default for AlignItems { } /// How items are aligned according to the cross axis -#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] -#[reflect(PartialEq, Serialize, Deserialize)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect, FromReflect)] +#[reflect(FromReflect, PartialEq, Serialize, Deserialize)] pub enum JustifyItems { /// The items are packed in their default position as if no alignment was applied Default, @@ -661,8 +662,8 @@ impl Default for JustifyItems { /// How this item is aligned according to the cross axis. /// Overrides [`AlignItems`]. -#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] -#[reflect(PartialEq, Serialize, Deserialize)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect, FromReflect)] +#[reflect(FromReflect, PartialEq, Serialize, Deserialize)] pub enum AlignSelf { /// Use the parent node's [`AlignItems`] value to determine how this item should be aligned. Auto, @@ -696,8 +697,8 @@ impl Default for AlignSelf { /// How this item is aligned according to the cross axis. /// Overrides [`AlignItems`]. -#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] -#[reflect(PartialEq, Serialize, Deserialize)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect, FromReflect)] +#[reflect(FromReflect, PartialEq, Serialize, Deserialize)] pub enum JustifySelf { /// Use the parent node's [`AlignItems`] value to determine how this item should be aligned. Auto, @@ -726,8 +727,8 @@ impl Default for JustifySelf { /// Defines how each line is aligned within the flexbox. /// /// It only applies if [`FlexWrap::Wrap`] is present and if there are multiple lines of items. -#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] -#[reflect(PartialEq, Serialize, Deserialize)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect, FromReflect)] +#[reflect(FromReflect, PartialEq, Serialize, Deserialize)] pub enum AlignContent { /// The items are packed in their default position as if no alignment was applied Default, @@ -765,8 +766,8 @@ impl Default for AlignContent { } /// Defines how items are aligned according to the main axis -#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] -#[reflect(PartialEq, Serialize, Deserialize)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect, FromReflect)] +#[reflect(FromReflect, PartialEq, Serialize, Deserialize)] pub enum JustifyContent { /// The items are packed in their default position as if no alignment was applied Default, @@ -801,8 +802,8 @@ impl Default for JustifyContent { /// Defines the text direction /// /// For example English is written LTR (left-to-right) while Arabic is written RTL (right-to-left). -#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] -#[reflect(PartialEq, Serialize, Deserialize)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect, FromReflect)] +#[reflect(FromReflect, PartialEq, Serialize, Deserialize)] pub enum Direction { /// Inherit from parent node. Inherit, @@ -825,8 +826,8 @@ impl Default for Direction { /// Whether to use a Flexbox layout model. /// /// Part of the [`Style`] component. -#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] -#[reflect(PartialEq, Serialize, Deserialize)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect, FromReflect)] +#[reflect(FromReflect, PartialEq, Serialize, Deserialize)] pub enum Display { /// Use Flexbox layout model to determine the position of this [`Node`]. Flex, @@ -850,8 +851,8 @@ impl Default for Display { } /// Defines how flexbox items are ordered within a flexbox -#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] -#[reflect(PartialEq, Serialize, Deserialize)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect, FromReflect)] +#[reflect(FromReflect, PartialEq, Serialize, Deserialize)] pub enum FlexDirection { /// Same way as text direction along the main axis. Row, @@ -874,8 +875,8 @@ impl Default for FlexDirection { } /// Whether to show or hide overflowing items -#[derive(Copy, Clone, PartialEq, Eq, Debug, Reflect, Serialize, Deserialize)] -#[reflect(PartialEq, Serialize, Deserialize)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Reflect, Serialize, Deserialize, FromReflect)] +#[reflect(FromReflect, PartialEq, Serialize, Deserialize)] pub struct Overflow { /// Whether to show or clip overflowing items on the x axis pub x: OverflowAxis, @@ -934,8 +935,8 @@ impl Default for Overflow { } /// Whether to show or hide overflowing items -#[derive(Copy, Clone, PartialEq, Eq, Debug, Reflect, Serialize, Deserialize)] -#[reflect(PartialEq, Serialize, Deserialize)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Reflect, FromReflect, Serialize, Deserialize)] +#[reflect(FromReflect, PartialEq, Serialize, Deserialize)] pub enum OverflowAxis { /// Show overflowing items. Visible, @@ -959,8 +960,8 @@ impl Default for OverflowAxis { } /// The strategy used to position this node -#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] -#[reflect(PartialEq, Serialize, Deserialize)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect, FromReflect)] +#[reflect(FromReflect, PartialEq, Serialize, Deserialize)] pub enum PositionType { /// Relative to all other nodes with the [`PositionType::Relative`] value. Relative, @@ -981,8 +982,8 @@ impl Default for PositionType { } /// Defines if flexbox items appear on a single line or on multiple lines -#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] -#[reflect(PartialEq, Serialize, Deserialize)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect, FromReflect)] +#[reflect(FromReflect, PartialEq, Serialize, Deserialize)] pub enum FlexWrap { /// Single line, will overflow if needed. NoWrap, @@ -1009,8 +1010,8 @@ impl Default for FlexWrap { /// Defaults to [`GridAutoFlow::Row`] /// /// -#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] -#[reflect(PartialEq, Serialize, Deserialize)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect, FromReflect)] +#[reflect(FromReflect, PartialEq, Serialize, Deserialize)] pub enum GridAutoFlow { /// Items are placed by filling each row in turn, adding new rows as necessary Row, @@ -1033,7 +1034,7 @@ impl Default for GridAutoFlow { } #[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect)] -#[reflect_value(PartialEq, Serialize, Deserialize)] +#[reflect_value(FromReflect, PartialEq, Serialize, Deserialize)] pub enum MinTrackSizingFunction { /// Track minimum size should be a fixed pixel value Px(f32), @@ -1048,7 +1049,7 @@ pub enum MinTrackSizingFunction { } #[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect)] -#[reflect_value(PartialEq, Serialize, Deserialize)] +#[reflect_value(FromReflect, PartialEq, Serialize, Deserialize)] pub enum MaxTrackSizingFunction { /// Track maximum size should be a fixed pixel value Px(f32), @@ -1073,7 +1074,7 @@ pub enum MaxTrackSizingFunction { /// A [`GridTrack`] is a Row or Column of a CSS Grid. This struct specifies what size the track should be. /// See below for the different "track sizing functions" you can specify. #[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect)] -#[reflect(PartialEq, Serialize, Deserialize)] +#[reflect(FromReflect, PartialEq, Serialize, Deserialize)] pub struct GridTrack { pub(crate) min_sizing_function: MinTrackSizingFunction, pub(crate) max_sizing_function: MaxTrackSizingFunction, @@ -1191,7 +1192,7 @@ impl Default for GridTrack { } #[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect)] -#[reflect(PartialEq, Serialize, Deserialize)] +#[reflect(FromReflect, PartialEq, Serialize, Deserialize)] /// How many times to repeat a repeated grid track /// /// @@ -1241,7 +1242,7 @@ impl From for GridTrackRepetition { /// then all track (in and outside of the repetition) must be fixed size (px or percent). Integer repetitions are just shorthand for writing out /// N tracks longhand and are not subject to the same limitations. #[derive(Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect)] -#[reflect(PartialEq, Serialize, Deserialize)] +#[reflect(FromReflect, PartialEq, Serialize, Deserialize)] pub struct RepeatedGridTrack { pub(crate) repetition: GridTrackRepetition, pub(crate) tracks: SmallVec<[GridTrack; 1]>, @@ -1390,8 +1391,8 @@ impl From for Vec { } } -#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] -#[reflect(PartialEq, Serialize, Deserialize)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect, FromReflect)] +#[reflect(FromReflect, PartialEq, Serialize, Deserialize)] /// Represents the position of a grid item in a single axis. /// /// There are 3 fields which may be set: @@ -1513,8 +1514,8 @@ impl Default for GridPlacement { /// /// This serves as the "fill" color. /// When combined with [`UiImage`], tints the provided texture. -#[derive(Component, Copy, Clone, Debug, Reflect)] -#[reflect(Component, Default)] +#[derive(Component, Copy, Clone, Debug, Reflect, FromReflect)] +#[reflect(FromReflect, Component, Default)] pub struct BackgroundColor(pub Color); impl BackgroundColor { @@ -1585,8 +1586,8 @@ impl From> for UiImage { } /// The calculated clip of the node -#[derive(Component, Default, Copy, Clone, Debug, Reflect)] -#[reflect(Component)] +#[derive(Component, Default, Copy, Clone, Debug, Reflect, FromReflect)] +#[reflect(FromReflect, Component)] pub struct CalculatedClip { /// The rect of the clip pub clip: Rect, @@ -1605,8 +1606,8 @@ pub struct CalculatedClip { /// [`ZIndex::Local(n)`] and [`ZIndex::Global(n)`] for root nodes. /// /// Nodes without this component will be treated as if they had a value of [`ZIndex::Local(0)`]. -#[derive(Component, Copy, Clone, Debug, Reflect)] -#[reflect(Component)] +#[derive(Component, Copy, Clone, Debug, Reflect, FromReflect)] +#[reflect(Component, FromReflect)] pub enum ZIndex { /// Indicates the order in which this node should be rendered relative to its siblings. Local(i32), diff --git a/crates/bevy_ui/src/widget/button.rs b/crates/bevy_ui/src/widget/button.rs index 6c7dced0f3..9e6bd94da8 100644 --- a/crates/bevy_ui/src/widget/button.rs +++ b/crates/bevy_ui/src/widget/button.rs @@ -1,9 +1,9 @@ use bevy_ecs::prelude::Component; use bevy_ecs::reflect::ReflectComponent; use bevy_reflect::std_traits::ReflectDefault; -use bevy_reflect::Reflect; +use bevy_reflect::{FromReflect, Reflect, ReflectFromReflect}; /// Marker struct for buttons -#[derive(Component, Debug, Default, Clone, Copy, Reflect)] -#[reflect(Component, Default)] +#[derive(Component, Debug, Default, Clone, Copy, Reflect, FromReflect)] +#[reflect(Component, FromReflect, Default)] pub struct Button; diff --git a/crates/bevy_ui/src/widget/label.rs b/crates/bevy_ui/src/widget/label.rs index 5b4561ac34..cf426d5803 100644 --- a/crates/bevy_ui/src/widget/label.rs +++ b/crates/bevy_ui/src/widget/label.rs @@ -1,9 +1,9 @@ use bevy_ecs::prelude::Component; use bevy_ecs::reflect::ReflectComponent; use bevy_reflect::std_traits::ReflectDefault; -use bevy_reflect::Reflect; +use bevy_reflect::{FromReflect, Reflect, ReflectFromReflect}; /// Marker struct for labels -#[derive(Component, Debug, Default, Clone, Copy, Reflect)] -#[reflect(Component, Default)] +#[derive(Component, Debug, Default, Clone, Copy, Reflect, FromReflect)] +#[reflect(Component, FromReflect, Default)] pub struct Label; From 75130bd5ecfe58693b6a6777fd5cee04b6a34489 Mon Sep 17 00:00:00 2001 From: Gino Valente <49806985+MrGVSV@users.noreply.github.com> Date: Wed, 26 Apr 2023 05:17:46 -0700 Subject: [PATCH 07/21] bevy_reflect: Better proxies (#6971) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Objective > This PR is based on discussion from #6601 The Dynamic types (e.g. `DynamicStruct`, `DynamicList`, etc.) act as both: 1. Dynamic containers which may hold any arbitrary data 2. Proxy types which may represent any other type Currently, the only way we can represent the proxy-ness of a Dynamic is by giving it a name. ```rust // This is just a dynamic container let mut data = DynamicStruct::default(); // This is a "proxy" data.set_name(std::any::type_name::()); ``` This type name is the only way we check that the given Dynamic is a proxy of some other type. When we need to "assert the type" of a `dyn Reflect`, we call `Reflect::type_name` on it. However, because we're only using a string to denote the type, we run into a few gotchas and limitations. For example, hashing a Dynamic proxy may work differently than the type it proxies: ```rust #[derive(Reflect, Hash)] #[reflect(Hash)] struct Foo(i32); let concrete = Foo(123); let dynamic = concrete.clone_dynamic(); let concrete_hash = concrete.reflect_hash(); let dynamic_hash = dynamic.reflect_hash(); // The hashes are not equal because `concrete` uses its own `Hash` impl // while `dynamic` uses a reflection-based hashing algorithm assert_ne!(concrete_hash, dynamic_hash); ``` Because the Dynamic proxy only knows about the name of the type, it's unaware of any other information about it. This means it also differs on `Reflect::reflect_partial_eq`, and may include ignored or skipped fields in places the concrete type wouldn't. ## Solution Rather than having Dynamics pass along just the type name of proxied types, we can instead have them pass around the `TypeInfo`. Now all Dynamic types contain an `Option<&'static TypeInfo>` rather than a `String`: ```diff pub struct DynamicTupleStruct { - type_name: String, + represented_type: Option<&'static TypeInfo>, fields: Vec>, } ``` By changing `Reflect::get_type_info` to `Reflect::represented_type_info`, hopefully we make this behavior a little clearer. And to account for `None` values on these dynamic types, `Reflect::represented_type_info` now returns `Option<&'static TypeInfo>`. ```rust let mut data = DynamicTupleStruct::default(); // Not proxying any specific type assert!(dyn_tuple_struct.represented_type_info().is_none()); let type_info = ::type_info(); dyn_tuple_struct.set_represented_type(Some(type_info)); // Alternatively: // let dyn_tuple_struct = foo.clone_dynamic(); // Now we're proxying `Foo` assert!(dyn_tuple_struct.represented_type_info().is_some()); ``` This means that we can have full access to all the static type information for the proxied type. Future work would include transitioning more static type information (trait impls, attributes, etc.) over to the `TypeInfo` so it can actually be utilized by Dynamic proxies. ### Alternatives & Rationale > **Note** > These alternatives were written when this PR was first made using a `Proxy` trait. This trait has since been removed.
View #### Alternative: The `Proxy` Approach I had considered adding something like a `Proxy` type where `T` would be the Dynamic and would contain the proxied type information. This was nice in that it allows us to explicitly determine whether something is a proxy or not at a type level. `Proxy` proxies a struct. Makes sense. The reason I didn't go with this approach is because (1) tuples, (2) complexity, and (3) `PartialReflect`. The `DynamicTuple` struct allows us to represent tuples at runtime. It also allows us to do something you normally can't with tuples: add new fields. Because of this, adding a field immediately invalidates the proxy (e.g. our info for `(i32, i32)` doesn't apply to `(i32, i32, NewField)`). By going with this PR's approach, we can just remove the type info on `DynamicTuple` when that happens. However, with the `Proxy` approach, it becomes difficult to represent this behavior— we'd have to completely control how we access data for `T` for each `T`. Secondly, it introduces some added complexities (aside from the manual impls for each `T`). Does `Proxy` impl `Reflect`? Likely yes, if we want to represent it as `dyn Reflect`. What `TypeInfo` do we give it? How would we forward reflection methods to the inner type (remember, we don't have specialization)? How do we separate this from Dynamic types? And finally, how do all this in a way that's both logical and intuitive for users? Lastly, introducing a `Proxy` trait rather than a `Proxy` struct is actually more inline with the [Unique Reflect RFC](https://github.com/bevyengine/rfcs/pull/56). In a way, the `Proxy` trait is really one part of the `PartialReflect` trait introduced in that RFC (it's technically not in that RFC but it fits well with it), where the `PartialReflect` serves as a way for proxies to work _like_ concrete types without having full access to everything a concrete `Reflect` type can do. This would help bridge the gap between the current state of the crate and the implementation of that RFC. All that said, this is still a viable solution. If the community believes this is the better path forward, then we can do that instead. These were just my reasons for not initially going with it in this PR. #### Alternative: The Type Registry Approach The `Proxy` trait is great and all, but how does it solve the original problem? Well, it doesn't— yet! The goal would be to start moving information from the derive macro and its attributes to the generated `TypeInfo` since these are known statically and shouldn't change. For example, adding `ignored: bool` to `[Un]NamedField` or a list of impls. However, there is another way of storing this information. This is, of course, one of the uses of the `TypeRegistry`. If we're worried about Dynamic proxies not aligning with their concrete counterparts, we could move more type information to the registry and require its usage. For example, we could replace `Reflect::reflect_hash(&self)` with `Reflect::reflect_hash(&self, registry: &TypeRegistry)`. That's not the _worst_ thing in the world, but it is an ergonomics loss. Additionally, other attributes may have their own requirements, further restricting what's possible without the registry. The `Reflect::apply` method will require the registry as well now. Why? Well because the `map_apply` function used for the `Reflect::apply` impls on `Map` types depends on `Map::insert_boxed`, which (at least for `DynamicMap`) requires `Reflect::reflect_hash`. The same would apply when adding support for reflection-based diffing, which will require `Reflect::reflect_partial_eq`. Again, this is a totally viable alternative. I just chose not to go with it for the reasons above. If we want to go with it, then we can close this PR and we can pursue this alternative instead. #### Downsides Just to highlight a quick potential downside (likely needs more investigation): retrieving the `TypeInfo` requires acquiring a lock on the `GenericTypeInfoCell` used by the `Typed` impls for generic types (non-generic types use a `OnceBox which should be faster). I am not sure how much of a performance hit that is and will need to run some benchmarks to compare against.
### Open Questions 1. Should we use `Cow<'static, TypeInfo>` instead? I think that might be easier for modding? Perhaps, in that case, we need to update `Typed::type_info` and friends as well? 2. Are the alternatives better than the approach this PR takes? Are there other alternatives? --- ## Changelog ### Changed - `Reflect::get_type_info` has been renamed to `Reflect::represented_type_info` - This method now returns `Option<&'static TypeInfo>` rather than just `&'static TypeInfo` ### Added - Added `Reflect::is_dynamic` method to indicate when a type is dynamic - Added a `set_represented_type` method on all dynamic types ### Removed - Removed `TypeInfo::Dynamic` (use `Reflect::is_dynamic` instead) - Removed `Typed` impls for all dynamic types ## Migration Guide - The Dynamic types no longer take a string type name. Instead, they require a static reference to `TypeInfo`: ```rust #[derive(Reflect)] struct MyTupleStruct(f32, f32); let mut dyn_tuple_struct = DynamicTupleStruct::default(); dyn_tuple_struct.insert(1.23_f32); dyn_tuple_struct.insert(3.21_f32); // BEFORE: let type_name = std::any::type_name::(); dyn_tuple_struct.set_name(type_name); // AFTER: let type_info = ::type_info(); dyn_tuple_struct.set_represented_type(Some(type_info)); ``` - `Reflect::get_type_info` has been renamed to `Reflect::represented_type_info` and now also returns an `Option<&'static TypeInfo>` (instead of just `&'static TypeInfo`): ```rust // BEFORE: let info: &'static TypeInfo = value.get_type_info(); // AFTER: let info: &'static TypeInfo = value.represented_type_info().unwrap(); ``` - `TypeInfo::Dynamic` and `DynamicInfo` has been removed. Use `Reflect::is_dynamic` instead: ```rust // BEFORE: if matches!(value.get_type_info(), TypeInfo::Dynamic) { // ... } // AFTER: if value.is_dynamic() { // ... } ``` --------- Co-authored-by: radiish --- benches/benches/bevy_reflect/struct.rs | 4 +- .../bevy_reflect_derive/src/impls/enums.rs | 4 +- .../bevy_reflect_derive/src/impls/structs.rs | 6 +- .../src/impls/tuple_structs.rs | 6 +- .../bevy_reflect_derive/src/impls/values.rs | 4 +- crates/bevy_reflect/src/array.rs | 58 +++++++------- crates/bevy_reflect/src/enums/dynamic_enum.rs | 77 +++++++++---------- crates/bevy_reflect/src/enums/mod.rs | 12 +-- crates/bevy_reflect/src/from_reflect.rs | 4 +- crates/bevy_reflect/src/impls/smallvec.rs | 4 +- crates/bevy_reflect/src/impls/std.rs | 26 +++---- crates/bevy_reflect/src/lib.rs | 46 +++++------ crates/bevy_reflect/src/list.rs | 58 +++++++------- crates/bevy_reflect/src/map.rs | 54 ++++++------- crates/bevy_reflect/src/reflect.rs | 27 ++++++- crates/bevy_reflect/src/serde/de.rs | 21 ++--- crates/bevy_reflect/src/serde/mod.rs | 12 +++ crates/bevy_reflect/src/serde/ser.rs | 59 ++++++-------- crates/bevy_reflect/src/struct_trait.rs | 52 +++++++------ crates/bevy_reflect/src/tuple.rs | 71 +++++++++-------- crates/bevy_reflect/src/tuple_struct.rs | 52 +++++++------ crates/bevy_reflect/src/type_info.rs | 72 ++--------------- crates/bevy_reflect/src/utility.rs | 4 +- 23 files changed, 357 insertions(+), 376 deletions(-) diff --git a/benches/benches/bevy_reflect/struct.rs b/benches/benches/bevy_reflect/struct.rs index 782d5e0b73..0495701807 100644 --- a/benches/benches/bevy_reflect/struct.rs +++ b/benches/benches/bevy_reflect/struct.rs @@ -148,14 +148,14 @@ fn concrete_struct_type_info(criterion: &mut Criterion) { BenchmarkId::new("NonGeneric", field_count), &standard, |bencher, s| { - bencher.iter(|| black_box(s.get_type_info())); + bencher.iter(|| black_box(s.get_represented_type_info())); }, ); group.bench_with_input( BenchmarkId::new("Generic", field_count), &generic, |bencher, s| { - bencher.iter(|| black_box(s.get_type_info())); + bencher.iter(|| black_box(s.get_represented_type_info())); }, ); } diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/impls/enums.rs b/crates/bevy_reflect/bevy_reflect_derive/src/impls/enums.rs index 666283615d..2f2f5cf5e3 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/impls/enums.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/impls/enums.rs @@ -192,8 +192,8 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> TokenStream { } #[inline] - fn get_type_info(&self) -> &'static #bevy_reflect_path::TypeInfo { - ::type_info() + fn get_represented_type_info(&self) -> #FQOption<&'static #bevy_reflect_path::TypeInfo> { + #FQOption::Some(::type_info()) } #[inline] diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/impls/structs.rs b/crates/bevy_reflect/bevy_reflect_derive/src/impls/structs.rs index e22634e5de..2b7fd1815c 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/impls/structs.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/impls/structs.rs @@ -151,7 +151,7 @@ pub(crate) fn impl_struct(reflect_struct: &ReflectStruct) -> TokenStream { fn clone_dynamic(&self) -> #bevy_reflect_path::DynamicStruct { let mut dynamic: #bevy_reflect_path::DynamicStruct = #FQDefault::default(); - dynamic.set_name(::std::string::ToString::to_string(#bevy_reflect_path::Reflect::type_name(self))); + dynamic.set_represented_type(#bevy_reflect_path::Reflect::get_represented_type_info(self)); #(dynamic.insert_boxed(#field_names, #bevy_reflect_path::Reflect::clone_value(&self.#field_idents));)* dynamic } @@ -164,8 +164,8 @@ pub(crate) fn impl_struct(reflect_struct: &ReflectStruct) -> TokenStream { } #[inline] - fn get_type_info(&self) -> &'static #bevy_reflect_path::TypeInfo { - ::type_info() + fn get_represented_type_info(&self) -> #FQOption<&'static #bevy_reflect_path::TypeInfo> { + #FQOption::Some(::type_info()) } #[inline] diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/impls/tuple_structs.rs b/crates/bevy_reflect/bevy_reflect_derive/src/impls/tuple_structs.rs index c41c53b86e..c74d4d9064 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/impls/tuple_structs.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/impls/tuple_structs.rs @@ -122,7 +122,7 @@ pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> TokenStream { fn clone_dynamic(&self) -> #bevy_reflect_path::DynamicTupleStruct { let mut dynamic: #bevy_reflect_path::DynamicTupleStruct = #FQDefault::default(); - dynamic.set_name(::std::string::ToString::to_string(#bevy_reflect_path::Reflect::type_name(self))); + dynamic.set_represented_type(#bevy_reflect_path::Reflect::get_represented_type_info(self)); #(dynamic.insert_boxed(#bevy_reflect_path::Reflect::clone_value(&self.#field_idents));)* dynamic } @@ -135,8 +135,8 @@ pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> TokenStream { } #[inline] - fn get_type_info(&self) -> &'static #bevy_reflect_path::TypeInfo { - ::type_info() + fn get_represented_type_info(&self) -> #FQOption<&'static #bevy_reflect_path::TypeInfo> { + #FQOption::Some(::type_info()) } #[inline] diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/impls/values.rs b/crates/bevy_reflect/bevy_reflect_derive/src/impls/values.rs index 4aa3aed418..964ef1f2ce 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/impls/values.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/impls/values.rs @@ -49,8 +49,8 @@ pub(crate) fn impl_value(meta: &ReflectMeta) -> TokenStream { } #[inline] - fn get_type_info(&self) -> &'static #bevy_reflect_path::TypeInfo { - ::type_info() + fn get_represented_type_info(&self) -> #FQOption<&'static #bevy_reflect_path::TypeInfo> { + #FQOption::Some(::type_info()) } #[inline] diff --git a/crates/bevy_reflect/src/array.rs b/crates/bevy_reflect/src/array.rs index 947601a154..0367e1add4 100644 --- a/crates/bevy_reflect/src/array.rs +++ b/crates/bevy_reflect/src/array.rs @@ -1,7 +1,4 @@ -use crate::{ - utility::{reflect_hasher, NonGenericTypeInfoCell}, - DynamicInfo, Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, Typed, -}; +use crate::{utility::reflect_hasher, Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo}; use std::{ any::{Any, TypeId}, fmt::Debug, @@ -67,7 +64,7 @@ pub trait Array: Reflect { /// Clones the list, producing a [`DynamicArray`]. fn clone_dynamic(&self) -> DynamicArray { DynamicArray { - name: self.type_name().to_string(), + represented_type: self.get_represented_type_info(), values: self.iter().map(|value| value.clone_value()).collect(), } } @@ -167,7 +164,7 @@ impl ArrayInfo { /// [`DynamicList`]: crate::DynamicList #[derive(Debug)] pub struct DynamicArray { - pub(crate) name: String, + pub(crate) represented_type: Option<&'static TypeInfo>, pub(crate) values: Box<[Box]>, } @@ -175,14 +172,14 @@ impl DynamicArray { #[inline] pub fn new(values: Box<[Box]>) -> Self { Self { - name: String::default(), + represented_type: None, values, } } pub fn from_vec(values: Vec) -> Self { Self { - name: String::default(), + represented_type: None, values: values .into_iter() .map(|field| Box::new(field) as Box) @@ -191,26 +188,37 @@ impl DynamicArray { } } - #[inline] - pub fn name(&self) -> &str { - &self.name - } + /// Sets the [type] to be represented by this `DynamicArray`. + /// + /// # Panics + /// + /// Panics if the given [type] is not a [`TypeInfo::Array`]. + /// + /// [type]: TypeInfo + pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) { + if let Some(represented_type) = represented_type { + assert!( + matches!(represented_type, TypeInfo::Array(_)), + "expected TypeInfo::Array but received: {:?}", + represented_type + ); + } - #[inline] - pub fn set_name(&mut self, name: String) { - self.name = name; + self.represented_type = represented_type; } } impl Reflect for DynamicArray { #[inline] fn type_name(&self) -> &str { - self.name.as_str() + self.represented_type + .map(|info| info.type_name()) + .unwrap_or_else(|| std::any::type_name::()) } #[inline] - fn get_type_info(&self) -> &'static TypeInfo { - ::type_info() + fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { + self.represented_type } #[inline] @@ -281,6 +289,11 @@ impl Reflect for DynamicArray { fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option { array_partial_eq(self, value) } + + #[inline] + fn is_dynamic(&self) -> bool { + true + } } impl Array for DynamicArray { @@ -312,7 +325,7 @@ impl Array for DynamicArray { #[inline] fn clone_dynamic(&self) -> DynamicArray { DynamicArray { - name: self.name.clone(), + represented_type: self.represented_type, values: self .values .iter() @@ -322,13 +335,6 @@ impl Array for DynamicArray { } } -impl Typed for DynamicArray { - fn type_info() -> &'static TypeInfo { - static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new(); - CELL.get_or_set(|| TypeInfo::Dynamic(DynamicInfo::new::())) - } -} - /// An iterator over an [`Array`]. pub struct ArrayIter<'a> { array: &'a dyn Array, diff --git a/crates/bevy_reflect/src/enums/dynamic_enum.rs b/crates/bevy_reflect/src/enums/dynamic_enum.rs index db9e050fbe..1e4cce1278 100644 --- a/crates/bevy_reflect/src/enums/dynamic_enum.rs +++ b/crates/bevy_reflect/src/enums/dynamic_enum.rs @@ -1,8 +1,6 @@ -use crate::utility::NonGenericTypeInfoCell; use crate::{ - enum_debug, enum_hash, enum_partial_eq, DynamicInfo, DynamicStruct, DynamicTuple, Enum, - Reflect, ReflectMut, ReflectOwned, ReflectRef, Struct, Tuple, TypeInfo, Typed, - VariantFieldIter, VariantType, + enum_debug, enum_hash, enum_partial_eq, DynamicStruct, DynamicTuple, Enum, Reflect, ReflectMut, + ReflectOwned, ReflectRef, Struct, Tuple, TypeInfo, VariantFieldIter, VariantType, }; use std::any::Any; use std::fmt::Formatter; @@ -58,7 +56,6 @@ impl From<()> for DynamicVariant { /// /// // Create a DynamicEnum to represent the new value /// let mut dyn_enum = DynamicEnum::new( -/// Reflect::type_name(&value), /// "None", /// DynamicVariant::Unit /// ); @@ -71,7 +68,7 @@ impl From<()> for DynamicVariant { /// ``` #[derive(Default, Debug)] pub struct DynamicEnum { - name: String, + represented_type: Option<&'static TypeInfo>, variant_name: String, variant_index: usize, variant: DynamicVariant, @@ -82,17 +79,12 @@ impl DynamicEnum { /// /// # Arguments /// - /// * `name`: The type name of the enum /// * `variant_name`: The name of the variant to set /// * `variant`: The variant data /// - pub fn new, V: Into>( - name: I, - variant_name: I, - variant: V, - ) -> Self { + pub fn new, V: Into>(variant_name: I, variant: V) -> Self { Self { - name: name.into(), + represented_type: None, variant_index: 0, variant_name: variant_name.into(), variant: variant.into(), @@ -103,33 +95,40 @@ impl DynamicEnum { /// /// # Arguments /// - /// * `name`: The type name of the enum /// * `variant_index`: The index of the variant to set /// * `variant_name`: The name of the variant to set /// * `variant`: The variant data /// pub fn new_with_index, V: Into>( - name: I, variant_index: usize, variant_name: I, variant: V, ) -> Self { Self { - name: name.into(), + represented_type: None, variant_index, variant_name: variant_name.into(), variant: variant.into(), } } - /// Returns the type name of the enum. - pub fn name(&self) -> &str { - &self.name - } + /// Sets the [type] to be represented by this `DynamicEnum`. + /// + /// # Panics + /// + /// Panics if the given [type] is not a [`TypeInfo::Enum`]. + /// + /// [type]: TypeInfo + pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) { + if let Some(represented_type) = represented_type { + assert!( + matches!(represented_type, TypeInfo::Enum(_)), + "expected TypeInfo::Enum but received: {:?}", + represented_type + ); + } - /// Sets the type name of the enum. - pub fn set_name(&mut self, name: String) { - self.name = name; + self.represented_type = represented_type; } /// Set the current enum variant represented by this struct. @@ -142,11 +141,11 @@ impl DynamicEnum { pub fn set_variant_with_index, V: Into>( &mut self, variant_index: usize, - name: I, + variant_name: I, variant: V, ) { self.variant_index = variant_index; - self.variant_name = name.into(); + self.variant_name = variant_name.into(); self.variant = variant.into(); } @@ -161,9 +160,9 @@ impl DynamicEnum { /// /// This is functionally the same as [`DynamicEnum::from`] except it takes a reference. pub fn from_ref(value: &TEnum) -> Self { - match value.variant_type() { + let type_info = value.get_represented_type_info(); + let mut dyn_enum = match value.variant_type() { VariantType::Unit => DynamicEnum::new_with_index( - value.type_name(), value.variant_index(), value.variant_name(), DynamicVariant::Unit, @@ -174,7 +173,6 @@ impl DynamicEnum { data.insert_boxed(field.value().clone_value()); } DynamicEnum::new_with_index( - value.type_name(), value.variant_index(), value.variant_name(), DynamicVariant::Tuple(data), @@ -187,13 +185,15 @@ impl DynamicEnum { data.insert_boxed(name, field.value().clone_value()); } DynamicEnum::new_with_index( - value.type_name(), value.variant_index(), value.variant_name(), DynamicVariant::Struct(data), ) } - } + }; + + dyn_enum.set_represented_type(type_info); + dyn_enum } } @@ -276,7 +276,7 @@ impl Enum for DynamicEnum { fn clone_dynamic(&self) -> DynamicEnum { Self { - name: self.name.clone(), + represented_type: self.represented_type, variant_index: self.variant_index, variant_name: self.variant_name.clone(), variant: self.variant.clone(), @@ -287,12 +287,14 @@ impl Enum for DynamicEnum { impl Reflect for DynamicEnum { #[inline] fn type_name(&self) -> &str { - &self.name + self.represented_type + .map(|info| info.type_name()) + .unwrap_or_default() } #[inline] - fn get_type_info(&self) -> &'static TypeInfo { - ::type_info() + fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { + self.represented_type } #[inline] @@ -418,10 +420,3 @@ impl Reflect for DynamicEnum { write!(f, ")") } } - -impl Typed for DynamicEnum { - fn type_info() -> &'static TypeInfo { - static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new(); - CELL.get_or_set(|| TypeInfo::Dynamic(DynamicInfo::new::())) - } -} diff --git a/crates/bevy_reflect/src/enums/mod.rs b/crates/bevy_reflect/src/enums/mod.rs index e8c32e73ef..7693bf9794 100644 --- a/crates/bevy_reflect/src/enums/mod.rs +++ b/crates/bevy_reflect/src/enums/mod.rs @@ -342,14 +342,14 @@ mod tests { // === Tuple === // let mut data = DynamicTuple::default(); data.insert(1.23_f32); - let dyn_enum = DynamicEnum::new(std::any::type_name::>(), "B", data); + let dyn_enum = DynamicEnum::new("B", data); value.apply(&dyn_enum); assert_eq!(TestEnum::B(1.23), value); // === Struct === // let mut data = DynamicStruct::default(); data.insert("value", 1.23_f32); - let dyn_enum = DynamicEnum::new(std::any::type_name::>(), "C", data); + let dyn_enum = DynamicEnum::new("C", data); value.apply(&dyn_enum); assert_eq!(TestEnum::C { value: 1.23 }, value); } @@ -371,14 +371,14 @@ mod tests { // === Tuple === // let mut data = DynamicTuple::default(); data.insert(TestStruct(123)); - let dyn_enum = DynamicEnum::new(std::any::type_name::(), "B", data); + let dyn_enum = DynamicEnum::new("B", data); value.apply(&dyn_enum); assert_eq!(TestEnum::B(TestStruct(123)), value); // === Struct === // let mut data = DynamicStruct::default(); data.insert("value", TestStruct(123)); - let dyn_enum = DynamicEnum::new(std::any::type_name::(), "C", data); + let dyn_enum = DynamicEnum::new("C", data); value.apply(&dyn_enum); assert_eq!( TestEnum::C { @@ -409,14 +409,14 @@ mod tests { // === Tuple === // let mut data = DynamicTuple::default(); data.insert(OtherEnum::B(123)); - let dyn_enum = DynamicEnum::new(std::any::type_name::(), "B", data); + let dyn_enum = DynamicEnum::new("B", data); value.apply(&dyn_enum); assert_eq!(TestEnum::B(OtherEnum::B(123)), value); // === Struct === // let mut data = DynamicStruct::default(); data.insert("value", OtherEnum::C { value: 1.23 }); - let dyn_enum = DynamicEnum::new(std::any::type_name::(), "C", data); + let dyn_enum = DynamicEnum::new("C", data); value.apply(&dyn_enum); assert_eq!( TestEnum::C { diff --git a/crates/bevy_reflect/src/from_reflect.rs b/crates/bevy_reflect/src/from_reflect.rs index 4d98698398..f4abb65d7e 100644 --- a/crates/bevy_reflect/src/from_reflect.rs +++ b/crates/bevy_reflect/src/from_reflect.rs @@ -75,7 +75,7 @@ pub trait FromReflect: Reflect + Sized { /// # Example /// /// ``` -/// # use bevy_reflect::{DynamicTupleStruct, FromReflect, Reflect, ReflectFromReflect, TypeRegistry}; +/// # use bevy_reflect::{DynamicTupleStruct, FromReflect, Reflect, ReflectFromReflect, Typed, TypeRegistry}; /// # #[derive(Reflect, FromReflect, PartialEq, Eq, Debug)] /// # #[reflect(FromReflect)] /// # struct Foo(#[reflect(default = "default_value")] usize); @@ -84,7 +84,7 @@ pub trait FromReflect: Reflect + Sized { /// # registry.register::(); /// /// let mut reflected = DynamicTupleStruct::default(); -/// reflected.set_name(std::any::type_name::().to_string()); +/// reflected.set_represented_type(Some(::type_info())); /// /// let registration = registry.get_with_name(reflected.type_name()).unwrap(); /// let rfr = registration.data::().unwrap(); diff --git a/crates/bevy_reflect/src/impls/smallvec.rs b/crates/bevy_reflect/src/impls/smallvec.rs index 769c541d9d..918dc849b6 100644 --- a/crates/bevy_reflect/src/impls/smallvec.rs +++ b/crates/bevy_reflect/src/impls/smallvec.rs @@ -82,8 +82,8 @@ where std::any::type_name::() } - fn get_type_info(&self) -> &'static TypeInfo { - ::type_info() + fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { + Some(::type_info()) } fn into_any(self: Box) -> Box { diff --git a/crates/bevy_reflect/src/impls/std.rs b/crates/bevy_reflect/src/impls/std.rs index 0b42a70793..db8baa3d9d 100644 --- a/crates/bevy_reflect/src/impls/std.rs +++ b/crates/bevy_reflect/src/impls/std.rs @@ -244,8 +244,8 @@ macro_rules! impl_reflect_for_veclike { std::any::type_name::() } - fn get_type_info(&self) -> &'static TypeInfo { - ::type_info() + fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { + Some(::type_info()) } fn into_any(self: Box) -> Box { @@ -397,7 +397,7 @@ macro_rules! impl_reflect_for_hashmap { fn clone_dynamic(&self) -> DynamicMap { let mut dynamic_map = DynamicMap::default(); - dynamic_map.set_name(self.type_name().to_string()); + dynamic_map.set_represented_type(self.get_represented_type_info()); for (k, v) in self { let key = K::from_reflect(k).unwrap_or_else(|| { panic!("Attempted to clone invalid key of type {}.", k.type_name()) @@ -450,8 +450,8 @@ macro_rules! impl_reflect_for_hashmap { std::any::type_name::() } - fn get_type_info(&self) -> &'static TypeInfo { - ::type_info() + fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { + Some(::type_info()) } fn into_any(self: Box) -> Box { @@ -595,8 +595,8 @@ impl Reflect for [T; N] { std::any::type_name::() } - fn get_type_info(&self) -> &'static TypeInfo { - ::type_info() + fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { + Some(::type_info()) } #[inline] @@ -800,8 +800,8 @@ impl Reflect for Option { } #[inline] - fn get_type_info(&self) -> &'static TypeInfo { - ::type_info() + fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { + Some(::type_info()) } #[inline] @@ -965,8 +965,8 @@ impl Reflect for Cow<'static, str> { std::any::type_name::() } - fn get_type_info(&self) -> &'static TypeInfo { - ::type_info() + fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { + Some(::type_info()) } fn into_any(self: Box) -> Box { @@ -1073,8 +1073,8 @@ impl Reflect for &'static Path { std::any::type_name::() } - fn get_type_info(&self) -> &'static TypeInfo { - ::type_info() + fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { + Some(::type_info()) } fn into_any(self: Box) -> Box { diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index 571fce022a..a2ef6d4af6 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -169,7 +169,7 @@ //! ``` //! # use bevy_reflect::{DynamicEnum, Reflect}; //! let mut value = Some(123_i32); -//! let patch = DynamicEnum::new(std::any::type_name::>(), "None", ()); +//! let patch = DynamicEnum::new("None", ()); //! value.apply(&patch); //! assert_eq!(None, value); //! ``` @@ -1100,7 +1100,7 @@ mod tests { // TypeInfo (instance) let value: &dyn Reflect = &123_i32; - let info = value.get_type_info(); + let info = value.get_represented_type_info().unwrap(); assert!(info.is::()); // Struct @@ -1133,7 +1133,7 @@ mod tests { } let value: &dyn Reflect = &MyStruct { foo: 123, bar: 321 }; - let info = value.get_type_info(); + let info = value.get_represented_type_info().unwrap(); assert!(info.is::()); // Struct (generic) @@ -1167,7 +1167,7 @@ mod tests { foo: String::from("Hello!"), bar: 321, }; - let info = value.get_type_info(); + let info = value.get_represented_type_info().unwrap(); assert!(info.is::>()); // Tuple Struct @@ -1203,7 +1203,7 @@ mod tests { } let value: &dyn Reflect = &(123_u32, 1.23_f32, String::from("Hello!")); - let info = value.get_type_info(); + let info = value.get_represented_type_info().unwrap(); assert!(info.is::()); // List @@ -1220,7 +1220,7 @@ mod tests { } let value: &dyn Reflect = &vec![123_usize]; - let info = value.get_type_info(); + let info = value.get_represented_type_info().unwrap(); assert!(info.is::()); // List (SmallVec) @@ -1240,7 +1240,7 @@ mod tests { let value: MySmallVec = smallvec::smallvec![String::default(); 2]; let value: &dyn Reflect = &value; - let info = value.get_type_info(); + let info = value.get_represented_type_info().unwrap(); assert!(info.is::()); } @@ -1259,7 +1259,7 @@ mod tests { } let value: &dyn Reflect = &[1usize, 2usize, 3usize]; - let info = value.get_type_info(); + let info = value.get_represented_type_info().unwrap(); assert!(info.is::()); // Map @@ -1278,7 +1278,7 @@ mod tests { } let value: &dyn Reflect = &MyMap::new(); - let info = value.get_type_info(); + let info = value.get_represented_type_info().unwrap(); assert!(info.is::()); // Value @@ -1293,23 +1293,23 @@ mod tests { } let value: &dyn Reflect = &String::from("Hello!"); - let info = value.get_type_info(); + let info = value.get_represented_type_info().unwrap(); assert!(info.is::()); + } - // Dynamic - type MyDynamic = DynamicList; + #[test] + fn should_permit_valid_represented_type_for_dynamic() { + let type_info = <[i32; 2] as Typed>::type_info(); + let mut dynamic_array = [123; 2].clone_dynamic(); + dynamic_array.set_represented_type(Some(type_info)); + } - let info = MyDynamic::type_info(); - if let TypeInfo::Dynamic(info) = info { - assert!(info.is::()); - assert_eq!(std::any::type_name::(), info.type_name()); - } else { - panic!("Expected `TypeInfo::Dynamic`"); - } - - let value: &dyn Reflect = &DynamicList::default(); - let info = value.get_type_info(); - assert!(info.is::()); + #[test] + #[should_panic(expected = "expected TypeInfo::Array but received")] + fn should_prohibit_invalid_represented_type_for_dynamic() { + let type_info = <(i32, i32) as Typed>::type_info(); + let mut dynamic_array = [123; 2].clone_dynamic(); + dynamic_array.set_represented_type(Some(type_info)); } #[cfg(feature = "documentation")] diff --git a/crates/bevy_reflect/src/list.rs b/crates/bevy_reflect/src/list.rs index d13e7776f0..6b17527302 100644 --- a/crates/bevy_reflect/src/list.rs +++ b/crates/bevy_reflect/src/list.rs @@ -2,10 +2,8 @@ use std::any::{Any, TypeId}; use std::fmt::{Debug, Formatter}; use std::hash::{Hash, Hasher}; -use crate::utility::{reflect_hasher, NonGenericTypeInfoCell}; -use crate::{ - DynamicInfo, FromReflect, Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, Typed, -}; +use crate::utility::reflect_hasher; +use crate::{FromReflect, Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo}; /// A trait used to power [list-like] operations via [reflection]. /// @@ -97,7 +95,7 @@ pub trait List: Reflect { /// Clones the list, producing a [`DynamicList`]. fn clone_dynamic(&self) -> DynamicList { DynamicList { - name: self.type_name().to_string(), + represented_type: self.get_represented_type_info(), values: self.iter().map(|value| value.clone_value()).collect(), } } @@ -177,25 +175,27 @@ impl ListInfo { /// A list of reflected values. #[derive(Default)] pub struct DynamicList { - name: String, + represented_type: Option<&'static TypeInfo>, values: Vec>, } impl DynamicList { - /// Returns the type name of the list. + /// Sets the [type] to be represented by this `DynamicList`. + /// # Panics /// - /// The value returned by this method is the same value returned by - /// [`Reflect::type_name`]. - pub fn name(&self) -> &str { - &self.name - } + /// Panics if the given [type] is not a [`TypeInfo::List`]. + /// + /// [type]: TypeInfo + pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) { + if let Some(represented_type) = represented_type { + assert!( + matches!(represented_type, TypeInfo::List(_)), + "expected TypeInfo::List but received: {:?}", + represented_type + ); + } - /// Sets the type name of the list. - /// - /// The value set by this method is the value returned by - /// [`Reflect::type_name`]. - pub fn set_name(&mut self, name: String) { - self.name = name; + self.represented_type = represented_type; } /// Appends a typed value to the list. @@ -248,7 +248,7 @@ impl List for DynamicList { fn clone_dynamic(&self) -> DynamicList { DynamicList { - name: self.name.clone(), + represented_type: self.represented_type, values: self .values .iter() @@ -261,12 +261,14 @@ impl List for DynamicList { impl Reflect for DynamicList { #[inline] fn type_name(&self) -> &str { - self.name.as_str() + self.represented_type + .map(|info| info.type_name()) + .unwrap_or_else(|| std::any::type_name::()) } #[inline] - fn get_type_info(&self) -> &'static TypeInfo { - ::type_info() + fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { + self.represented_type } #[inline] @@ -343,6 +345,11 @@ impl Reflect for DynamicList { list_debug(self, f)?; write!(f, ")") } + + #[inline] + fn is_dynamic(&self) -> bool { + true + } } impl Debug for DynamicList { @@ -351,13 +358,6 @@ impl Debug for DynamicList { } } -impl Typed for DynamicList { - fn type_info() -> &'static TypeInfo { - static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new(); - CELL.get_or_set(|| TypeInfo::Dynamic(DynamicInfo::new::())) - } -} - impl IntoIterator for DynamicList { type Item = Box; type IntoIter = std::vec::IntoIter; diff --git a/crates/bevy_reflect/src/map.rs b/crates/bevy_reflect/src/map.rs index 8dcd28386a..6e997ffd32 100644 --- a/crates/bevy_reflect/src/map.rs +++ b/crates/bevy_reflect/src/map.rs @@ -4,8 +4,7 @@ use std::hash::Hash; use bevy_utils::{Entry, HashMap}; -use crate::utility::NonGenericTypeInfoCell; -use crate::{DynamicInfo, Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, Typed}; +use crate::{Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo}; /// A trait used to power [map-like] operations via [reflection]. /// @@ -184,26 +183,29 @@ const HASH_ERROR: &str = "the given key does not support hashing"; /// An ordered mapping between reflected values. #[derive(Default)] pub struct DynamicMap { - name: String, + represented_type: Option<&'static TypeInfo>, values: Vec<(Box, Box)>, indices: HashMap, } impl DynamicMap { - /// Returns the type name of the map. + /// Sets the [type] to be represented by this `DynamicMap`. /// - /// The value returned by this method is the same value returned by - /// [`Reflect::type_name`]. - pub fn name(&self) -> &str { - &self.name - } + /// # Panics + /// + /// Panics if the given [type] is not a [`TypeInfo::Map`]. + /// + /// [type]: TypeInfo + pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) { + if let Some(represented_type) = represented_type { + assert!( + matches!(represented_type, TypeInfo::Map(_)), + "expected TypeInfo::Map but received: {:?}", + represented_type + ); + } - /// Sets the type name of the map. - /// - /// The value set by this method is the same value returned by - /// [`Reflect::type_name`]. - pub fn set_name(&mut self, name: String) { - self.name = name; + self.represented_type = represented_type; } /// Inserts a typed key-value pair into the map. @@ -232,7 +234,7 @@ impl Map for DynamicMap { fn clone_dynamic(&self) -> DynamicMap { DynamicMap { - name: self.name.clone(), + represented_type: self.represented_type, values: self .values .iter() @@ -289,12 +291,14 @@ impl Map for DynamicMap { impl Reflect for DynamicMap { fn type_name(&self) -> &str { - &self.name + self.represented_type + .map(|info| info.type_name()) + .unwrap_or_else(|| std::any::type_name::()) } #[inline] - fn get_type_info(&self) -> &'static TypeInfo { - ::type_info() + fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { + self.represented_type } fn into_any(self: Box) -> Box { @@ -358,6 +362,11 @@ impl Reflect for DynamicMap { map_debug(self, f)?; write!(f, ")") } + + #[inline] + fn is_dynamic(&self) -> bool { + true + } } impl Debug for DynamicMap { @@ -366,13 +375,6 @@ impl Debug for DynamicMap { } } -impl Typed for DynamicMap { - fn type_info() -> &'static TypeInfo { - static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new(); - CELL.get_or_set(|| TypeInfo::Dynamic(DynamicInfo::new::())) - } -} - /// An iterator over the key-value pairs of a [`Map`]. pub struct MapIter<'a> { pub(crate) map: &'a dyn Map, diff --git a/crates/bevy_reflect/src/reflect.rs b/crates/bevy_reflect/src/reflect.rs index 8abfeef742..c0749f5067 100644 --- a/crates/bevy_reflect/src/reflect.rs +++ b/crates/bevy_reflect/src/reflect.rs @@ -76,15 +76,22 @@ pub trait Reflect: Any + Send + Sync { /// Returns the [type name][std::any::type_name] of the underlying type. fn type_name(&self) -> &str; - /// Returns the [`TypeInfo`] of the underlying type. + /// Returns the [`TypeInfo`] of the type _represented_ by this value. + /// + /// For most types, this will simply return their own `TypeInfo`. + /// However, for dynamic types, such as [`DynamicStruct`] or [`DynamicList`], + /// this will return the type they represent + /// (or `None` if they don't represent any particular type). /// /// This method is great if you have an instance of a type or a `dyn Reflect`, /// and want to access its [`TypeInfo`]. However, if this method is to be called /// frequently, consider using [`TypeRegistry::get_type_info`] as it can be more /// performant for such use cases. /// + /// [`DynamicStruct`]: crate::DynamicStruct + /// [`DynamicList`]: crate::DynamicList /// [`TypeRegistry::get_type_info`]: crate::TypeRegistry::get_type_info - fn get_type_info(&self) -> &'static TypeInfo; + fn get_represented_type_info(&self) -> Option<&'static TypeInfo>; /// Returns the value as a [`Box`][std::any::Any]. fn into_any(self: Box) -> Box; @@ -216,6 +223,22 @@ pub trait Reflect: Any + Send + Sync { fn serializable(&self) -> Option { None } + + /// Indicates whether or not this type is a _dynamic_ type. + /// + /// Dynamic types include the ones built-in to this [crate], + /// such as [`DynamicStruct`], [`DynamicList`], and [`DynamicTuple`]. + /// However, they may be custom types used as proxies for other types + /// or to facilitate scripting capabilities. + /// + /// By default, this method will return `false`. + /// + /// [`DynamicStruct`]: crate::DynamicStruct + /// [`DynamicList`]: crate::DynamicList + /// [`DynamicTuple`]: crate::DynamicTuple + fn is_dynamic(&self) -> bool { + false + } } impl Debug for dyn Reflect { diff --git a/crates/bevy_reflect/src/serde/de.rs b/crates/bevy_reflect/src/serde/de.rs index 60d3b0aa20..de7c474381 100644 --- a/crates/bevy_reflect/src/serde/de.rs +++ b/crates/bevy_reflect/src/serde/de.rs @@ -389,7 +389,7 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> { registry: self.registry, }, )?; - dynamic_struct.set_name(struct_info.type_name().to_string()); + dynamic_struct.set_represented_type(Some(self.registration.type_info())); Ok(Box::new(dynamic_struct)) } TypeInfo::TupleStruct(tuple_struct_info) => { @@ -402,7 +402,7 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> { registration: self.registration, }, )?; - dynamic_tuple_struct.set_name(tuple_struct_info.type_name().to_string()); + dynamic_tuple_struct.set_represented_type(Some(self.registration.type_info())); Ok(Box::new(dynamic_tuple_struct)) } TypeInfo::List(list_info) => { @@ -410,7 +410,7 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> { list_info, registry: self.registry, })?; - dynamic_list.set_name(list_info.type_name().to_string()); + dynamic_list.set_represented_type(Some(self.registration.type_info())); Ok(Box::new(dynamic_list)) } TypeInfo::Array(array_info) => { @@ -421,7 +421,7 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> { registry: self.registry, }, )?; - dynamic_array.set_name(array_info.type_name().to_string()); + dynamic_array.set_represented_type(Some(self.registration.type_info())); Ok(Box::new(dynamic_array)) } TypeInfo::Map(map_info) => { @@ -429,7 +429,7 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> { map_info, registry: self.registry, })?; - dynamic_map.set_name(map_info.type_name().to_string()); + dynamic_map.set_represented_type(Some(self.registration.type_info())); Ok(Box::new(dynamic_map)) } TypeInfo::Tuple(tuple_info) => { @@ -440,7 +440,7 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> { registry: self.registry, }, )?; - dynamic_tuple.set_name(tuple_info.type_name().to_string()); + dynamic_tuple.set_represented_type(Some(self.registration.type_info())); Ok(Box::new(dynamic_tuple)) } TypeInfo::Enum(enum_info) => { @@ -461,7 +461,7 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> { }, )? }; - dynamic_enum.set_name(type_name.to_string()); + dynamic_enum.set_represented_type(Some(self.registration.type_info())); Ok(Box::new(dynamic_enum)) } TypeInfo::Value(_) => { @@ -470,13 +470,6 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> { "the TypeRegistration for {type_name} doesn't have ReflectDeserialize", ))) } - TypeInfo::Dynamic(_) => { - // We could potentially allow this but we'd have no idea what the actual types of the - // fields are and would rely on the deserializer to determine them (e.g. `i32` vs `i64`) - Err(de::Error::custom(format_args!( - "cannot deserialize arbitrary dynamic type {type_name}", - ))) - } } } } diff --git a/crates/bevy_reflect/src/serde/mod.rs b/crates/bevy_reflect/src/serde/mod.rs index 3355ed38d0..58231b2654 100644 --- a/crates/bevy_reflect/src/serde/mod.rs +++ b/crates/bevy_reflect/src/serde/mod.rs @@ -92,4 +92,16 @@ mod tests { "Expected {expected:?} found {deserialized:?}" ); } + + #[test] + #[should_panic(expected = "cannot get type info for bevy_reflect::struct_trait::DynamicStruct")] + fn unproxied_dynamic_should_not_serialize() { + let registry = TypeRegistry::default(); + + let mut value = DynamicStruct::default(); + value.insert("foo", 123_u32); + + let serializer = ReflectSerializer::new(&value, ®istry); + ron::ser::to_string(&serializer).unwrap(); + } } diff --git a/crates/bevy_reflect/src/serde/ser.rs b/crates/bevy_reflect/src/serde/ser.rs index e9e4abe1d8..38d4529a3a 100644 --- a/crates/bevy_reflect/src/serde/ser.rs +++ b/crates/bevy_reflect/src/serde/ser.rs @@ -43,26 +43,6 @@ fn get_serializable<'a, E: serde::ser::Error>( Ok(reflect_serialize.get_serializable(reflect_value)) } -/// Get the underlying [`TypeInfo`] of a given type. -/// -/// If the given type is a [`TypeInfo::Dynamic`] then we need to try and look -/// up the actual type in the registry. -fn get_type_info( - type_info: &'static TypeInfo, - type_name: &str, - registry: &TypeRegistry, -) -> Result<&'static TypeInfo, E> { - match type_info { - TypeInfo::Dynamic(..) => match registry.get_with_name(type_name) { - Some(registration) => Ok(registration.type_info()), - None => Err(Error::custom(format_args!( - "no registration found for dynamic type with name {type_name}", - ))), - }, - info => Ok(info), - } -} - /// A general purpose serializer for reflected types. /// /// The serialized data will take the form of a map containing the following entries: @@ -186,11 +166,15 @@ impl<'a> Serialize for StructSerializer<'a> { where S: serde::Serializer, { - let type_info = get_type_info( - self.struct_value.get_type_info(), - self.struct_value.type_name(), - self.registry, - )?; + let type_info = self + .struct_value + .get_represented_type_info() + .ok_or_else(|| { + Error::custom(format_args!( + "cannot get type info for {}", + self.struct_value.type_name() + )) + })?; let struct_info = match type_info { TypeInfo::Struct(struct_info) => struct_info, @@ -235,11 +219,15 @@ impl<'a> Serialize for TupleStructSerializer<'a> { where S: serde::Serializer, { - let type_info = get_type_info( - self.tuple_struct.get_type_info(), - self.tuple_struct.type_name(), - self.registry, - )?; + let type_info = self + .tuple_struct + .get_represented_type_info() + .ok_or_else(|| { + Error::custom(format_args!( + "cannot get type info for {}", + self.tuple_struct.type_name() + )) + })?; let tuple_struct_info = match type_info { TypeInfo::TupleStruct(tuple_struct_info) => tuple_struct_info, @@ -283,11 +271,12 @@ impl<'a> Serialize for EnumSerializer<'a> { where S: serde::Serializer, { - let type_info = get_type_info( - self.enum_value.get_type_info(), - self.enum_value.type_name(), - self.registry, - )?; + let type_info = self.enum_value.get_represented_type_info().ok_or_else(|| { + Error::custom(format_args!( + "cannot get type info for {}", + self.enum_value.type_name() + )) + })?; let enum_info = match type_info { TypeInfo::Enum(enum_info) => enum_info, diff --git a/crates/bevy_reflect/src/struct_trait.rs b/crates/bevy_reflect/src/struct_trait.rs index ab146d1b36..ede4ddec4d 100644 --- a/crates/bevy_reflect/src/struct_trait.rs +++ b/crates/bevy_reflect/src/struct_trait.rs @@ -1,7 +1,4 @@ -use crate::utility::NonGenericTypeInfoCell; -use crate::{ - DynamicInfo, NamedField, Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, Typed, -}; +use crate::{NamedField, Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo}; use bevy_utils::{Entry, HashMap}; use std::fmt::{Debug, Formatter}; use std::{ @@ -272,21 +269,30 @@ impl GetField for dyn Struct { /// A struct type which allows fields to be added at runtime. #[derive(Default)] pub struct DynamicStruct { - name: String, + represented_type: Option<&'static TypeInfo>, fields: Vec>, field_names: Vec>, field_indices: HashMap, usize>, } impl DynamicStruct { - /// Returns the type name of the struct. - pub fn name(&self) -> &str { - &self.name - } + /// Sets the [type] to be represented by this `DynamicStruct`. + /// + /// # Panics + /// + /// Panics if the given [type] is not a [`TypeInfo::Struct`]. + /// + /// [type]: TypeInfo + pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) { + if let Some(represented_type) = represented_type { + assert!( + matches!(represented_type, TypeInfo::Struct(_)), + "expected TypeInfo::Struct but received: {:?}", + represented_type + ); + } - /// Sets the type name of the struct. - pub fn set_name(&mut self, name: String) { - self.name = name; + self.represented_type = represented_type; } /// Inserts a field named `name` with value `value` into the struct. @@ -370,7 +376,7 @@ impl Struct for DynamicStruct { fn clone_dynamic(&self) -> DynamicStruct { DynamicStruct { - name: self.name.clone(), + represented_type: self.get_represented_type_info(), field_names: self.field_names.clone(), field_indices: self.field_indices.clone(), fields: self @@ -385,12 +391,14 @@ impl Struct for DynamicStruct { impl Reflect for DynamicStruct { #[inline] fn type_name(&self) -> &str { - &self.name + self.represented_type + .map(|info| info.type_name()) + .unwrap_or_else(|| std::any::type_name::()) } #[inline] - fn get_type_info(&self) -> &'static TypeInfo { - ::type_info() + fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { + self.represented_type } #[inline] @@ -470,6 +478,11 @@ impl Reflect for DynamicStruct { struct_debug(self, f)?; write!(f, ")") } + + #[inline] + fn is_dynamic(&self) -> bool { + true + } } impl Debug for DynamicStruct { @@ -478,13 +491,6 @@ impl Debug for DynamicStruct { } } -impl Typed for DynamicStruct { - fn type_info() -> &'static TypeInfo { - static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new(); - CELL.get_or_set(|| TypeInfo::Dynamic(DynamicInfo::new::())) - } -} - /// Compares a [`Struct`] with a [`Reflect`] value. /// /// Returns true if and only if all of the following are true: diff --git a/crates/bevy_reflect/src/tuple.rs b/crates/bevy_reflect/src/tuple.rs index f0e20aff6b..8f0340bcbb 100644 --- a/crates/bevy_reflect/src/tuple.rs +++ b/crates/bevy_reflect/src/tuple.rs @@ -1,9 +1,9 @@ -use crate::utility::NonGenericTypeInfoCell; use crate::{ - DynamicInfo, FromReflect, GetTypeRegistration, Reflect, ReflectMut, ReflectOwned, ReflectRef, - TypeInfo, TypeRegistration, Typed, UnnamedField, + FromReflect, GetTypeRegistration, Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, + TypeRegistration, Typed, UnnamedField, }; use std::any::{Any, TypeId}; +use std::borrow::Cow; use std::fmt::{Debug, Formatter}; use std::slice::Iter; @@ -207,39 +207,48 @@ impl TupleInfo { /// A tuple which allows fields to be added at runtime. #[derive(Default, Debug)] pub struct DynamicTuple { - name: String, + name: Cow<'static, str>, + represented_type: Option<&'static TypeInfo>, fields: Vec>, } impl DynamicTuple { - /// Returns the type name of the tuple. + /// Sets the [type] to be represented by this `DynamicTuple`. /// - /// The tuple's name is automatically generated from its element types. - pub fn name(&self) -> &str { - &self.name - } + /// # Panics + /// + /// Panics if the given [type] is not a [`TypeInfo::Tuple`]. + /// + /// [type]: TypeInfo + pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) { + if let Some(represented_type) = represented_type { + assert!( + matches!(represented_type, TypeInfo::Tuple(_)), + "expected TypeInfo::Tuple but received: {:?}", + represented_type + ); - /// Manually sets the type name of the tuple. - /// - /// Note that the tuple name will be overwritten when elements are added. - pub fn set_name(&mut self, name: String) { - self.name = name; + self.name = Cow::Borrowed(represented_type.type_name()); + } + self.represented_type = represented_type; } /// Appends an element with value `value` to the tuple. pub fn insert_boxed(&mut self, value: Box) { + self.represented_type = None; self.fields.push(value); self.generate_name(); } /// Appends a typed element with value `value` to the tuple. pub fn insert(&mut self, value: T) { + self.represented_type = None; self.insert_boxed(Box::new(value)); self.generate_name(); } fn generate_name(&mut self) { - let name = &mut self.name; + let mut name = self.name.to_string(); name.clear(); name.push('('); for (i, field) in self.fields.iter().enumerate() { @@ -249,6 +258,7 @@ impl DynamicTuple { name.push_str(field.type_name()); } name.push(')'); + self.name = Cow::Owned(name); } } @@ -285,6 +295,7 @@ impl Tuple for DynamicTuple { fn clone_dynamic(&self) -> DynamicTuple { DynamicTuple { name: self.name.clone(), + represented_type: self.represented_type, fields: self .fields .iter() @@ -297,12 +308,14 @@ impl Tuple for DynamicTuple { impl Reflect for DynamicTuple { #[inline] fn type_name(&self) -> &str { - self.name() + self.represented_type + .map(|info| info.type_name()) + .unwrap_or_else(|| &self.name) } #[inline] - fn get_type_info(&self) -> &'static TypeInfo { - ::type_info() + fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { + self.represented_type } #[inline] @@ -373,12 +386,10 @@ impl Reflect for DynamicTuple { tuple_debug(self, f)?; write!(f, ")") } -} -impl Typed for DynamicTuple { - fn type_info() -> &'static TypeInfo { - static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new(); - CELL.get_or_set(|| TypeInfo::Dynamic(DynamicInfo::new::())) + #[inline] + fn is_dynamic(&self) -> bool { + true } } @@ -496,15 +507,15 @@ macro_rules! impl_reflect_tuple { #[inline] fn clone_dynamic(&self) -> DynamicTuple { - let mut dyn_tuple = DynamicTuple { - name: String::default(), + let info = self.get_represented_type_info(); + DynamicTuple { + name: Cow::Borrowed(::core::any::type_name::()), + represented_type: info, fields: self .iter_fields() .map(|value| value.clone_value()) .collect(), - }; - dyn_tuple.generate_name(); - dyn_tuple + } } } @@ -513,8 +524,8 @@ macro_rules! impl_reflect_tuple { std::any::type_name::() } - fn get_type_info(&self) -> &'static TypeInfo { - ::type_info() + fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { + Some(::type_info()) } fn into_any(self: Box) -> Box { diff --git a/crates/bevy_reflect/src/tuple_struct.rs b/crates/bevy_reflect/src/tuple_struct.rs index 33edd7bb17..9b7466d575 100644 --- a/crates/bevy_reflect/src/tuple_struct.rs +++ b/crates/bevy_reflect/src/tuple_struct.rs @@ -1,7 +1,4 @@ -use crate::utility::NonGenericTypeInfoCell; -use crate::{ - DynamicInfo, Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, Typed, UnnamedField, -}; +use crate::{Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, UnnamedField}; use std::any::{Any, TypeId}; use std::fmt::{Debug, Formatter}; use std::slice::Iter; @@ -222,19 +219,28 @@ impl GetTupleStructField for dyn TupleStruct { /// A tuple struct which allows fields to be added at runtime. #[derive(Default)] pub struct DynamicTupleStruct { - name: String, + represented_type: Option<&'static TypeInfo>, fields: Vec>, } impl DynamicTupleStruct { - /// Returns the type name of the tuple struct. - pub fn name(&self) -> &str { - &self.name - } + /// Sets the [type] to be represented by this `DynamicTupleStruct`. + /// + /// # Panics + /// + /// Panics if the given [type] is not a [`TypeInfo::TupleStruct`]. + /// + /// [type]: TypeInfo + pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) { + if let Some(represented_type) = represented_type { + assert!( + matches!(represented_type, TypeInfo::TupleStruct(_)), + "expected TypeInfo::TupleStruct but received: {:?}", + represented_type + ); + } - /// Sets the type name of the tuple struct. - pub fn set_name(&mut self, name: String) { - self.name = name; + self.represented_type = represented_type; } /// Appends an element with value `value` to the tuple struct. @@ -274,7 +280,7 @@ impl TupleStruct for DynamicTupleStruct { fn clone_dynamic(&self) -> DynamicTupleStruct { DynamicTupleStruct { - name: self.name.clone(), + represented_type: self.represented_type, fields: self .fields .iter() @@ -287,12 +293,14 @@ impl TupleStruct for DynamicTupleStruct { impl Reflect for DynamicTupleStruct { #[inline] fn type_name(&self) -> &str { - self.name.as_str() + self.represented_type + .map(|info| info.type_name()) + .unwrap_or_else(|| std::any::type_name::()) } #[inline] - fn get_type_info(&self) -> &'static TypeInfo { - ::type_info() + fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { + self.represented_type } #[inline] @@ -371,6 +379,11 @@ impl Reflect for DynamicTupleStruct { tuple_struct_debug(self, f)?; write!(f, ")") } + + #[inline] + fn is_dynamic(&self) -> bool { + true + } } impl Debug for DynamicTupleStruct { @@ -379,13 +392,6 @@ impl Debug for DynamicTupleStruct { } } -impl Typed for DynamicTupleStruct { - fn type_info() -> &'static TypeInfo { - static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new(); - CELL.get_or_set(|| TypeInfo::Dynamic(DynamicInfo::new::())) - } -} - /// Compares a [`TupleStruct`] with a [`Reflect`] value. /// /// Returns true if and only if all of the following are true: diff --git a/crates/bevy_reflect/src/type_info.rs b/crates/bevy_reflect/src/type_info.rs index 27df34ea76..c99beece3a 100644 --- a/crates/bevy_reflect/src/type_info.rs +++ b/crates/bevy_reflect/src/type_info.rs @@ -2,6 +2,7 @@ use crate::{ ArrayInfo, EnumInfo, ListInfo, MapInfo, Reflect, StructInfo, TupleInfo, TupleStructInfo, }; use std::any::{Any, TypeId}; +use std::fmt::Debug; /// A static accessor to compile-time type information. /// @@ -49,7 +50,7 @@ use std::any::{Any, TypeId}; /// # /// # impl Reflect for MyStruct { /// # fn type_name(&self) -> &str { todo!() } -/// # fn get_type_info(&self) -> &'static TypeInfo { todo!() } +/// # fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { todo!() } /// # fn into_any(self: Box) -> Box { todo!() } /// # fn as_any(&self) -> &dyn Any { todo!() } /// # fn as_any_mut(&mut self) -> &mut dyn Any { todo!() } @@ -78,12 +79,12 @@ pub trait Typed: Reflect { /// Generally, for any given type, this value can be retrieved one of three ways: /// /// 1. [`Typed::type_info`] -/// 2. [`Reflect::get_type_info`] +/// 2. [`Reflect::get_represented_type_info`] /// 3. [`TypeRegistry::get_type_info`] /// /// Each return a static reference to [`TypeInfo`], but they all have their own use cases. /// For example, if you know the type at compile time, [`Typed::type_info`] is probably -/// the simplest. If all you have is a `dyn Reflect`, you'll probably want [`Reflect::get_type_info`]. +/// the simplest. If all you have is a `dyn Reflect`, you'll probably want [`Reflect::get_represented_type_info`]. /// Lastly, if all you have is a [`TypeId`] or [type name], you will need to go through /// [`TypeRegistry::get_type_info`]. /// @@ -91,7 +92,7 @@ pub trait Typed: Reflect { /// it can be more performant. This is because those other methods may require attaining a lock on /// the static [`TypeInfo`], while the registry simply checks a map. /// -/// [`Reflect::get_type_info`]: crate::Reflect::get_type_info +/// [`Reflect::get_represented_type_info`]: crate::Reflect::get_represented_type_info /// [`TypeRegistry::get_type_info`]: crate::TypeRegistry::get_type_info /// [`TypeId`]: std::any::TypeId /// [type name]: std::any::type_name @@ -105,10 +106,6 @@ pub enum TypeInfo { Map(MapInfo), Enum(EnumInfo), Value(ValueInfo), - /// Type information for "dynamic" types whose metadata can't be known at compile-time. - /// - /// This includes structs like [`DynamicStruct`](crate::DynamicStruct) and [`DynamicList`](crate::DynamicList). - Dynamic(DynamicInfo), } impl TypeInfo { @@ -123,7 +120,6 @@ impl TypeInfo { Self::Map(info) => info.type_id(), Self::Enum(info) => info.type_id(), Self::Value(info) => info.type_id(), - Self::Dynamic(info) => info.type_id(), } } @@ -140,7 +136,6 @@ impl TypeInfo { Self::Map(info) => info.type_name(), Self::Enum(info) => info.type_name(), Self::Value(info) => info.type_name(), - Self::Dynamic(info) => info.type_name(), } } @@ -161,7 +156,6 @@ impl TypeInfo { Self::Map(info) => info.docs(), Self::Enum(info) => info.docs(), Self::Value(info) => info.docs(), - Self::Dynamic(info) => info.docs(), } } } @@ -221,59 +215,3 @@ impl ValueInfo { self.docs } } - -/// A container for compile-time info related to Bevy's _dynamic_ types, including primitives. -/// -/// This is functionally the same as [`ValueInfo`], however, semantically it refers to dynamic -/// types such as [`DynamicStruct`], [`DynamicTuple`], [`DynamicList`], etc. -/// -/// [`DynamicStruct`]: crate::DynamicStruct -/// [`DynamicTuple`]: crate::DynamicTuple -/// [`DynamicList`]: crate::DynamicList -#[derive(Debug, Clone)] -pub struct DynamicInfo { - type_name: &'static str, - type_id: TypeId, - #[cfg(feature = "documentation")] - docs: Option<&'static str>, -} - -impl DynamicInfo { - pub fn new() -> Self { - Self { - type_name: std::any::type_name::(), - type_id: TypeId::of::(), - #[cfg(feature = "documentation")] - docs: None, - } - } - - /// Sets the docstring for this dynamic value. - #[cfg(feature = "documentation")] - pub fn with_docs(self, docs: Option<&'static str>) -> Self { - Self { docs, ..self } - } - - /// The [type name] of the dynamic value. - /// - /// [type name]: std::any::type_name - pub fn type_name(&self) -> &'static str { - self.type_name - } - - /// The [`TypeId`] of the dynamic value. - pub fn type_id(&self) -> TypeId { - self.type_id - } - - /// Check if the given type matches the dynamic value type. - pub fn is(&self) -> bool { - TypeId::of::() == self.type_id - } - - /// The docstring of this value, if any. - #[cfg(feature = "documentation")] - pub fn docs(&self) -> Option<&'static str> { - self.docs - } -} diff --git a/crates/bevy_reflect/src/utility.rs b/crates/bevy_reflect/src/utility.rs index 3af535a192..7c203631aa 100644 --- a/crates/bevy_reflect/src/utility.rs +++ b/crates/bevy_reflect/src/utility.rs @@ -39,7 +39,7 @@ use std::{ /// # /// # impl Reflect for Foo { /// # fn type_name(&self) -> &str { todo!() } -/// # fn get_type_info(&self) -> &'static TypeInfo { todo!() } +/// # fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { todo!() } /// # fn into_any(self: Box) -> Box { todo!() } /// # fn as_any(&self) -> &dyn Any { todo!() } /// # fn as_any_mut(&mut self) -> &mut dyn Any { todo!() } @@ -102,7 +102,7 @@ impl NonGenericTypeInfoCell { /// # /// # impl Reflect for Foo { /// # fn type_name(&self) -> &str { todo!() } -/// # fn get_type_info(&self) -> &'static TypeInfo { todo!() } +/// # fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { todo!() } /// # fn into_any(self: Box) -> Box { todo!() } /// # fn as_any(&self) -> &dyn Any { todo!() } /// # fn as_any_mut(&mut self) -> &mut dyn Any { todo!() } From 4d54ce14aaee8d7432380df37c41c03c28594b27 Mon Sep 17 00:00:00 2001 From: Airing Date: Wed, 26 Apr 2023 23:34:23 +0800 Subject: [PATCH 08/21] Updated to wgpu 0.16.0, wgpu-hal 0.16.0 and naga 0.12.0 (#8446) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Objective - Updated to wgpu 0.16.0 and wgpu-hal 0.16.0 --- ## Changelog 1. Upgrade wgpu to 0.16.0 and wgpu-hal to 0.16.0 2. Fix the error in native when using a filterable `TextureSampleType::Float` on a multisample `BindingType::Texture`. ([https://github.com/gfx-rs/wgpu/pull/3686](https://github.com/gfx-rs/wgpu/pull/3686)) --------- Co-authored-by: François --- crates/bevy_core_pipeline/src/bloom/mod.rs | 3 +-- crates/bevy_pbr/src/prepass/mod.rs | 4 ++-- crates/bevy_pbr/src/render/light.rs | 11 ++++------ crates/bevy_pbr/src/render/mesh.rs | 7 +----- crates/bevy_render/Cargo.toml | 6 ++--- .../bevy_render/src/render_resource/shader.rs | 4 ++-- crates/bevy_render/src/texture/dds.rs | 2 +- .../bevy_render/src/texture/fallback_image.rs | 6 ++--- crates/bevy_render/src/texture/image.rs | 20 ++++++++--------- crates/bevy_render/src/texture/ktx2.rs | 22 ++++++++++--------- .../bevy_render/src/view/window/screenshot.rs | 4 ++-- crates/bevy_sprite/src/mesh2d/mesh.rs | 7 +----- crates/bevy_sprite/src/render/mod.rs | 7 +----- 13 files changed, 42 insertions(+), 61 deletions(-) diff --git a/crates/bevy_core_pipeline/src/bloom/mod.rs b/crates/bevy_core_pipeline/src/bloom/mod.rs index 34f615345f..3e761fbf76 100644 --- a/crates/bevy_core_pipeline/src/bloom/mod.rs +++ b/crates/bevy_core_pipeline/src/bloom/mod.rs @@ -30,7 +30,6 @@ use downsampling_pipeline::{ prepare_downsampling_pipeline, BloomDownsamplingPipeline, BloomDownsamplingPipelineIds, BloomUniforms, }; -use std::num::NonZeroU32; use upsampling_pipeline::{ prepare_upsampling_pipeline, BloomUpsamplingPipeline, UpsamplingPipelineIds, }; @@ -310,7 +309,7 @@ impl BloomTexture { fn view(&self, base_mip_level: u32) -> TextureView { self.texture.texture.create_view(&TextureViewDescriptor { base_mip_level, - mip_level_count: NonZeroU32::new(1), + mip_level_count: Some(1u32), ..Default::default() }) } diff --git a/crates/bevy_pbr/src/prepass/mod.rs b/crates/bevy_pbr/src/prepass/mod.rs index 0659f20a32..c24eb14335 100644 --- a/crates/bevy_pbr/src/prepass/mod.rs +++ b/crates/bevy_pbr/src/prepass/mod.rs @@ -561,7 +561,7 @@ pub fn get_bind_group_layout_entries( visibility: ShaderStages::FRAGMENT, ty: BindingType::Texture { multisampled, - sample_type: TextureSampleType::Float { filterable: true }, + sample_type: TextureSampleType::Float { filterable: false }, view_dimension: TextureViewDimension::D2, }, count: None, @@ -572,7 +572,7 @@ pub fn get_bind_group_layout_entries( visibility: ShaderStages::FRAGMENT, ty: BindingType::Texture { multisampled, - sample_type: TextureSampleType::Float { filterable: true }, + sample_type: TextureSampleType::Float { filterable: false }, view_dimension: TextureViewDimension::D2, }, count: None, diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index dc28bdfc06..1e73198a87 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -30,10 +30,7 @@ use bevy_utils::{ tracing::{error, warn}, HashMap, }; -use std::{ - hash::Hash, - num::{NonZeroU32, NonZeroU64}, -}; +use std::{hash::Hash, num::NonZeroU64}; #[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)] pub enum RenderLightSystems { @@ -998,7 +995,7 @@ pub fn prepare_lights( base_mip_level: 0, mip_level_count: None, base_array_layer: (light_index * 6 + face_index) as u32, - array_layer_count: NonZeroU32::new(1), + array_layer_count: Some(1u32), }); let view_light_entity = commands @@ -1060,7 +1057,7 @@ pub fn prepare_lights( base_mip_level: 0, mip_level_count: None, base_array_layer: (num_directional_cascades_enabled + light_index) as u32, - array_layer_count: NonZeroU32::new(1), + array_layer_count: Some(1u32), }); let view_light_entity = commands @@ -1124,7 +1121,7 @@ pub fn prepare_lights( base_mip_level: 0, mip_level_count: None, base_array_layer: directional_depth_texture_array_index, - array_layer_count: NonZeroU32::new(1), + array_layer_count: Some(1u32), }); directional_depth_texture_array_index += 1; diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 61f0eadba9..fb5fed27bb 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -514,12 +514,7 @@ impl FromWorld for MeshPipeline { &image.data, ImageDataLayout { offset: 0, - bytes_per_row: Some( - std::num::NonZeroU32::new( - image.texture_descriptor.size.width * format_size as u32, - ) - .unwrap(), - ), + bytes_per_row: Some(image.texture_descriptor.size.width * format_size as u32), rows_per_image: None, }, image.texture_descriptor.size, diff --git a/crates/bevy_render/Cargo.toml b/crates/bevy_render/Cargo.toml index a75130c133..e0f307650f 100644 --- a/crates/bevy_render/Cargo.toml +++ b/crates/bevy_render/Cargo.toml @@ -55,10 +55,10 @@ bevy_tasks = { path = "../bevy_tasks", version = "0.11.0-dev" } image = { version = "0.24", default-features = false } # misc -wgpu = { version = "0.15.0" } -wgpu-hal = "0.15.1" +wgpu = { version = "0.16.0" } +wgpu-hal = "0.16.0" codespan-reporting = "0.11.0" -naga = { version = "0.11.0", features = ["wgsl-in"] } +naga = { version = "0.12.0", features = ["wgsl-in"] } serde = { version = "1", features = ["derive"] } bitflags = "1.2.1" smallvec = { version = "1.6", features = ["union", "const_generics"] } diff --git a/crates/bevy_render/src/render_resource/shader.rs b/crates/bevy_render/src/render_resource/shader.rs index 95116432b2..572e5fea4a 100644 --- a/crates/bevy_render/src/render_resource/shader.rs +++ b/crates/bevy_render/src/render_resource/shader.rs @@ -128,7 +128,7 @@ impl ProcessedShader { ProcessedShader::Wgsl(source) => naga::front::wgsl::parse_str(source)?, #[cfg(feature = "shader_format_glsl")] ProcessedShader::Glsl(source, shader_stage) => { - let mut parser = naga::front::glsl::Parser::default(); + let mut parser = naga::front::glsl::Frontend::default(); parser .parse(&naga::front::glsl::Options::from(*shader_stage), source) .map_err(ShaderReflectError::GlslParse)? @@ -152,7 +152,7 @@ impl ProcessedShader { }; const CAPABILITIES: &[(Features, Capabilities)] = &[ (Features::PUSH_CONSTANTS, Capabilities::PUSH_CONSTANT), - (Features::SHADER_FLOAT64, Capabilities::FLOAT64), + (Features::SHADER_F64, Capabilities::FLOAT64), ( Features::SHADER_PRIMITIVE_INDEX, Capabilities::PRIMITIVE_INDEX, diff --git a/crates/bevy_render/src/texture/dds.rs b/crates/bevy_render/src/texture/dds.rs index bd008a3600..bfedd4b102 100644 --- a/crates/bevy_render/src/texture/dds.rs +++ b/crates/bevy_render/src/texture/dds.rs @@ -215,7 +215,7 @@ pub fn dds_format_to_texture_format( } DxgiFormat::BC6H_Typeless | DxgiFormat::BC6H_UF16 => TextureFormat::Bc6hRgbUfloat, - DxgiFormat::BC6H_SF16 => TextureFormat::Bc6hRgbSfloat, + DxgiFormat::BC6H_SF16 => TextureFormat::Bc6hRgbFloat, DxgiFormat::BC7_Typeless | DxgiFormat::BC7_UNorm | DxgiFormat::BC7_UNorm_sRGB => { if is_srgb { TextureFormat::Bc7RgbaUnormSrgb diff --git a/crates/bevy_render/src/texture/fallback_image.rs b/crates/bevy_render/src/texture/fallback_image.rs index 2ffe5204ac..cb3bec1420 100644 --- a/crates/bevy_render/src/texture/fallback_image.rs +++ b/crates/bevy_render/src/texture/fallback_image.rs @@ -1,5 +1,3 @@ -use std::num::NonZeroU32; - use crate::{render_resource::*, texture::DefaultImageSampler}; use bevy_derive::{Deref, DerefMut}; use bevy_ecs::{ @@ -54,7 +52,7 @@ fn fallback_image_new( image.texture_descriptor.usage |= TextureUsages::RENDER_ATTACHMENT; // We can't create textures with data when it's a depth texture or when using multiple samples - let texture = if format.describe().sample_type == TextureSampleType::Depth || samples > 1 { + let texture = if format.is_depth_stencil_format() || samples > 1 { render_device.create_texture(&image.texture_descriptor) } else { render_device.create_texture_with_data(render_queue, &image.texture_descriptor, &image.data) @@ -62,7 +60,7 @@ fn fallback_image_new( let texture_view = texture.create_view(&TextureViewDescriptor { dimension: Some(dimension), - array_layer_count: NonZeroU32::new(extents.depth_or_array_layers), + array_layer_count: Some(extents.depth_or_array_layers), ..TextureViewDescriptor::default() }); let sampler = match image.sampler_descriptor { diff --git a/crates/bevy_render/src/texture/image.rs b/crates/bevy_render/src/texture/image.rs index a2424365fe..bf3396e327 100644 --- a/crates/bevy_render/src/texture/image.rs +++ b/crates/bevy_render/src/texture/image.rs @@ -386,15 +386,15 @@ impl Image { /// Whether the texture format is compressed or uncompressed pub fn is_compressed(&self) -> bool { - let format_description = self.texture_descriptor.format.describe(); + let format_description = self.texture_descriptor.format; format_description - .required_features - .contains(wgpu::Features::TEXTURE_COMPRESSION_ASTC_LDR) + .required_features() + .contains(wgpu::Features::TEXTURE_COMPRESSION_ASTC) || format_description - .required_features + .required_features() .contains(wgpu::Features::TEXTURE_COMPRESSION_BC) || format_description - .required_features + .required_features() .contains(wgpu::Features::TEXTURE_COMPRESSION_ETC2) } } @@ -482,9 +482,9 @@ pub trait TextureFormatPixelInfo { impl TextureFormatPixelInfo for TextureFormat { fn pixel_size(&self) -> usize { - let info = self.describe(); - match info.block_dimensions { - (1, 1) => info.block_size.into(), + let info = self; + match info.block_dimensions() { + (1, 1) => info.block_size(None).unwrap() as usize, _ => panic!("Using pixel_size for compressed textures is invalid"), } } @@ -568,7 +568,7 @@ bitflags::bitflags! { impl CompressedImageFormats { pub fn from_features(features: wgpu::Features) -> Self { let mut supported_compressed_formats = Self::default(); - if features.contains(wgpu::Features::TEXTURE_COMPRESSION_ASTC_LDR) { + if features.contains(wgpu::Features::TEXTURE_COMPRESSION_ASTC) { supported_compressed_formats |= Self::ASTC_LDR; } if features.contains(wgpu::Features::TEXTURE_COMPRESSION_BC) { @@ -593,7 +593,7 @@ impl CompressedImageFormats { | TextureFormat::Bc5RgUnorm | TextureFormat::Bc5RgSnorm | TextureFormat::Bc6hRgbUfloat - | TextureFormat::Bc6hRgbSfloat + | TextureFormat::Bc6hRgbFloat | TextureFormat::Bc7RgbaUnorm | TextureFormat::Bc7RgbaUnormSrgb => self.contains(CompressedImageFormats::BC), TextureFormat::Etc2Rgb8Unorm diff --git a/crates/bevy_render/src/texture/ktx2.rs b/crates/bevy_render/src/texture/ktx2.rs index 6202df95d5..41801178de 100644 --- a/crates/bevy_render/src/texture/ktx2.rs +++ b/crates/bevy_render/src/texture/ktx2.rs @@ -154,12 +154,13 @@ pub fn ktx2_buffer_to_image( TranscodeFormat::Uastc(data_format) => { let (transcode_block_format, texture_format) = get_transcoded_formats(supported_compressed_formats, data_format, is_srgb); - let texture_format_info = texture_format.describe(); + let texture_format_info = texture_format; let (block_width_pixels, block_height_pixels) = ( - texture_format_info.block_dimensions.0 as u32, - texture_format_info.block_dimensions.1 as u32, + texture_format_info.block_dimensions().0, + texture_format_info.block_dimensions().1, ); - let block_bytes = texture_format_info.block_size as u32; + // Texture is not a depth or stencil format, it is possible to pass `None` and unwrap + let block_bytes = texture_format_info.block_size(None).unwrap(); let transcoder = LowLevelUastcTranscoder::new(); for (level, level_data) in levels.iter().enumerate() { @@ -233,12 +234,13 @@ pub fn ktx2_buffer_to_image( } // Reorder data from KTX2 MipXLayerYFaceZ to wgpu LayerYFaceZMipX - let texture_format_info = texture_format.describe(); + let texture_format_info = texture_format; let (block_width_pixels, block_height_pixels) = ( - texture_format_info.block_dimensions.0 as usize, - texture_format_info.block_dimensions.1 as usize, + texture_format_info.block_dimensions().0 as usize, + texture_format_info.block_dimensions().1 as usize, ); - let block_bytes = texture_format_info.block_size as usize; + // Texture is not a depth or stencil format, it is possible to pass `None` and unwrap + let block_bytes = texture_format_info.block_size(None).unwrap() as usize; let mut wgpu_data = vec![Vec::default(); (layer_count * face_count) as usize]; for (level, level_data) in levels.iter().enumerate() { @@ -1037,7 +1039,7 @@ pub fn ktx2_dfd_to_texture_format( if sample_information[0].lower == 0 { TextureFormat::Bc6hRgbUfloat } else { - TextureFormat::Bc6hRgbSfloat + TextureFormat::Bc6hRgbFloat } } Some(ColorModel::BC7) => { @@ -1311,7 +1313,7 @@ pub fn ktx2_format_to_texture_format( ktx2::Format::BC5_UNORM_BLOCK => TextureFormat::Bc5RgUnorm, ktx2::Format::BC5_SNORM_BLOCK => TextureFormat::Bc5RgSnorm, ktx2::Format::BC6H_UFLOAT_BLOCK => TextureFormat::Bc6hRgbUfloat, - ktx2::Format::BC6H_SFLOAT_BLOCK => TextureFormat::Bc6hRgbSfloat, + ktx2::Format::BC6H_SFLOAT_BLOCK => TextureFormat::Bc6hRgbFloat, ktx2::Format::BC7_UNORM_BLOCK | ktx2::Format::BC7_SRGB_BLOCK => { if is_srgb { TextureFormat::Bc7RgbaUnormSrgb diff --git a/crates/bevy_render/src/view/window/screenshot.rs b/crates/bevy_render/src/view/window/screenshot.rs index 2a67f43005..3ddca12256 100644 --- a/crates/bevy_render/src/view/window/screenshot.rs +++ b/crates/bevy_render/src/view/window/screenshot.rs @@ -1,4 +1,4 @@ -use std::{borrow::Cow, num::NonZeroU32, path::Path}; +use std::{borrow::Cow, path::Path}; use bevy_app::Plugin; use bevy_asset::{load_internal_asset, HandleUntyped}; @@ -117,7 +117,7 @@ pub(crate) fn layout_data(width: u32, height: u32, format: TextureFormat) -> Ima ImageDataLayout { bytes_per_row: if height > 1 { // 1 = 1 row - NonZeroU32::new(get_aligned_size(width, 1, format.pixel_size() as u32)) + Some(get_aligned_size(width, 1, format.pixel_size() as u32)) } else { None }, diff --git a/crates/bevy_sprite/src/mesh2d/mesh.rs b/crates/bevy_sprite/src/mesh2d/mesh.rs index d7b63d7d4c..11d4552af5 100644 --- a/crates/bevy_sprite/src/mesh2d/mesh.rs +++ b/crates/bevy_sprite/src/mesh2d/mesh.rs @@ -232,12 +232,7 @@ impl FromWorld for Mesh2dPipeline { &image.data, ImageDataLayout { offset: 0, - bytes_per_row: Some( - std::num::NonZeroU32::new( - image.texture_descriptor.size.width * format_size as u32, - ) - .unwrap(), - ), + bytes_per_row: Some(image.texture_descriptor.size.width * format_size as u32), rows_per_image: None, }, image.texture_descriptor.size, diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index 1279de05f0..725aab3234 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -109,12 +109,7 @@ impl FromWorld for SpritePipeline { &image.data, ImageDataLayout { offset: 0, - bytes_per_row: Some( - std::num::NonZeroU32::new( - image.texture_descriptor.size.width * format_size as u32, - ) - .unwrap(), - ), + bytes_per_row: Some(image.texture_descriptor.size.width * format_size as u32), rows_per_image: None, }, image.texture_descriptor.size, From 8ec4b99a6917379acfe1e50a3c1f4119504d7ffe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Wed, 26 Apr 2023 21:52:31 +0200 Subject: [PATCH 09/21] standardize instructions in examples (#8478) # Objective - Standardize on screen instructions in examples: - top left, bottom left when better - white, black when better - same margin (12px) and font size (20) ## Solution - Started with a few examples, let's reach consensus then document and open issues for the rest --- examples/3d/3d_gizmos.rs | 24 +++++--- examples/3d/anti_aliasing.rs | 5 +- examples/3d/atmospheric_fog.rs | 6 +- examples/3d/bloom_3d.rs | 7 ++- examples/3d/fog.rs | 27 ++++---- examples/3d/lighting.rs | 17 ++++++ examples/3d/parallax_mapping.rs | 11 ++-- examples/3d/shadow_biases.rs | 105 +++++++++++++++++++------------- 8 files changed, 123 insertions(+), 79 deletions(-) diff --git a/examples/3d/3d_gizmos.rs b/examples/3d/3d_gizmos.rs index 7ae97cd49d..585df5718d 100644 --- a/examples/3d/3d_gizmos.rs +++ b/examples/3d/3d_gizmos.rs @@ -43,15 +43,23 @@ fn setup( transform: Transform::from_xyz(4.0, 8.0, 4.0), ..default() }); - // text - commands.spawn(TextBundle::from_section( - "Press 't' to toggle drawing gizmos on top of everything else in the scene", - TextStyle { - font_size: 24., - color: Color::WHITE, + + // example instructions + commands.spawn( + TextBundle::from_section( + "Press 't' to toggle drawing gizmos on top of everything else in the scene", + TextStyle { + font_size: 20., + ..default() + }, + ) + .with_style(Style { + position_type: PositionType::Absolute, + top: Val::Px(12.0), + left: Val::Px(12.0), ..default() - }, - )); + }), + ); } fn system(mut gizmos: Gizmos, time: Res