refactor: hardcoded proc macro for GameState supertraits

This commit is contained in:
nativerv
2024-02-19 03:14:32 +03:00
parent 25b3580384
commit 43be3da536
6 changed files with 154 additions and 55 deletions
Generated
+10
View File
@@ -448,6 +448,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"bevy-inspector-egui", "bevy-inspector-egui",
"bevy_app", "bevy_app",
"bevy_controls_macros",
"bevy_derive", "bevy_derive",
"bevy_ecs", "bevy_ecs",
"bevy_input", "bevy_input",
@@ -470,6 +471,15 @@ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]]
name = "bevy_controls_macros"
version = "0.1.0"
dependencies = [
"env_logger",
"quote",
"syn 1.0.109",
]
[[package]] [[package]]
name = "bevy_core" name = "bevy_core"
version = "0.12.1" version = "0.12.1"
+1
View File
@@ -21,6 +21,7 @@ log = "0.4.20"
serde = { version = "1.0.194", optional = true } serde = { version = "1.0.194", optional = true }
strum = "0.25.0" strum = "0.25.0"
strum_macros = "0.25.3" strum_macros = "0.25.3"
bevy_controls_macros = { path = "macros", version = "0.1.0" }
[dev-dependencies] [dev-dependencies]
env_logger = "0.10.1" env_logger = "0.10.1"
+16
View File
@@ -0,0 +1,16 @@
[package]
name = "bevy_controls_macros"
version = "0.1.0"
edition = "2021"
[lib]
proc-macro = true
[dependencies]
#bevy_controls = { path = "./../bevy_controls" }
syn = { version = "1.0", features = [ "full", "extra-traits" ] }
quote = "1.0"
[dev-dependencies]
env_logger = "0.10.1"
+116
View File
@@ -0,0 +1,116 @@
extern crate proc_macro;
use proc_macro::TokenStream;
use std::collections::HashMap;
//use quote::quote;
use syn::{
parse::{Parse, ParseStream, Result},
parse_macro_input,
punctuated::Punctuated,
token::{Bracket, Add},
Expr, Ident, ItemTrait, Token, TypeParamBound, LitStr,
};
use quote::quote;
// #[cfg_feature_trait_bounds {
// "serialize" => Serialize + DeserializeOwned,
// "reflect" => Reflect + TypePath + FromReflect,
// "inspector-egui" => InspectorOptionsType,
// }]
type RuleKey = LitStr;
#[derive(Debug)]
struct FeatureTraitBoundMap(HashMap<RuleKey, Punctuated<TypeParamBound, Token![+]>>);
impl Parse for FeatureTraitBoundMap {
fn parse(input: ParseStream) -> Result<Self> {
let mut rules = HashMap::new();
loop {
let condition: RuleKey = input.parse()?;
let _arrow = input.parse::<Token![=>]>()?;
let supertraits = {
let mut supertraits = Punctuated::new();
loop {
supertraits.push_value(input.parse()?);
if !input.peek(Token![+]) {
break;
}
supertraits.push_punct(input.parse()?);
if input.peek(Token![,]) {
break;
}
}
supertraits
};
let _comma = input.parse::<Token![,]>();
rules.insert(condition, supertraits);
if input.is_empty() {
break;
}
}
Ok(FeatureTraitBoundMap(rules))
}
}
#[proc_macro_attribute]
pub fn cfg_feature_trait_bounds(attr: TokenStream, input: TokenStream) -> TokenStream {
let rules = parse_macro_input!(attr as FeatureTraitBoundMap);
let input = parse_macro_input!(input as ItemTrait);
dbg!(std::env::vars().map(|(key, _)| key).collect::<Vec<_>>());
// let code = quote! {
// trait #name: #rules {}
// };
//
// dbg!(code);
TokenStream::new()
}
#[proc_macro_attribute]
pub fn game_state_supertraits(_attrs: TokenStream, input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as ItemTrait);
let mut bounds = Vec::new();
if cfg!(feature = "serialize") {
bounds.push(quote! { serde::Serialize });
bounds.push(quote! { serde::de::DeserializeOwned });
};
if cfg!(feature = "reflect") {
bounds.push(quote! { bevy_reflect::Reflect });
bounds.push(quote! { bevy_reflect::TypePath });
bounds.push(quote! { bevy_reflect::FromReflect });
};
if cfg!(feature = "inspector-egui") {
bounds.push(quote! { bevy_inspector_egui::inspector_options::InspectorOptionsType });
};
let ItemTrait {
ident,
vis,
items,
supertraits: bounds_old,
..
} = input;
let bounds_old = bounds_old.iter().collect::<Vec<_>>();
let out = quote! {
#vis trait #ident: #(#bounds_old)+* + #(#bounds)+* { #(#items)* }
};
// dbg!(&out);
// dbg!(out.to_string());
TokenStream::from(out)
}
+11 -38
View File
@@ -10,6 +10,7 @@ use strum::IntoEnumIterator;
use bevy_reflect::{FromReflect, Reflect, TypePath}; use bevy_reflect::{FromReflect, Reflect, TypePath};
#[cfg(feature = "serialize")] #[cfg(feature = "serialize")]
use serde::{de::DeserializeOwned, Serialize}; use serde::{de::DeserializeOwned, Serialize};
use bevy_controls_macros::{cfg_feature_trait_bounds, game_state_supertraits};
use crate::resource::PlayerInputs; use crate::resource::PlayerInputs;
@@ -27,11 +28,6 @@ pub trait ActionInner:
{ {
} }
pub trait GameStateInner:
'static + std::marker::Sync + std::marker::Send + States + Default + std::fmt::Debug
{
}
pub trait InputsContainerInner<A: Action>: pub trait InputsContainerInner<A: Action>:
'static + std::marker::Sync + std::marker::Send + Resource + Default + std::fmt::Debug 'static + std::marker::Sync + std::marker::Send + Resource + Default + std::fmt::Debug
{ {
@@ -91,39 +87,16 @@ pub trait Action: ActionInner + SerializeImpl + ReflectImpl + InspectorEguiImpl
// ===== GameState ===== // ===== GameState =====
// SAFETY: inspector-egui includes reflect // SAFETY: inspector-egui includes reflect
#[cfg(all( #[game_state_supertraits]
not(feature = "serialize"), pub trait GameState:
not(feature = "reflect"), 'static
not(feature = "inspector-egui") + std::marker::Sync
))] + std::marker::Send
pub trait GameState: GameStateInner {} + States
+ Default
#[cfg(all( + std::fmt::Debug
feature = "serialize", {
not(feature = "reflect"), }
not(feature = "inspector-egui")
))]
pub trait GameState: GameStateInner + SerializeImpl {}
#[cfg(all(
not(feature = "serialize"),
feature = "reflect",
not(feature = "inspector-egui")
))]
pub trait GameState: GameStateInner + ReflectImpl {}
#[cfg(all(
feature = "serialize",
feature = "reflect",
not(feature = "inspector-egui")
))]
pub trait GameState: GameStateInner + SerializeImpl + ReflectImpl {}
#[cfg(all(not(feature = "serialize"), feature = "inspector-egui"))]
pub trait GameState: GameStateInner + ReflectImpl + InspectorEguiImpl {}
#[cfg(all(feature = "serialize", feature = "inspector-egui"))]
pub trait GameState: GameStateInner + SerializeImpl + ReflectImpl + InspectorEguiImpl {}
// ===== InputsContainer ===== // ===== InputsContainer =====
// SAFETY: inspector-egui includes reflect // SAFETY: inspector-egui includes reflect
-17
View File
@@ -6,24 +6,7 @@ edition = "2021"
[lib] [lib]
proc-macro = true proc-macro = true
# [features]
# default = []
# serialize = ["bevy_input/serialize", "serde"]
# reflect = ["dep:bevy_reflect"]
# inspector-egui = ["reflect", "dep:bevy-inspector-egui"]
[dependencies] [dependencies]
# bevy-inspector-egui = { version = "0.22.1", optional = true }
# bevy_app = "0.12.1"
# bevy_derive = "0.12.1"
# bevy_ecs = "0.12.1"
# bevy_input = "0.12.1"
# bevy_reflect = { version = "0.12.1", optional = true }
# bevy_utils = "0.12.1"
# log = "0.4.20"
# serde = { version = "1.0.194", optional = true }
# strum = "0.25.0"
# strum_macros = "0.25.3"
bevy_controls = { path = "./../bevy_controls" } bevy_controls = { path = "./../bevy_controls" }
syn = "1.0" syn = "1.0"
quote = "1.0" quote = "1.0"