Separate state crate (#13216)
# Objective
Extracts the state mechanisms into a new crate called "bevy_state".
This comes with a few goals:
- state wasn't really an inherent machinery of the ecs system, and so
keeping it within bevy_ecs felt forced
- by mixing it in with bevy_ecs, the maintainability of our more robust
state system was significantly compromised
moving state into a new crate makes it easier to encapsulate as it's own
feature, and easier to read and understand since it's no longer a
single, massive file.
## Solution
move the state-related elements from bevy_ecs to a new crate
## Testing
- Did you test these changes? If so, how? all the automated tests
migrated and passed, ran the pre-existing examples without changes to
validate.
---
## Migration Guide
Since bevy_state is now gated behind the `bevy_state` feature, projects
that use state but don't use the `default-features` will need to add
that feature flag.
Since it is no longer part of bevy_ecs, projects that use bevy_ecs
directly will need to manually pull in `bevy_state`, trigger the
StateTransition schedule, and handle any of the elements that bevy_app
currently sets up.
---------
Co-authored-by: Kristoffer Søholm <k.soeholm@gmail.com>
2024-05-09 18:06:05 +00:00
|
|
|
use proc_macro::TokenStream;
|
|
|
|
use quote::{format_ident, quote};
|
|
|
|
use syn::{parse_macro_input, spanned::Spanned, DeriveInput, Pat, Path, Result};
|
|
|
|
|
|
|
|
use crate::bevy_state_path;
|
|
|
|
|
2024-12-01 20:09:36 +00:00
|
|
|
pub const STATES: &str = "states";
|
|
|
|
pub const SCOPED_ENTITIES: &str = "scoped_entities";
|
|
|
|
|
|
|
|
struct StatesAttrs {
|
|
|
|
scoped_entities_enabled: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_states_attr(ast: &DeriveInput) -> Result<StatesAttrs> {
|
|
|
|
let mut attrs = StatesAttrs {
|
|
|
|
scoped_entities_enabled: false,
|
|
|
|
};
|
|
|
|
|
|
|
|
for attr in ast.attrs.iter() {
|
|
|
|
if attr.path().is_ident(STATES) {
|
|
|
|
attr.parse_nested_meta(|nested| {
|
|
|
|
if nested.path.is_ident(SCOPED_ENTITIES) {
|
|
|
|
attrs.scoped_entities_enabled = true;
|
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
Err(nested.error("Unsupported attribute"))
|
|
|
|
}
|
|
|
|
})?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(attrs)
|
|
|
|
}
|
|
|
|
|
Separate state crate (#13216)
# Objective
Extracts the state mechanisms into a new crate called "bevy_state".
This comes with a few goals:
- state wasn't really an inherent machinery of the ecs system, and so
keeping it within bevy_ecs felt forced
- by mixing it in with bevy_ecs, the maintainability of our more robust
state system was significantly compromised
moving state into a new crate makes it easier to encapsulate as it's own
feature, and easier to read and understand since it's no longer a
single, massive file.
## Solution
move the state-related elements from bevy_ecs to a new crate
## Testing
- Did you test these changes? If so, how? all the automated tests
migrated and passed, ran the pre-existing examples without changes to
validate.
---
## Migration Guide
Since bevy_state is now gated behind the `bevy_state` feature, projects
that use state but don't use the `default-features` will need to add
that feature flag.
Since it is no longer part of bevy_ecs, projects that use bevy_ecs
directly will need to manually pull in `bevy_state`, trigger the
StateTransition schedule, and handle any of the elements that bevy_app
currently sets up.
---------
Co-authored-by: Kristoffer Søholm <k.soeholm@gmail.com>
2024-05-09 18:06:05 +00:00
|
|
|
pub fn derive_states(input: TokenStream) -> TokenStream {
|
|
|
|
let ast = parse_macro_input!(input as DeriveInput);
|
|
|
|
|
2024-12-01 20:09:36 +00:00
|
|
|
let attrs = match parse_states_attr(&ast) {
|
|
|
|
Ok(attrs) => attrs,
|
|
|
|
Err(e) => return e.into_compile_error().into(),
|
|
|
|
};
|
|
|
|
|
Separate state crate (#13216)
# Objective
Extracts the state mechanisms into a new crate called "bevy_state".
This comes with a few goals:
- state wasn't really an inherent machinery of the ecs system, and so
keeping it within bevy_ecs felt forced
- by mixing it in with bevy_ecs, the maintainability of our more robust
state system was significantly compromised
moving state into a new crate makes it easier to encapsulate as it's own
feature, and easier to read and understand since it's no longer a
single, massive file.
## Solution
move the state-related elements from bevy_ecs to a new crate
## Testing
- Did you test these changes? If so, how? all the automated tests
migrated and passed, ran the pre-existing examples without changes to
validate.
---
## Migration Guide
Since bevy_state is now gated behind the `bevy_state` feature, projects
that use state but don't use the `default-features` will need to add
that feature flag.
Since it is no longer part of bevy_ecs, projects that use bevy_ecs
directly will need to manually pull in `bevy_state`, trigger the
StateTransition schedule, and handle any of the elements that bevy_app
currently sets up.
---------
Co-authored-by: Kristoffer Søholm <k.soeholm@gmail.com>
2024-05-09 18:06:05 +00:00
|
|
|
let generics = ast.generics;
|
|
|
|
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
|
|
|
|
|
|
|
let mut base_trait_path = bevy_state_path();
|
|
|
|
base_trait_path.segments.push(format_ident!("state").into());
|
|
|
|
|
|
|
|
let mut trait_path = base_trait_path.clone();
|
|
|
|
trait_path.segments.push(format_ident!("States").into());
|
|
|
|
|
|
|
|
let mut state_mutation_trait_path = base_trait_path.clone();
|
|
|
|
state_mutation_trait_path
|
|
|
|
.segments
|
|
|
|
.push(format_ident!("FreelyMutableState").into());
|
|
|
|
|
|
|
|
let struct_name = &ast.ident;
|
|
|
|
|
2024-12-01 20:09:36 +00:00
|
|
|
let scoped_entities_enabled = attrs.scoped_entities_enabled;
|
|
|
|
|
Separate state crate (#13216)
# Objective
Extracts the state mechanisms into a new crate called "bevy_state".
This comes with a few goals:
- state wasn't really an inherent machinery of the ecs system, and so
keeping it within bevy_ecs felt forced
- by mixing it in with bevy_ecs, the maintainability of our more robust
state system was significantly compromised
moving state into a new crate makes it easier to encapsulate as it's own
feature, and easier to read and understand since it's no longer a
single, massive file.
## Solution
move the state-related elements from bevy_ecs to a new crate
## Testing
- Did you test these changes? If so, how? all the automated tests
migrated and passed, ran the pre-existing examples without changes to
validate.
---
## Migration Guide
Since bevy_state is now gated behind the `bevy_state` feature, projects
that use state but don't use the `default-features` will need to add
that feature flag.
Since it is no longer part of bevy_ecs, projects that use bevy_ecs
directly will need to manually pull in `bevy_state`, trigger the
StateTransition schedule, and handle any of the elements that bevy_app
currently sets up.
---------
Co-authored-by: Kristoffer Søholm <k.soeholm@gmail.com>
2024-05-09 18:06:05 +00:00
|
|
|
quote! {
|
2024-12-01 20:09:36 +00:00
|
|
|
impl #impl_generics #trait_path for #struct_name #ty_generics #where_clause {
|
|
|
|
const SCOPED_ENTITIES_ENABLED: bool = #scoped_entities_enabled;
|
|
|
|
}
|
Separate state crate (#13216)
# Objective
Extracts the state mechanisms into a new crate called "bevy_state".
This comes with a few goals:
- state wasn't really an inherent machinery of the ecs system, and so
keeping it within bevy_ecs felt forced
- by mixing it in with bevy_ecs, the maintainability of our more robust
state system was significantly compromised
moving state into a new crate makes it easier to encapsulate as it's own
feature, and easier to read and understand since it's no longer a
single, massive file.
## Solution
move the state-related elements from bevy_ecs to a new crate
## Testing
- Did you test these changes? If so, how? all the automated tests
migrated and passed, ran the pre-existing examples without changes to
validate.
---
## Migration Guide
Since bevy_state is now gated behind the `bevy_state` feature, projects
that use state but don't use the `default-features` will need to add
that feature flag.
Since it is no longer part of bevy_ecs, projects that use bevy_ecs
directly will need to manually pull in `bevy_state`, trigger the
StateTransition schedule, and handle any of the elements that bevy_app
currently sets up.
---------
Co-authored-by: Kristoffer Søholm <k.soeholm@gmail.com>
2024-05-09 18:06:05 +00:00
|
|
|
|
|
|
|
impl #impl_generics #state_mutation_trait_path for #struct_name #ty_generics #where_clause {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.into()
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Source {
|
|
|
|
source_type: Path,
|
|
|
|
source_value: Pat,
|
|
|
|
}
|
|
|
|
|
2024-12-01 20:09:36 +00:00
|
|
|
fn parse_sources_attr(ast: &DeriveInput) -> Result<(StatesAttrs, Source)> {
|
Separate state crate (#13216)
# Objective
Extracts the state mechanisms into a new crate called "bevy_state".
This comes with a few goals:
- state wasn't really an inherent machinery of the ecs system, and so
keeping it within bevy_ecs felt forced
- by mixing it in with bevy_ecs, the maintainability of our more robust
state system was significantly compromised
moving state into a new crate makes it easier to encapsulate as it's own
feature, and easier to read and understand since it's no longer a
single, massive file.
## Solution
move the state-related elements from bevy_ecs to a new crate
## Testing
- Did you test these changes? If so, how? all the automated tests
migrated and passed, ran the pre-existing examples without changes to
validate.
---
## Migration Guide
Since bevy_state is now gated behind the `bevy_state` feature, projects
that use state but don't use the `default-features` will need to add
that feature flag.
Since it is no longer part of bevy_ecs, projects that use bevy_ecs
directly will need to manually pull in `bevy_state`, trigger the
StateTransition schedule, and handle any of the elements that bevy_app
currently sets up.
---------
Co-authored-by: Kristoffer Søholm <k.soeholm@gmail.com>
2024-05-09 18:06:05 +00:00
|
|
|
let mut result = ast
|
|
|
|
.attrs
|
|
|
|
.iter()
|
|
|
|
.filter(|a| a.path().is_ident("source"))
|
|
|
|
.map(|meta| {
|
|
|
|
let mut source = None;
|
|
|
|
let value = meta.parse_nested_meta(|nested| {
|
|
|
|
let source_type = nested.path.clone();
|
|
|
|
let source_value = Pat::parse_multi(nested.value()?)?;
|
|
|
|
source = Some(Source {
|
|
|
|
source_type,
|
|
|
|
source_value,
|
|
|
|
});
|
|
|
|
Ok(())
|
|
|
|
});
|
|
|
|
match source {
|
|
|
|
Some(value) => Ok(value),
|
|
|
|
None => match value {
|
|
|
|
Ok(_) => Err(syn::Error::new(
|
|
|
|
ast.span(),
|
|
|
|
"Couldn't parse SubStates source",
|
|
|
|
)),
|
|
|
|
Err(e) => Err(e),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<Result<Vec<_>>>()?;
|
|
|
|
|
|
|
|
if result.len() > 1 {
|
|
|
|
return Err(syn::Error::new(
|
|
|
|
ast.span(),
|
|
|
|
"Only one source is allowed for SubStates",
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2024-12-01 20:09:36 +00:00
|
|
|
let states_attrs = parse_states_attr(ast)?;
|
|
|
|
|
Separate state crate (#13216)
# Objective
Extracts the state mechanisms into a new crate called "bevy_state".
This comes with a few goals:
- state wasn't really an inherent machinery of the ecs system, and so
keeping it within bevy_ecs felt forced
- by mixing it in with bevy_ecs, the maintainability of our more robust
state system was significantly compromised
moving state into a new crate makes it easier to encapsulate as it's own
feature, and easier to read and understand since it's no longer a
single, massive file.
## Solution
move the state-related elements from bevy_ecs to a new crate
## Testing
- Did you test these changes? If so, how? all the automated tests
migrated and passed, ran the pre-existing examples without changes to
validate.
---
## Migration Guide
Since bevy_state is now gated behind the `bevy_state` feature, projects
that use state but don't use the `default-features` will need to add
that feature flag.
Since it is no longer part of bevy_ecs, projects that use bevy_ecs
directly will need to manually pull in `bevy_state`, trigger the
StateTransition schedule, and handle any of the elements that bevy_app
currently sets up.
---------
Co-authored-by: Kristoffer Søholm <k.soeholm@gmail.com>
2024-05-09 18:06:05 +00:00
|
|
|
let Some(result) = result.pop() else {
|
|
|
|
return Err(syn::Error::new(ast.span(), "SubStates require a source"));
|
|
|
|
};
|
|
|
|
|
2024-12-01 20:09:36 +00:00
|
|
|
Ok((states_attrs, result))
|
Separate state crate (#13216)
# Objective
Extracts the state mechanisms into a new crate called "bevy_state".
This comes with a few goals:
- state wasn't really an inherent machinery of the ecs system, and so
keeping it within bevy_ecs felt forced
- by mixing it in with bevy_ecs, the maintainability of our more robust
state system was significantly compromised
moving state into a new crate makes it easier to encapsulate as it's own
feature, and easier to read and understand since it's no longer a
single, massive file.
## Solution
move the state-related elements from bevy_ecs to a new crate
## Testing
- Did you test these changes? If so, how? all the automated tests
migrated and passed, ran the pre-existing examples without changes to
validate.
---
## Migration Guide
Since bevy_state is now gated behind the `bevy_state` feature, projects
that use state but don't use the `default-features` will need to add
that feature flag.
Since it is no longer part of bevy_ecs, projects that use bevy_ecs
directly will need to manually pull in `bevy_state`, trigger the
StateTransition schedule, and handle any of the elements that bevy_app
currently sets up.
---------
Co-authored-by: Kristoffer Søholm <k.soeholm@gmail.com>
2024-05-09 18:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn derive_substates(input: TokenStream) -> TokenStream {
|
|
|
|
let ast = parse_macro_input!(input as DeriveInput);
|
2024-12-01 20:09:36 +00:00
|
|
|
let (states_attrs, sources) =
|
|
|
|
parse_sources_attr(&ast).expect("Failed to parse substate sources");
|
Separate state crate (#13216)
# Objective
Extracts the state mechanisms into a new crate called "bevy_state".
This comes with a few goals:
- state wasn't really an inherent machinery of the ecs system, and so
keeping it within bevy_ecs felt forced
- by mixing it in with bevy_ecs, the maintainability of our more robust
state system was significantly compromised
moving state into a new crate makes it easier to encapsulate as it's own
feature, and easier to read and understand since it's no longer a
single, massive file.
## Solution
move the state-related elements from bevy_ecs to a new crate
## Testing
- Did you test these changes? If so, how? all the automated tests
migrated and passed, ran the pre-existing examples without changes to
validate.
---
## Migration Guide
Since bevy_state is now gated behind the `bevy_state` feature, projects
that use state but don't use the `default-features` will need to add
that feature flag.
Since it is no longer part of bevy_ecs, projects that use bevy_ecs
directly will need to manually pull in `bevy_state`, trigger the
StateTransition schedule, and handle any of the elements that bevy_app
currently sets up.
---------
Co-authored-by: Kristoffer Søholm <k.soeholm@gmail.com>
2024-05-09 18:06:05 +00:00
|
|
|
|
|
|
|
let generics = ast.generics;
|
|
|
|
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
|
|
|
|
|
|
|
let mut base_trait_path = bevy_state_path();
|
|
|
|
base_trait_path.segments.push(format_ident!("state").into());
|
|
|
|
|
|
|
|
let mut trait_path = base_trait_path.clone();
|
|
|
|
trait_path.segments.push(format_ident!("SubStates").into());
|
|
|
|
|
|
|
|
let mut state_set_trait_path = base_trait_path.clone();
|
|
|
|
state_set_trait_path
|
|
|
|
.segments
|
|
|
|
.push(format_ident!("StateSet").into());
|
|
|
|
|
|
|
|
let mut state_trait_path = base_trait_path.clone();
|
|
|
|
state_trait_path
|
|
|
|
.segments
|
|
|
|
.push(format_ident!("States").into());
|
|
|
|
|
|
|
|
let mut state_mutation_trait_path = base_trait_path.clone();
|
|
|
|
state_mutation_trait_path
|
|
|
|
.segments
|
|
|
|
.push(format_ident!("FreelyMutableState").into());
|
|
|
|
|
|
|
|
let struct_name = &ast.ident;
|
|
|
|
|
|
|
|
let source_state_type = sources.source_type;
|
|
|
|
let source_state_value = sources.source_value;
|
|
|
|
|
2024-12-01 20:09:36 +00:00
|
|
|
let scoped_entities_enabled = states_attrs.scoped_entities_enabled;
|
|
|
|
|
Separate state crate (#13216)
# Objective
Extracts the state mechanisms into a new crate called "bevy_state".
This comes with a few goals:
- state wasn't really an inherent machinery of the ecs system, and so
keeping it within bevy_ecs felt forced
- by mixing it in with bevy_ecs, the maintainability of our more robust
state system was significantly compromised
moving state into a new crate makes it easier to encapsulate as it's own
feature, and easier to read and understand since it's no longer a
single, massive file.
## Solution
move the state-related elements from bevy_ecs to a new crate
## Testing
- Did you test these changes? If so, how? all the automated tests
migrated and passed, ran the pre-existing examples without changes to
validate.
---
## Migration Guide
Since bevy_state is now gated behind the `bevy_state` feature, projects
that use state but don't use the `default-features` will need to add
that feature flag.
Since it is no longer part of bevy_ecs, projects that use bevy_ecs
directly will need to manually pull in `bevy_state`, trigger the
StateTransition schedule, and handle any of the elements that bevy_app
currently sets up.
---------
Co-authored-by: Kristoffer Søholm <k.soeholm@gmail.com>
2024-05-09 18:06:05 +00:00
|
|
|
let result = quote! {
|
|
|
|
impl #impl_generics #trait_path for #struct_name #ty_generics #where_clause {
|
|
|
|
type SourceStates = #source_state_type;
|
|
|
|
|
|
|
|
fn should_exist(sources: #source_state_type) -> Option<Self> {
|
2024-06-02 13:36:44 +00:00
|
|
|
matches!(sources, #source_state_value).then_some(Self::default())
|
Separate state crate (#13216)
# Objective
Extracts the state mechanisms into a new crate called "bevy_state".
This comes with a few goals:
- state wasn't really an inherent machinery of the ecs system, and so
keeping it within bevy_ecs felt forced
- by mixing it in with bevy_ecs, the maintainability of our more robust
state system was significantly compromised
moving state into a new crate makes it easier to encapsulate as it's own
feature, and easier to read and understand since it's no longer a
single, massive file.
## Solution
move the state-related elements from bevy_ecs to a new crate
## Testing
- Did you test these changes? If so, how? all the automated tests
migrated and passed, ran the pre-existing examples without changes to
validate.
---
## Migration Guide
Since bevy_state is now gated behind the `bevy_state` feature, projects
that use state but don't use the `default-features` will need to add
that feature flag.
Since it is no longer part of bevy_ecs, projects that use bevy_ecs
directly will need to manually pull in `bevy_state`, trigger the
StateTransition schedule, and handle any of the elements that bevy_app
currently sets up.
---------
Co-authored-by: Kristoffer Søholm <k.soeholm@gmail.com>
2024-05-09 18:06:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl #impl_generics #state_trait_path for #struct_name #ty_generics #where_clause {
|
|
|
|
const DEPENDENCY_DEPTH : usize = <Self as #trait_path>::SourceStates::SET_DEPENDENCY_DEPTH + 1;
|
2024-12-01 20:09:36 +00:00
|
|
|
|
|
|
|
const SCOPED_ENTITIES_ENABLED: bool = #scoped_entities_enabled;
|
Separate state crate (#13216)
# Objective
Extracts the state mechanisms into a new crate called "bevy_state".
This comes with a few goals:
- state wasn't really an inherent machinery of the ecs system, and so
keeping it within bevy_ecs felt forced
- by mixing it in with bevy_ecs, the maintainability of our more robust
state system was significantly compromised
moving state into a new crate makes it easier to encapsulate as it's own
feature, and easier to read and understand since it's no longer a
single, massive file.
## Solution
move the state-related elements from bevy_ecs to a new crate
## Testing
- Did you test these changes? If so, how? all the automated tests
migrated and passed, ran the pre-existing examples without changes to
validate.
---
## Migration Guide
Since bevy_state is now gated behind the `bevy_state` feature, projects
that use state but don't use the `default-features` will need to add
that feature flag.
Since it is no longer part of bevy_ecs, projects that use bevy_ecs
directly will need to manually pull in `bevy_state`, trigger the
StateTransition schedule, and handle any of the elements that bevy_app
currently sets up.
---------
Co-authored-by: Kristoffer Søholm <k.soeholm@gmail.com>
2024-05-09 18:06:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl #impl_generics #state_mutation_trait_path for #struct_name #ty_generics #where_clause {
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// panic!("Got Result\n{}", result.to_string());
|
|
|
|
|
|
|
|
result.into()
|
|
|
|
}
|