From 329fc46f56f9a46e6d36c818162c2c0d3f9a90df Mon Sep 17 00:00:00 2001 From: DasLixou Date: Wed, 18 Jan 2023 20:08:50 +0100 Subject: [PATCH 1/7] Add `IterableEnum` --- crates/bevy_utils/src/iterable_enum.rs | 38 ++++++++++++++++++++++++++ crates/bevy_utils/src/lib.rs | 2 ++ 2 files changed, 40 insertions(+) create mode 100644 crates/bevy_utils/src/iterable_enum.rs diff --git a/crates/bevy_utils/src/iterable_enum.rs b/crates/bevy_utils/src/iterable_enum.rs new file mode 100644 index 0000000000000..af85fef3accef --- /dev/null +++ b/crates/bevy_utils/src/iterable_enum.rs @@ -0,0 +1,38 @@ +use std::marker::PhantomData; + +/// A trait for enums to get a `Unit`-enum-field by a `usize` +pub trait IterableEnum: Sized { + /// Gets an `Unit`-enum-field by the given `usize` index + fn get_at(index: usize) -> Option; + + /// Creates a new [`EnumIterator`] which will numerically return every `Unit` of this enum + #[inline] + fn enum_iter() -> EnumIterator { + EnumIterator { + accelerator: 0, + phantom: PhantomData, + } + } +} + +/// An iterator over `IterableEnum`s +/// +/// Iterates all `Unit` fields in numeric order +pub struct EnumIterator { + accelerator: usize, + phantom: PhantomData, +} + +impl Iterator for EnumIterator { + type Item = E; + + #[inline] + fn next(&mut self) -> Option { + if let Some(unit) = E::get_at(self.accelerator) { + self.accelerator += 1; + Some(unit) + } else { + None + } + } +} diff --git a/crates/bevy_utils/src/lib.rs b/crates/bevy_utils/src/lib.rs index 2a522c087900f..b222cf74c7557 100644 --- a/crates/bevy_utils/src/lib.rs +++ b/crates/bevy_utils/src/lib.rs @@ -18,12 +18,14 @@ pub mod synccell; mod default; mod float_ord; +mod iterable_enum; pub use ahash::AHasher; pub use default::default; pub use float_ord::*; pub use hashbrown; pub use instant::{Duration, Instant}; +pub use iterable_enum::IterableEnum; pub use tracing; pub use uuid::Uuid; From 5eaeca50b80bf585599e96b702d8091a3d626304 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Wed, 18 Jan 2023 20:29:25 +0100 Subject: [PATCH 2/7] Add `#[derive(IterableEnum)]` --- crates/bevy_utils/Cargo.toml | 3 +- crates/bevy_utils/macros/Cargo.toml | 16 +++++ crates/bevy_utils/macros/src/iterable_enum.rs | 59 +++++++++++++++++++ crates/bevy_utils/macros/src/lib.rs | 8 +++ 4 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 crates/bevy_utils/macros/Cargo.toml create mode 100644 crates/bevy_utils/macros/src/iterable_enum.rs create mode 100644 crates/bevy_utils/macros/src/lib.rs diff --git a/crates/bevy_utils/Cargo.toml b/crates/bevy_utils/Cargo.toml index a61ce8d16594d..3e596ccd6b421 100644 --- a/crates/bevy_utils/Cargo.toml +++ b/crates/bevy_utils/Cargo.toml @@ -13,7 +13,8 @@ ahash = "0.7.0" tracing = { version = "0.1", default-features = false, features = ["std"] } instant = { version = "0.1", features = ["wasm-bindgen"] } uuid = { version = "1.1", features = ["v4", "serde"] } -hashbrown = { version = "0.12", features = ["serde"] } +hashbrown = { version = "0.12.3", features = ["serde"] } +bevy_utils_macros = { version = "0.9.0", path = "./macros" } [target.'cfg(target_arch = "wasm32")'.dependencies] getrandom = {version = "0.2.0", features = ["js"]} diff --git a/crates/bevy_utils/macros/Cargo.toml b/crates/bevy_utils/macros/Cargo.toml new file mode 100644 index 0000000000000..d894232bbca0e --- /dev/null +++ b/crates/bevy_utils/macros/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "bevy_utils_macros" +version = "0.9.0" +edition = "2021" +description = "Derive implementations for bevy_utils" +homepage = "https://bevyengine.org" +repository = "https://github.com/bevyengine/bevy" +license = "MIT OR Apache-2.0" +keywords = ["bevy"] + +[lib] +proc-macro = true + +[dependencies] +syn = { version = "1.0", features = ["full", "parsing", "extra-traits"] } +quote = "1.0" \ No newline at end of file diff --git a/crates/bevy_utils/macros/src/iterable_enum.rs b/crates/bevy_utils/macros/src/iterable_enum.rs new file mode 100644 index 0000000000000..1fd1beaf5517a --- /dev/null +++ b/crates/bevy_utils/macros/src/iterable_enum.rs @@ -0,0 +1,59 @@ +use proc_macro::TokenStream; +use quote::{quote, quote_spanned, ToTokens}; +use syn::{__private::Span, spanned::Spanned, DataEnum}; + +pub fn parse_iterable_enum_derive(input: TokenStream) -> TokenStream { + let ast = syn::parse_macro_input!(input as syn::DeriveInput); + + let span = ast.span(); + + let name = &ast.ident; + let generics = &ast.generics; + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + + let get_at = match ast.data { + syn::Data::Enum(d) => get_at_impl(name, span, d), + _ => quote_spanned! { + span => compile_error!("`IterableEnum` can only be applied to `enum`") + }, + }; + + quote! { + impl #impl_generics bevy_utils::IterableEnum for #name #ty_generics #where_clause { + #get_at + } + } + .into() +} + +fn get_at_impl(name: impl ToTokens, span: Span, d: DataEnum) -> quote::__private::TokenStream { + let mut arms = quote!(); + let mut index: usize = 0; + + for variant in d.variants { + match variant.fields { + syn::Fields::Unit => { + let ident = variant.ident; + arms = quote! { #arms #index => Some(#name::#ident), }; + index += 1; + } + _ => { + return quote_spanned! { + span => compile_error!("All Fields should be Units!"); + } + .into(); + } + }; + } + + quote! { + #[inline] + fn get_at(index: usize) -> Option { + match index { + #arms, + _ => None, + } + } + } + .into() +} diff --git a/crates/bevy_utils/macros/src/lib.rs b/crates/bevy_utils/macros/src/lib.rs new file mode 100644 index 0000000000000..26f68174295f3 --- /dev/null +++ b/crates/bevy_utils/macros/src/lib.rs @@ -0,0 +1,8 @@ +use proc_macro::TokenStream; + +mod iterable_enum; + +#[proc_macro_derive(IterableEnum)] +pub fn iterable_enum_derive(input: TokenStream) -> TokenStream { + iterable_enum::parse_iterable_enum_derive(input) +} From 6fcc72b77d1f312f8b2e5f4c2704e54d2bd32011 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Wed, 18 Jan 2023 20:42:33 +0100 Subject: [PATCH 3/7] Use BevyManifest --- crates/bevy_utils/macros/Cargo.toml | 3 ++- crates/bevy_utils/macros/src/iterable_enum.rs | 6 +++++- crates/bevy_utils/macros/src/lib.rs | 1 + crates/bevy_utils/macros/src/paths.rs | 16 ++++++++++++++++ crates/bevy_utils/src/iterable_enum.rs | 4 ++-- 5 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 crates/bevy_utils/macros/src/paths.rs diff --git a/crates/bevy_utils/macros/Cargo.toml b/crates/bevy_utils/macros/Cargo.toml index d894232bbca0e..49cd048960f9c 100644 --- a/crates/bevy_utils/macros/Cargo.toml +++ b/crates/bevy_utils/macros/Cargo.toml @@ -13,4 +13,5 @@ proc-macro = true [dependencies] syn = { version = "1.0", features = ["full", "parsing", "extra-traits"] } -quote = "1.0" \ No newline at end of file +quote = "1.0" +bevy_macro_utils = { version = "0.9.0", path = "../../bevy_macro_utils" } \ No newline at end of file diff --git a/crates/bevy_utils/macros/src/iterable_enum.rs b/crates/bevy_utils/macros/src/iterable_enum.rs index 1fd1beaf5517a..7235d208967e1 100644 --- a/crates/bevy_utils/macros/src/iterable_enum.rs +++ b/crates/bevy_utils/macros/src/iterable_enum.rs @@ -2,6 +2,8 @@ use proc_macro::TokenStream; use quote::{quote, quote_spanned, ToTokens}; use syn::{__private::Span, spanned::Spanned, DataEnum}; +use crate::paths; + pub fn parse_iterable_enum_derive(input: TokenStream) -> TokenStream { let ast = syn::parse_macro_input!(input as syn::DeriveInput); @@ -18,8 +20,10 @@ pub fn parse_iterable_enum_derive(input: TokenStream) -> TokenStream { }, }; + let iterable_enum = paths::iterable_enum_path(); + quote! { - impl #impl_generics bevy_utils::IterableEnum for #name #ty_generics #where_clause { + impl #impl_generics #iterable_enum for #name #ty_generics #where_clause { #get_at } } diff --git a/crates/bevy_utils/macros/src/lib.rs b/crates/bevy_utils/macros/src/lib.rs index 26f68174295f3..a06cee2e24ea2 100644 --- a/crates/bevy_utils/macros/src/lib.rs +++ b/crates/bevy_utils/macros/src/lib.rs @@ -1,6 +1,7 @@ use proc_macro::TokenStream; mod iterable_enum; +mod paths; #[proc_macro_derive(IterableEnum)] pub fn iterable_enum_derive(input: TokenStream) -> TokenStream { diff --git a/crates/bevy_utils/macros/src/paths.rs b/crates/bevy_utils/macros/src/paths.rs new file mode 100644 index 0000000000000..b07bcf0db071c --- /dev/null +++ b/crates/bevy_utils/macros/src/paths.rs @@ -0,0 +1,16 @@ +use bevy_macro_utils::BevyManifest; +use quote::format_ident; + +#[inline] +pub(crate) fn bevy_utils_path() -> syn::Path { + BevyManifest::default().get_path("bevy_utils") +} + +#[inline] +pub(crate) fn iterable_enum_path() -> syn::Path { + let mut utils_path = bevy_utils_path(); + utils_path + .segments + .push(format_ident!("IterableEnum").into()); + utils_path +} diff --git a/crates/bevy_utils/src/iterable_enum.rs b/crates/bevy_utils/src/iterable_enum.rs index af85fef3accef..325783a81c46e 100644 --- a/crates/bevy_utils/src/iterable_enum.rs +++ b/crates/bevy_utils/src/iterable_enum.rs @@ -16,7 +16,7 @@ pub trait IterableEnum: Sized { } /// An iterator over `IterableEnum`s -/// +/// /// Iterates all `Unit` fields in numeric order pub struct EnumIterator { accelerator: usize, @@ -35,4 +35,4 @@ impl Iterator for EnumIterator { None } } -} +} \ No newline at end of file From 8beb9ad86de4f80bca2f917b55f3a34c75c02809 Mon Sep 17 00:00:00 2001 From: DasLixou Date: Wed, 18 Jan 2023 20:47:21 +0100 Subject: [PATCH 4/7] Implement for `KeyCode` --- crates/bevy_input/src/keyboard.rs | 5 ++++- crates/bevy_utils/macros/src/iterable_enum.rs | 2 +- crates/bevy_utils/src/lib.rs | 2 ++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/crates/bevy_input/src/keyboard.rs b/crates/bevy_input/src/keyboard.rs index 021646015be7c..501f611cac417 100644 --- a/crates/bevy_input/src/keyboard.rs +++ b/crates/bevy_input/src/keyboard.rs @@ -4,6 +4,7 @@ use bevy_reflect::{FromReflect, Reflect}; #[cfg(feature = "serialize")] use bevy_reflect::{ReflectDeserialize, ReflectSerialize}; +use bevy_utils::IterableEnum; /// A keyboard input event. /// @@ -71,7 +72,9 @@ pub fn keyboard_input_system( /// ## Updating /// /// The resource is updated inside of the [`keyboard_input_system`](crate::keyboard::keyboard_input_system). -#[derive(Debug, Hash, Ord, PartialOrd, PartialEq, Eq, Clone, Copy, Reflect, FromReflect)] +#[derive( + Debug, Hash, Ord, PartialOrd, PartialEq, Eq, Clone, Copy, Reflect, FromReflect, IterableEnum, +)] #[reflect(Debug, Hash, PartialEq)] #[cfg_attr( feature = "serialize", diff --git a/crates/bevy_utils/macros/src/iterable_enum.rs b/crates/bevy_utils/macros/src/iterable_enum.rs index 7235d208967e1..4c353c5c02a0e 100644 --- a/crates/bevy_utils/macros/src/iterable_enum.rs +++ b/crates/bevy_utils/macros/src/iterable_enum.rs @@ -54,7 +54,7 @@ fn get_at_impl(name: impl ToTokens, span: Span, d: DataEnum) -> quote::__private #[inline] fn get_at(index: usize) -> Option { match index { - #arms, + #arms _ => None, } } diff --git a/crates/bevy_utils/src/lib.rs b/crates/bevy_utils/src/lib.rs index b222cf74c7557..f813b67eaa1fd 100644 --- a/crates/bevy_utils/src/lib.rs +++ b/crates/bevy_utils/src/lib.rs @@ -10,6 +10,8 @@ pub mod prelude { pub use crate::default; } +pub use bevy_utils_macros::*; + pub mod futures; pub mod label; mod short_names; From 5bf736d06fbec203713a5e63ace11cc8637c0882 Mon Sep 17 00:00:00 2001 From: Lixou <82600264+DasLixou@users.noreply.github.com> Date: Wed, 18 Jan 2023 20:55:37 +0100 Subject: [PATCH 5/7] Update crates/bevy_utils/macros/Cargo.toml Co-authored-by: James Liu --- crates/bevy_utils/macros/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_utils/macros/Cargo.toml b/crates/bevy_utils/macros/Cargo.toml index 49cd048960f9c..fed53367d0cbb 100644 --- a/crates/bevy_utils/macros/Cargo.toml +++ b/crates/bevy_utils/macros/Cargo.toml @@ -14,4 +14,4 @@ proc-macro = true [dependencies] syn = { version = "1.0", features = ["full", "parsing", "extra-traits"] } quote = "1.0" -bevy_macro_utils = { version = "0.9.0", path = "../../bevy_macro_utils" } \ No newline at end of file +bevy_macro_utils = { version = "0.9.0", path = "../../bevy_macro_utils" } From e29579c6a90dd6c2bf8fe7ea11c6058021f99400 Mon Sep 17 00:00:00 2001 From: Lixou <82600264+DasLixou@users.noreply.github.com> Date: Wed, 18 Jan 2023 20:56:05 +0100 Subject: [PATCH 6/7] Update crates/bevy_utils/src/iterable_enum.rs Co-authored-by: James Liu --- crates/bevy_utils/src/iterable_enum.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_utils/src/iterable_enum.rs b/crates/bevy_utils/src/iterable_enum.rs index 325783a81c46e..c6061d99caa7c 100644 --- a/crates/bevy_utils/src/iterable_enum.rs +++ b/crates/bevy_utils/src/iterable_enum.rs @@ -35,4 +35,4 @@ impl Iterator for EnumIterator { None } } -} \ No newline at end of file +} From 51d0433c11b57062fdf7c5e4141853e431930942 Mon Sep 17 00:00:00 2001 From: Lixou <82600264+DasLixou@users.noreply.github.com> Date: Wed, 18 Jan 2023 20:56:24 +0100 Subject: [PATCH 7/7] Update crates/bevy_utils/macros/src/lib.rs Co-authored-by: James Liu --- crates/bevy_utils/macros/src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crates/bevy_utils/macros/src/lib.rs b/crates/bevy_utils/macros/src/lib.rs index a06cee2e24ea2..6ec2be74629a3 100644 --- a/crates/bevy_utils/macros/src/lib.rs +++ b/crates/bevy_utils/macros/src/lib.rs @@ -1,3 +1,6 @@ +#![forbid(unsafe_code)] +#![warn(missing_docs)] + use proc_macro::TokenStream; mod iterable_enum;