Skip to content

Commit 1291879

Browse files
States derive macro
1 parent ea2ecd4 commit 1291879

File tree

7 files changed

+50
-52
lines changed

7 files changed

+50
-52
lines changed

crates/bevy_ecs/macros/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ extern crate proc_macro;
33
mod component;
44
mod fetch;
55
mod set;
6+
mod states;
67

78
use crate::{fetch::derive_world_query_impl, set::derive_set};
89
use bevy_macro_utils::{derive_boxed_label, get_named_struct_fields, BevyManifest};
@@ -558,3 +559,8 @@ pub fn derive_resource(input: TokenStream) -> TokenStream {
558559
pub fn derive_component(input: TokenStream) -> TokenStream {
559560
component::derive_component(input)
560561
}
562+
563+
#[proc_macro_derive(States)]
564+
pub fn derive_states(input: TokenStream) -> TokenStream {
565+
states::derive_states(input)
566+
}

crates/bevy_ecs/macros/src/states.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use proc_macro::{Span, TokenStream};
2+
use quote::quote;
3+
use syn::{parse_macro_input, Data::Enum, DeriveInput};
4+
5+
pub fn derive_states(input: TokenStream) -> TokenStream {
6+
let ast = parse_macro_input!(input as DeriveInput);
7+
let error = || {
8+
syn::Error::new(
9+
Span::call_site().into(),
10+
"derive(States) only supports fieldless enums",
11+
)
12+
.into_compile_error()
13+
.into()
14+
};
15+
let Enum(enumeration) = ast.data else {
16+
return error();
17+
};
18+
if enumeration.variants.iter().any(|v| !v.fields.is_empty()) {
19+
return error();
20+
}
21+
22+
let generics = ast.generics;
23+
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
24+
25+
let struct_name = &ast.ident;
26+
let idents = enumeration.variants.iter().map(|v| &v.ident);
27+
let len = idents.len();
28+
29+
quote! {
30+
impl #impl_generics bevy::ecs::schedule_v3::States for #struct_name #ty_generics #where_clause {
31+
type Iter = std::array::IntoIter<Self, #len>;
32+
33+
fn variants() -> Self::Iter {
34+
[#(Self::#idents,)*].into_iter()
35+
}
36+
}
37+
}.into()
38+
}

crates/bevy_ecs/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ pub mod prelude {
4848
},
4949
world::{FromWorld, World},
5050
};
51+
pub use bevy_ecs_macros::States;
5152
}
5253

5354
pub use bevy_ecs_macros::all_tuples;

crates/bevy_ecs/src/schedule/state.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,14 @@ use crate::world::World;
2525
/// ```rust
2626
/// use bevy_ecs::prelude::States;
2727
///
28-
/// #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default)]
28+
/// #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, States)]
2929
/// enum GameState {
3030
/// #[default]
3131
/// MainMenu,
3232
/// SettingsMenu,
3333
/// InGame,
3434
/// }
3535
///
36-
/// impl States for GameState {
37-
/// type Iter = std::array::IntoIter<GameState, 3>;
38-
///
39-
/// fn variants() -> Self::Iter {
40-
/// [GameState::MainMenu, GameState::SettingsMenu, GameState::InGame].into_iter()
41-
/// }
42-
/// }
43-
///
4436
/// ```
4537
pub trait States: 'static + Send + Sync + Clone + PartialEq + Eq + Hash + Debug + Default {
4638
type Iter: Iterator<Item = Self>;

examples/ecs/state.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,13 @@ fn main() {
2525
.run();
2626
}
2727

28-
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash)]
28+
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash, States)]
2929
enum AppState {
3030
#[default]
3131
Menu,
3232
InGame,
3333
}
3434

35-
impl States for AppState {
36-
type Iter = std::array::IntoIter<AppState, 2>;
37-
38-
fn variants() -> Self::Iter {
39-
[AppState::Menu, AppState::InGame].into_iter()
40-
}
41-
}
42-
4335
#[derive(Resource)]
4436
struct MenuData {
4537
button_entity: Entity,

examples/games/alien_cake_addict.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,13 @@ use std::f32::consts::PI;
55
use bevy::prelude::*;
66
use rand::Rng;
77

8-
#[derive(Clone, Eq, PartialEq, Debug, Hash, Default)]
8+
#[derive(Clone, Eq, PartialEq, Debug, Hash, Default, States)]
99
enum GameState {
1010
#[default]
1111
Playing,
1212
GameOver,
1313
}
1414

15-
impl States for GameState {
16-
type Iter = std::array::IntoIter<GameState, 2>;
17-
18-
fn variants() -> Self::Iter {
19-
[GameState::Playing, GameState::GameOver].into_iter()
20-
}
21-
}
22-
2315
#[derive(Resource)]
2416
struct BonusSpawnTimer(Timer);
2517

examples/games/game_menu.rs

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,14 @@ use bevy::prelude::*;
77
const TEXT_COLOR: Color = Color::rgb(0.9, 0.9, 0.9);
88

99
// Enum that will be used as a global state for the game
10-
#[derive(Clone, Copy, Default, Eq, PartialEq, Debug, Hash)]
10+
#[derive(Clone, Copy, Default, Eq, PartialEq, Debug, Hash, States)]
1111
enum GameState {
1212
#[default]
1313
Splash,
1414
Menu,
1515
Game,
1616
}
1717

18-
impl States for GameState {
19-
type Iter = std::array::IntoIter<GameState, 3>;
20-
21-
fn variants() -> Self::Iter {
22-
[GameState::Splash, GameState::Menu, GameState::Game].into_iter()
23-
}
24-
}
25-
2618
// One of the two settings that can be set through the menu. It will be a resource in the app
2719
#[derive(Resource, Debug, Component, PartialEq, Eq, Clone, Copy)]
2820
enum DisplayQuality {
@@ -312,7 +304,7 @@ mod menu {
312304
}
313305

314306
// State used for the current menu screen
315-
#[derive(Clone, Copy, Default, Eq, PartialEq, Debug, Hash)]
307+
#[derive(Clone, Copy, Default, Eq, PartialEq, Debug, Hash, States)]
316308
enum MenuState {
317309
Main,
318310
Settings,
@@ -322,21 +314,6 @@ mod menu {
322314
Disabled,
323315
}
324316

325-
impl States for MenuState {
326-
type Iter = std::array::IntoIter<MenuState, 5>;
327-
328-
fn variants() -> Self::Iter {
329-
[
330-
MenuState::Main,
331-
MenuState::Settings,
332-
MenuState::SettingsDisplay,
333-
MenuState::SettingsSound,
334-
MenuState::Disabled,
335-
]
336-
.into_iter()
337-
}
338-
}
339-
340317
// Tag component used to tag entities added on the main menu screen
341318
#[derive(Component)]
342319
struct OnMainMenuScreen;

0 commit comments

Comments
 (0)