diff --git a/crates/bevy_derive/src/enum_variant_meta.rs b/crates/bevy_derive/src/enum_variant_meta.rs new file mode 100644 index 00000000000000..ceb689b90bc0ff --- /dev/null +++ b/crates/bevy_derive/src/enum_variant_meta.rs @@ -0,0 +1,40 @@ +use crate::modules::{get_modules, get_path}; +use proc_macro::TokenStream; +use quote::quote; +use syn::{parse_macro_input, Data, DeriveInput}; + +pub fn derive_enum_variant_meta(input: TokenStream) -> TokenStream { + let ast = parse_macro_input!(input as DeriveInput); + let variants = match &ast.data { + Data::Enum(v) => &v.variants, + _ => panic!("Expected an enum."), + }; + + let modules = get_modules(&ast.attrs); + let bevy_util_path = get_path(&modules.bevy_utils); + + let generics = ast.generics; + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + + let struct_name = &ast.ident; + let idents = variants.iter().map(|v| &v.ident); + let names = variants.iter().map(|v| v.ident.to_string()); + let indices = 0..names.len(); + + TokenStream::from(quote! { + impl #impl_generics #bevy_util_path::EnumVariantMeta for #struct_name#ty_generics #where_clause { + fn enum_variant_index(&self) -> usize { + match self { + #(#struct_name::#idents {..} => #indices,)* + } + } + fn enum_variant_name(&self) -> &'static str { + static variants: &[&str] = &[ + #(#names,)* + ]; + let index = self.enum_variant_index(); + variants[index] + } + } + }) +} diff --git a/crates/bevy_derive/src/lib.rs b/crates/bevy_derive/src/lib.rs index 8603625470fa06..4b34c3ba2fdc37 100644 --- a/crates/bevy_derive/src/lib.rs +++ b/crates/bevy_derive/src/lib.rs @@ -3,6 +3,7 @@ extern crate proc_macro; mod app_plugin; mod bevy_main; mod bytes; +mod enum_variant_meta; mod modules; mod render_resource; mod render_resources; @@ -54,3 +55,8 @@ pub fn derive_dynamic_plugin(input: TokenStream) -> TokenStream { pub fn bevy_main(attr: TokenStream, item: TokenStream) -> TokenStream { bevy_main::bevy_main(attr, item) } + +#[proc_macro_derive(EnumVariantMeta, attributes(as_crate))] +pub fn derive_enum_variant_meta(input: TokenStream) -> TokenStream { + enum_variant_meta::derive_enum_variant_meta(input) +} diff --git a/crates/bevy_derive/src/modules.rs b/crates/bevy_derive/src/modules.rs index 19cd16c7aaa6dd..d8014a26034f68 100644 --- a/crates/bevy_derive/src/modules.rs +++ b/crates/bevy_derive/src/modules.rs @@ -7,6 +7,7 @@ pub struct Modules { pub bevy_render: String, pub bevy_asset: String, pub bevy_core: String, + pub bevy_utils: String, pub bevy_app: String, } @@ -16,6 +17,7 @@ impl Modules { bevy_asset: format!("{}::asset", name), bevy_render: format!("{}::render", name), bevy_core: format!("{}::core", name), + bevy_utils: format!("{}::utils", name), bevy_app: format!("{}::app", name), } } @@ -25,6 +27,7 @@ impl Modules { bevy_asset: "bevy_asset".to_string(), bevy_render: "bevy_render".to_string(), bevy_core: "bevy_core".to_string(), + bevy_utils: "bevy_utils".to_string(), bevy_app: "bevy_app".to_string(), } } diff --git a/crates/bevy_render/src/mesh/mesh.rs b/crates/bevy_render/src/mesh/mesh.rs index ddb7275312282f..f4772fb4992485 100644 --- a/crates/bevy_render/src/mesh/mesh.rs +++ b/crates/bevy_render/src/mesh/mesh.rs @@ -15,6 +15,7 @@ use bevy_ecs::{ }; use bevy_math::*; use bevy_reflect::TypeUuid; +use bevy_utils::EnumVariantMeta; use std::{borrow::Cow, collections::BTreeMap}; use crate::pipeline::{InputStepMode, VertexAttribute, VertexBufferLayout}; @@ -24,7 +25,7 @@ pub const INDEX_BUFFER_ASSET_INDEX: u64 = 0; pub const VERTEX_ATTRIBUTE_BUFFER_ID: u64 = 10; /// An array where each entry describes a property of a single vertex. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, EnumVariantMeta)] pub enum VertexAttributeValues { Float(Vec), Int(Vec), diff --git a/crates/bevy_render/src/mesh/mesh/conversions.rs b/crates/bevy_render/src/mesh/mesh/conversions.rs index 1326cd27fdfdd9..df41df5f1da2c7 100644 --- a/crates/bevy_render/src/mesh/mesh/conversions.rs +++ b/crates/bevy_render/src/mesh/mesh/conversions.rs @@ -26,49 +26,25 @@ //! ``` use crate::mesh::VertexAttributeValues; -use std::{convert::TryFrom, error::Error, fmt}; +use bevy_utils::EnumVariantMeta; +use std::convert::TryFrom; +use thiserror::Error; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Error)] +#[error("cannot convert VertexAttributeValues::{variant} to {into}")] pub struct FromVertexAttributeError { from: VertexAttributeValues, + variant: &'static str, into: &'static str, } -impl Error for FromVertexAttributeError {} - -impl fmt::Display for FromVertexAttributeError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let value_name = match self.from { - VertexAttributeValues::Float(..) => "VertexAttributeValues::Float", - VertexAttributeValues::Int(..) => "VertexAttributeValues::Int", - VertexAttributeValues::Uint(..) => "VertexAttributeValues::Uint", - VertexAttributeValues::Float2(..) => "VertexAttributeValues::Float2", - VertexAttributeValues::Int2(..) => "VertexAttributeValues::Int2", - VertexAttributeValues::Uint2(..) => "VertexAttributeValues::Uint2", - VertexAttributeValues::Float3(..) => "VertexAttributeValues::Float3", - VertexAttributeValues::Int3(..) => "VertexAttributeValues::Int3", - VertexAttributeValues::Uint3(..) => "VertexAttributeValues::Uint3", - VertexAttributeValues::Float4(..) => "VertexAttributeValues::Float4", - VertexAttributeValues::Int4(..) => "VertexAttributeValues::Int4", - VertexAttributeValues::Uint4(..) => "VertexAttributeValues::Uint4", - VertexAttributeValues::Short2(..) => "VertexAttributeValues::Short2", - VertexAttributeValues::Short2Norm(..) => "VertexAttributeValues::Short2Norm", - VertexAttributeValues::Ushort2(..) => "VertexAttributeValues::Ushort2", - VertexAttributeValues::Ushort2Norm(..) => "VertexAttributeValues::Ushort2Norm", - VertexAttributeValues::Short4(..) => "VertexAttributeValues::Short4", - VertexAttributeValues::Short4Norm(..) => "VertexAttributeValues::Short4Norm", - VertexAttributeValues::Ushort4(..) => "VertexAttributeValues::Ushort4", - VertexAttributeValues::Ushort4Norm(..) => "VertexAttributeValues::Ushort4Norm", - VertexAttributeValues::Char2(..) => "VertexAttributeValues::Char2", - VertexAttributeValues::Char2Norm(..) => "VertexAttributeValues::Char2Norm", - VertexAttributeValues::Uchar2(..) => "VertexAttributeValues::Uchar2", - VertexAttributeValues::Uchar2Norm(..) => "VertexAttributeValues::Uchar2Norm", - VertexAttributeValues::Char4(..) => "VertexAttributeValues::Char4", - VertexAttributeValues::Char4Norm(..) => "VertexAttributeValues::Char4Norm", - VertexAttributeValues::Uchar4(..) => "VertexAttributeValues::Uchar4", - VertexAttributeValues::Uchar4Norm(..) => "VertexAttributeValues::Uchar4Norm", - }; - write!(f, "can't convert `{}` to `{}`", value_name, self.into) +impl FromVertexAttributeError { + fn new(from: VertexAttributeValues) -> Self { + Self { + variant: from.enum_variant_name(), + into: std::any::type_name::(), + from, + } } } @@ -157,10 +133,7 @@ impl TryFrom for Vec<[u8; 4]> { match value { VertexAttributeValues::Uchar4(value) => Ok(value), VertexAttributeValues::Uchar4Norm(value) => Ok(value), - _ => Err(FromVertexAttributeError { - from: value, - into: "Vec<[u8; 4]>", - }), + _ => Err(FromVertexAttributeError::new::(value)), } } } @@ -172,10 +145,7 @@ impl TryFrom for Vec<[i8; 4]> { match value { VertexAttributeValues::Char4(value) => Ok(value), VertexAttributeValues::Char4Norm(value) => Ok(value), - _ => Err(FromVertexAttributeError { - from: value, - into: "Vec<[i8; 4]>", - }), + _ => Err(FromVertexAttributeError::new::(value)), } } } @@ -187,10 +157,7 @@ impl TryFrom for Vec<[u8; 2]> { match value { VertexAttributeValues::Uchar2(value) => Ok(value), VertexAttributeValues::Uchar2Norm(value) => Ok(value), - _ => Err(FromVertexAttributeError { - from: value, - into: "Vec<[u8; 2]>", - }), + _ => Err(FromVertexAttributeError::new::(value)), } } } @@ -202,10 +169,7 @@ impl TryFrom for Vec<[i8; 2]> { match value { VertexAttributeValues::Char2(value) => Ok(value), VertexAttributeValues::Char2Norm(value) => Ok(value), - _ => Err(FromVertexAttributeError { - from: value, - into: "Vec<[i8; 2]>", - }), + _ => Err(FromVertexAttributeError::new::(value)), } } } @@ -217,10 +181,7 @@ impl TryFrom for Vec<[i16; 4]> { match value { VertexAttributeValues::Short4(value) => Ok(value), VertexAttributeValues::Short4Norm(value) => Ok(value), - _ => Err(FromVertexAttributeError { - from: value, - into: "Vec<[i16; 4]>", - }), + _ => Err(FromVertexAttributeError::new::(value)), } } } @@ -232,10 +193,7 @@ impl TryFrom for Vec<[u16; 4]> { match value { VertexAttributeValues::Ushort4(value) => Ok(value), VertexAttributeValues::Ushort4Norm(value) => Ok(value), - _ => Err(FromVertexAttributeError { - from: value, - into: "Vec<[u16; 4]>", - }), + _ => Err(FromVertexAttributeError::new::(value)), } } } @@ -247,10 +205,7 @@ impl TryFrom for Vec<[u16; 2]> { match value { VertexAttributeValues::Ushort2(value) => Ok(value), VertexAttributeValues::Ushort2Norm(value) => Ok(value), - _ => Err(FromVertexAttributeError { - from: value, - into: "Vec<[i16; 2]>", - }), + _ => Err(FromVertexAttributeError::new::(value)), } } } @@ -262,10 +217,7 @@ impl TryFrom for Vec<[i16; 2]> { match value { VertexAttributeValues::Short2(value) => Ok(value), VertexAttributeValues::Short2Norm(value) => Ok(value), - _ => Err(FromVertexAttributeError { - from: value, - into: "Vec<[i16; 2]>", - }), + _ => Err(FromVertexAttributeError::new::(value)), } } } @@ -276,10 +228,7 @@ impl TryFrom for Vec<[u32; 4]> { fn try_from(value: VertexAttributeValues) -> Result { match value { VertexAttributeValues::Uint4(value) => Ok(value), - _ => Err(FromVertexAttributeError { - from: value, - into: "Vec<[u32; 4]>", - }), + _ => Err(FromVertexAttributeError::new::(value)), } } } @@ -290,10 +239,7 @@ impl TryFrom for Vec<[i32; 4]> { fn try_from(value: VertexAttributeValues) -> Result { match value { VertexAttributeValues::Int4(value) => Ok(value), - _ => Err(FromVertexAttributeError { - from: value, - into: "Vec<[i32; 4]>", - }), + _ => Err(FromVertexAttributeError::new::(value)), } } } @@ -304,10 +250,7 @@ impl TryFrom for Vec<[f32; 4]> { fn try_from(value: VertexAttributeValues) -> Result { match value { VertexAttributeValues::Float4(value) => Ok(value), - _ => Err(FromVertexAttributeError { - from: value, - into: "Vec<[f32; 4]>", - }), + _ => Err(FromVertexAttributeError::new::(value)), } } } @@ -318,10 +261,7 @@ impl TryFrom for Vec<[u32; 3]> { fn try_from(value: VertexAttributeValues) -> Result { match value { VertexAttributeValues::Uint3(value) => Ok(value), - _ => Err(FromVertexAttributeError { - from: value, - into: "Vec<[u32; 3]>", - }), + _ => Err(FromVertexAttributeError::new::(value)), } } } @@ -332,10 +272,7 @@ impl TryFrom for Vec<[i32; 3]> { fn try_from(value: VertexAttributeValues) -> Result { match value { VertexAttributeValues::Int3(value) => Ok(value), - _ => Err(FromVertexAttributeError { - from: value, - into: "Vec<[i32; 3]>", - }), + _ => Err(FromVertexAttributeError::new::(value)), } } } @@ -346,10 +283,7 @@ impl TryFrom for Vec<[f32; 3]> { fn try_from(value: VertexAttributeValues) -> Result { match value { VertexAttributeValues::Float3(value) => Ok(value), - _ => Err(FromVertexAttributeError { - from: value, - into: "Vec<[f32; 3]>", - }), + _ => Err(FromVertexAttributeError::new::(value)), } } } @@ -360,10 +294,7 @@ impl TryFrom for Vec<[u32; 2]> { fn try_from(value: VertexAttributeValues) -> Result { match value { VertexAttributeValues::Uint2(value) => Ok(value), - _ => Err(FromVertexAttributeError { - from: value, - into: "Vec<[u32; 2]>", - }), + _ => Err(FromVertexAttributeError::new::(value)), } } } @@ -374,10 +305,7 @@ impl TryFrom for Vec<[i32; 2]> { fn try_from(value: VertexAttributeValues) -> Result { match value { VertexAttributeValues::Int2(value) => Ok(value), - _ => Err(FromVertexAttributeError { - from: value, - into: "Vec<[i32; 2]>", - }), + _ => Err(FromVertexAttributeError::new::(value)), } } } @@ -388,10 +316,7 @@ impl TryFrom for Vec<[f32; 2]> { fn try_from(value: VertexAttributeValues) -> Result { match value { VertexAttributeValues::Float2(value) => Ok(value), - _ => Err(FromVertexAttributeError { - from: value, - into: "Vec<[f32; 2]>", - }), + _ => Err(FromVertexAttributeError::new::(value)), } } } @@ -402,10 +327,7 @@ impl TryFrom for Vec { fn try_from(value: VertexAttributeValues) -> Result { match value { VertexAttributeValues::Uint(value) => Ok(value), - _ => Err(FromVertexAttributeError { - from: value, - into: "Vec", - }), + _ => Err(FromVertexAttributeError::new::(value)), } } } @@ -416,10 +338,7 @@ impl TryFrom for Vec { fn try_from(value: VertexAttributeValues) -> Result { match value { VertexAttributeValues::Int(value) => Ok(value), - _ => Err(FromVertexAttributeError { - from: value, - into: "Vec", - }), + _ => Err(FromVertexAttributeError::new::(value)), } } } @@ -430,10 +349,7 @@ impl TryFrom for Vec { fn try_from(value: VertexAttributeValues) -> Result { match value { VertexAttributeValues::Float(value) => Ok(value), - _ => Err(FromVertexAttributeError { - from: value, - into: "Vec", - }), + _ => Err(FromVertexAttributeError::new::(value)), } } } @@ -442,7 +358,6 @@ impl TryFrom for Vec { mod tests { use super::VertexAttributeValues; use std::convert::{TryFrom, TryInto}; - #[test] fn f32() { let buffer = vec![0.0; 10]; @@ -598,9 +513,9 @@ mod tests { }; assert_eq!( format!("{}", error), - "can't convert `VertexAttributeValues::Uint4` to `Vec`" + "cannot convert VertexAttributeValues::Uint4 to alloc::vec::Vec" ); assert_eq!(format!("{:?}", error), - "FromVertexAttributeError { from: Uint4([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]), into: \"Vec\" }"); + "FromVertexAttributeError { from: Uint4([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]), variant: \"Uint4\", into: \"alloc::vec::Vec\" }"); } } diff --git a/crates/bevy_utils/Cargo.toml b/crates/bevy_utils/Cargo.toml index ca11ca3d868abb..c96746d01b4922 100644 --- a/crates/bevy_utils/Cargo.toml +++ b/crates/bevy_utils/Cargo.toml @@ -13,6 +13,7 @@ license = "MIT" keywords = ["bevy"] [dependencies] +bevy_derive = { path = "../bevy_derive", version = "0.5.0" } ahash = "0.7.0" tracing = {version = "0.1", features = ["release_max_level_info"]} instant = { version = "0.1", features = ["wasm-bindgen"] } diff --git a/crates/bevy_utils/src/enum_variant_meta.rs b/crates/bevy_utils/src/enum_variant_meta.rs new file mode 100644 index 00000000000000..fa55230e59af8d --- /dev/null +++ b/crates/bevy_utils/src/enum_variant_meta.rs @@ -0,0 +1,6 @@ +pub use bevy_derive::EnumVariantMeta; + +pub trait EnumVariantMeta { + fn enum_variant_index(&self) -> usize; + fn enum_variant_name(&self) -> &'static str; +} diff --git a/crates/bevy_utils/src/lib.rs b/crates/bevy_utils/src/lib.rs index 17560532b79495..9d66179df301ce 100644 --- a/crates/bevy_utils/src/lib.rs +++ b/crates/bevy_utils/src/lib.rs @@ -1,10 +1,14 @@ +mod enum_variant_meta; +pub use enum_variant_meta::*; + pub use ahash::AHasher; -use ahash::RandomState; pub use instant::{Duration, Instant}; -use std::{future::Future, pin::Pin}; pub use tracing; pub use uuid::Uuid; +use ahash::RandomState; +use std::{future::Future, pin::Pin}; + #[cfg(not(target_arch = "wasm32"))] pub type BoxedFuture<'a, T> = Pin + Send + 'a>>;