refactor: hardcoded proc macro for GameState supertraits
This commit is contained in:
@@ -21,6 +21,7 @@ log = "0.4.20"
|
||||
serde = { version = "1.0.194", optional = true }
|
||||
strum = "0.25.0"
|
||||
strum_macros = "0.25.3"
|
||||
bevy_controls_macros = { path = "macros", version = "0.1.0" }
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = "0.10.1"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -10,6 +10,7 @@ use strum::IntoEnumIterator;
|
||||
use bevy_reflect::{FromReflect, Reflect, TypePath};
|
||||
#[cfg(feature = "serialize")]
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use bevy_controls_macros::{cfg_feature_trait_bounds, game_state_supertraits};
|
||||
|
||||
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>:
|
||||
'static + std::marker::Sync + std::marker::Send + Resource + Default + std::fmt::Debug
|
||||
{
|
||||
@@ -91,39 +87,16 @@ pub trait Action: ActionInner + SerializeImpl + ReflectImpl + InspectorEguiImpl
|
||||
|
||||
// ===== GameState =====
|
||||
// SAFETY: inspector-egui includes reflect
|
||||
#[cfg(all(
|
||||
not(feature = "serialize"),
|
||||
not(feature = "reflect"),
|
||||
not(feature = "inspector-egui")
|
||||
))]
|
||||
pub trait GameState: GameStateInner {}
|
||||
|
||||
#[cfg(all(
|
||||
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 {}
|
||||
#[game_state_supertraits]
|
||||
pub trait GameState:
|
||||
'static
|
||||
+ std::marker::Sync
|
||||
+ std::marker::Send
|
||||
+ States
|
||||
+ Default
|
||||
+ std::fmt::Debug
|
||||
{
|
||||
}
|
||||
|
||||
// ===== InputsContainer =====
|
||||
// SAFETY: inspector-egui includes reflect
|
||||
|
||||
@@ -6,24 +6,7 @@ edition = "2021"
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
# [features]
|
||||
# default = []
|
||||
# serialize = ["bevy_input/serialize", "serde"]
|
||||
# reflect = ["dep:bevy_reflect"]
|
||||
# inspector-egui = ["reflect", "dep:bevy-inspector-egui"]
|
||||
|
||||
[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" }
|
||||
syn = "1.0"
|
||||
quote = "1.0"
|
||||
|
||||
Reference in New Issue
Block a user