Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_state/macros/src/states.rs
6596 views
1
use proc_macro::TokenStream;
2
use quote::{format_ident, quote};
3
use syn::{parse_macro_input, spanned::Spanned, DeriveInput, Pat, Path, Result};
4
5
use crate::bevy_state_path;
6
7
pub fn derive_states(input: TokenStream) -> TokenStream {
8
let ast = parse_macro_input!(input as DeriveInput);
9
10
let generics = ast.generics;
11
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
12
13
let mut base_trait_path = bevy_state_path();
14
base_trait_path.segments.push(format_ident!("state").into());
15
16
let mut trait_path = base_trait_path.clone();
17
trait_path.segments.push(format_ident!("States").into());
18
19
let mut state_mutation_trait_path = base_trait_path.clone();
20
state_mutation_trait_path
21
.segments
22
.push(format_ident!("FreelyMutableState").into());
23
24
let struct_name = &ast.ident;
25
26
quote! {
27
impl #impl_generics #trait_path for #struct_name #ty_generics #where_clause {
28
}
29
30
impl #impl_generics #state_mutation_trait_path for #struct_name #ty_generics #where_clause {
31
}
32
}
33
.into()
34
}
35
36
struct Source {
37
source_type: Path,
38
source_value: Pat,
39
}
40
41
fn parse_sources_attr(ast: &DeriveInput) -> Result<Source> {
42
let mut result = ast
43
.attrs
44
.iter()
45
.filter(|a| a.path().is_ident("source"))
46
.map(|meta| {
47
let mut source = None;
48
let value = meta.parse_nested_meta(|nested| {
49
let source_type = nested.path.clone();
50
let source_value = Pat::parse_multi(nested.value()?)?;
51
source = Some(Source {
52
source_type,
53
source_value,
54
});
55
Ok(())
56
});
57
match source {
58
Some(value) => Ok(value),
59
None => match value {
60
Ok(_) => Err(syn::Error::new(
61
ast.span(),
62
"Couldn't parse SubStates source",
63
)),
64
Err(e) => Err(e),
65
},
66
}
67
})
68
.collect::<Result<Vec<_>>>()?;
69
70
if result.len() > 1 {
71
return Err(syn::Error::new(
72
ast.span(),
73
"Only one source is allowed for SubStates",
74
));
75
}
76
77
let Some(result) = result.pop() else {
78
return Err(syn::Error::new(ast.span(), "SubStates require a source"));
79
};
80
81
Ok(result)
82
}
83
84
pub fn derive_substates(input: TokenStream) -> TokenStream {
85
let ast = parse_macro_input!(input as DeriveInput);
86
let sources = parse_sources_attr(&ast).expect("Failed to parse substate sources");
87
88
let generics = ast.generics;
89
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
90
91
let mut base_trait_path = bevy_state_path();
92
base_trait_path.segments.push(format_ident!("state").into());
93
94
let mut trait_path = base_trait_path.clone();
95
trait_path.segments.push(format_ident!("SubStates").into());
96
97
let mut state_set_trait_path = base_trait_path.clone();
98
state_set_trait_path
99
.segments
100
.push(format_ident!("StateSet").into());
101
102
let mut state_trait_path = base_trait_path.clone();
103
state_trait_path
104
.segments
105
.push(format_ident!("States").into());
106
107
let mut state_mutation_trait_path = base_trait_path.clone();
108
state_mutation_trait_path
109
.segments
110
.push(format_ident!("FreelyMutableState").into());
111
112
let struct_name = &ast.ident;
113
114
let source_state_type = sources.source_type;
115
let source_state_value = sources.source_value;
116
117
let result = quote! {
118
impl #impl_generics #trait_path for #struct_name #ty_generics #where_clause {
119
type SourceStates = #source_state_type;
120
121
fn should_exist(sources: #source_state_type) -> Option<Self> {
122
matches!(sources, #source_state_value).then_some(Self::default())
123
}
124
}
125
126
impl #impl_generics #state_trait_path for #struct_name #ty_generics #where_clause {
127
const DEPENDENCY_DEPTH : usize = <Self as #trait_path>::SourceStates::SET_DEPENDENCY_DEPTH + 1;
128
}
129
130
impl #impl_generics #state_mutation_trait_path for #struct_name #ty_generics #where_clause {
131
}
132
};
133
134
// panic!("Got Result\n{}", result.to_string());
135
136
result.into()
137
}
138
139