-
-
Notifications
You must be signed in to change notification settings - Fork 3.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add IterableEnum
trait
#7269
Add IterableEnum
trait
#7269
Changes from 4 commits
329fc46
5eaeca5
6fcc72b
8beb9ad
31ced3b
5bf736d
e29579c
51d0433
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
[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" | ||
bevy_macro_utils = { version = "0.9.0", path = "../../bevy_macro_utils" } | ||
DasLixou marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is really confusing to now have both There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Already thought about that on discord. But no answer from Alice yet |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
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 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pretty smart idea. I’ll try There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we lose the trait altogether and just generate an associated const on the type itself? |
||
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`") | ||
}, | ||
}; | ||
|
||
let iterable_enum = paths::iterable_enum_path(); | ||
|
||
quote! { | ||
impl #impl_generics #iterable_enum 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<Self> { | ||
match index { | ||
#arms | ||
_ => None, | ||
} | ||
} | ||
} | ||
.into() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
use proc_macro::TokenStream; | ||
DasLixou marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
mod iterable_enum; | ||
mod paths; | ||
|
||
#[proc_macro_derive(IterableEnum)] | ||
pub fn iterable_enum_derive(input: TokenStream) -> TokenStream { | ||
iterable_enum::parse_iterable_enum_derive(input) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<Self>; | ||
|
||
/// Creates a new [`EnumIterator`] which will numerically return every `Unit` of this enum | ||
#[inline] | ||
fn enum_iter() -> EnumIterator<Self> { | ||
EnumIterator { | ||
accelerator: 0, | ||
phantom: PhantomData, | ||
} | ||
} | ||
} | ||
|
||
/// An iterator over `IterableEnum`s | ||
/// | ||
/// Iterates all `Unit` fields in numeric order | ||
pub struct EnumIterator<E: IterableEnum> { | ||
accelerator: usize, | ||
phantom: PhantomData<E>, | ||
} | ||
|
||
impl<E: IterableEnum> Iterator for EnumIterator<E> { | ||
type Item = E; | ||
|
||
#[inline] | ||
fn next(&mut self) -> Option<Self::Item> { | ||
if let Some(unit) = E::get_at(self.accelerator) { | ||
self.accelerator += 1; | ||
Some(unit) | ||
} else { | ||
None | ||
} | ||
} | ||
} | ||
DasLixou marked this conversation as resolved.
Show resolved
Hide resolved
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.