Skip to content

Commit

Permalink
States derive macro
Browse files Browse the repository at this point in the history
  • Loading branch information
SpecificProtagonist committed Feb 7, 2023
1 parent ea2ecd4 commit 3194fc9
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 52 deletions.
6 changes: 6 additions & 0 deletions crates/bevy_ecs/macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ extern crate proc_macro;
mod component;
mod fetch;
mod set;
mod states;

use crate::{fetch::derive_world_query_impl, set::derive_set};
use bevy_macro_utils::{derive_boxed_label, get_named_struct_fields, BevyManifest};
Expand Down Expand Up @@ -558,3 +559,8 @@ pub fn derive_resource(input: TokenStream) -> TokenStream {
pub fn derive_component(input: TokenStream) -> TokenStream {
component::derive_component(input)
}

#[proc_macro_derive(States)]
pub fn derive_states(input: TokenStream) -> TokenStream {
states::derive_states(input)
}
38 changes: 38 additions & 0 deletions crates/bevy_ecs/macros/src/states.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use proc_macro::{Span, TokenStream};
use quote::quote;
use syn::{parse_macro_input, Data::Enum, DeriveInput};

pub fn derive_states(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let error = || {
syn::Error::new(
Span::call_site().into(),
"derive(States) only supports fieldless enums",
)
.into_compile_error()
.into()
};
let Enum(enumeration) = ast.data else {
return error();
};
if enumeration.variants.iter().any(|v| !v.fields.is_empty()) {
return error();
}

let generics = ast.generics;
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

let struct_name = &ast.ident;
let idents = enumeration.variants.iter().map(|v| &v.ident);
let len = idents.len();

quote! {
impl #impl_generics bevy::ecs::schedule::States for #struct_name #ty_generics #where_clause {
type Iter = std::array::IntoIter<Self, #len>;

fn variants() -> Self::Iter {
[#(Self::#idents,)*].into_iter()
}
}
}.into()
}
1 change: 1 addition & 0 deletions crates/bevy_ecs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ pub mod prelude {
},
world::{FromWorld, World},
};
pub use bevy_ecs_macros::States;
}

pub use bevy_ecs_macros::all_tuples;
Expand Down
10 changes: 1 addition & 9 deletions crates/bevy_ecs/src/schedule/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,14 @@ use crate::world::World;
/// ```rust
/// use bevy_ecs::prelude::States;
///
/// #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default)]
/// #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, States)]
/// enum GameState {
/// #[default]
/// MainMenu,
/// SettingsMenu,
/// InGame,
/// }
///
/// impl States for GameState {
/// type Iter = std::array::IntoIter<GameState, 3>;
///
/// fn variants() -> Self::Iter {
/// [GameState::MainMenu, GameState::SettingsMenu, GameState::InGame].into_iter()
/// }
/// }
///
/// ```
pub trait States: 'static + Send + Sync + Clone + PartialEq + Eq + Hash + Debug + Default {
type Iter: Iterator<Item = Self>;
Expand Down
10 changes: 1 addition & 9 deletions examples/ecs/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,13 @@ fn main() {
.run();
}

#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash)]
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash, States)]
enum AppState {
#[default]
Menu,
InGame,
}

impl States for AppState {
type Iter = std::array::IntoIter<AppState, 2>;

fn variants() -> Self::Iter {
[AppState::Menu, AppState::InGame].into_iter()
}
}

#[derive(Resource)]
struct MenuData {
button_entity: Entity,
Expand Down
10 changes: 1 addition & 9 deletions examples/games/alien_cake_addict.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,13 @@ use std::f32::consts::PI;
use bevy::prelude::*;
use rand::Rng;

#[derive(Clone, Eq, PartialEq, Debug, Hash, Default)]
#[derive(Clone, Eq, PartialEq, Debug, Hash, Default, States)]
enum GameState {
#[default]
Playing,
GameOver,
}

impl States for GameState {
type Iter = std::array::IntoIter<GameState, 2>;

fn variants() -> Self::Iter {
[GameState::Playing, GameState::GameOver].into_iter()
}
}

#[derive(Resource)]
struct BonusSpawnTimer(Timer);

Expand Down
27 changes: 2 additions & 25 deletions examples/games/game_menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,14 @@ use bevy::prelude::*;
const TEXT_COLOR: Color = Color::rgb(0.9, 0.9, 0.9);

// Enum that will be used as a global state for the game
#[derive(Clone, Copy, Default, Eq, PartialEq, Debug, Hash)]
#[derive(Clone, Copy, Default, Eq, PartialEq, Debug, Hash, States)]
enum GameState {
#[default]
Splash,
Menu,
Game,
}

impl States for GameState {
type Iter = std::array::IntoIter<GameState, 3>;

fn variants() -> Self::Iter {
[GameState::Splash, GameState::Menu, GameState::Game].into_iter()
}
}

// One of the two settings that can be set through the menu. It will be a resource in the app
#[derive(Resource, Debug, Component, PartialEq, Eq, Clone, Copy)]
enum DisplayQuality {
Expand Down Expand Up @@ -312,7 +304,7 @@ mod menu {
}

// State used for the current menu screen
#[derive(Clone, Copy, Default, Eq, PartialEq, Debug, Hash)]
#[derive(Clone, Copy, Default, Eq, PartialEq, Debug, Hash, States)]
enum MenuState {
Main,
Settings,
Expand All @@ -322,21 +314,6 @@ mod menu {
Disabled,
}

impl States for MenuState {
type Iter = std::array::IntoIter<MenuState, 5>;

fn variants() -> Self::Iter {
[
MenuState::Main,
MenuState::Settings,
MenuState::SettingsDisplay,
MenuState::SettingsSound,
MenuState::Disabled,
]
.into_iter()
}
}

// Tag component used to tag entities added on the main menu screen
#[derive(Component)]
struct OnMainMenuScreen;
Expand Down

0 comments on commit 3194fc9

Please sign in to comment.