mirror of
https://github.com/bevyengine/bevy
synced 2024-11-25 22:20:20 +00:00
implement TypeUuid
for primitives and fix multiple-parameter generics having the same TypeUuid
(#6633)
# Objective - Fixes #5432 - Fixes #6680 ## Solution - move code responsible for generating the `impl TypeUuid` from `type_uuid_derive` into a new function, `gen_impl_type_uuid`. - this allows the new proc macro, `impl_type_uuid`, to call the code for generation. - added struct `TypeUuidDef` and implemented `syn::Parse` to allow parsing of the input for the new macro. - finally, used the new macro `impl_type_uuid` to implement `TypeUuid` for the standard library (in `crates/bevy_reflect/src/type_uuid_impl.rs`). - fixes #6680 by doing a wrapping add of the param's index to its `TYPE_UUID` Co-authored-by: dis-da-moe <84386186+dis-da-moe@users.noreply.github.com>
This commit is contained in:
parent
81307290e2
commit
8853bef6df
20 changed files with 281 additions and 98 deletions
|
@ -11,79 +11,11 @@ use proc_macro::TokenStream;
|
|||
use proc_macro2::Span;
|
||||
use quote::{format_ident, quote};
|
||||
use syn::{
|
||||
parse::{Parse, ParseStream},
|
||||
parse_macro_input, parse_quote,
|
||||
punctuated::Punctuated,
|
||||
spanned::Spanned,
|
||||
token::Comma,
|
||||
ConstParam, DeriveInput, Field, GenericParam, Ident, Index, LitInt, Meta, MetaList, NestedMeta,
|
||||
Result, Token, TypeParam,
|
||||
parse::ParseStream, parse_macro_input, parse_quote, punctuated::Punctuated, spanned::Spanned,
|
||||
ConstParam, DeriveInput, Field, GenericParam, Ident, Index, Meta, MetaList, NestedMeta, Token,
|
||||
TypeParam,
|
||||
};
|
||||
|
||||
struct AllTuples {
|
||||
macro_ident: Ident,
|
||||
start: usize,
|
||||
end: usize,
|
||||
idents: Vec<Ident>,
|
||||
}
|
||||
|
||||
impl Parse for AllTuples {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let macro_ident = input.parse::<Ident>()?;
|
||||
input.parse::<Comma>()?;
|
||||
let start = input.parse::<LitInt>()?.base10_parse()?;
|
||||
input.parse::<Comma>()?;
|
||||
let end = input.parse::<LitInt>()?.base10_parse()?;
|
||||
input.parse::<Comma>()?;
|
||||
let mut idents = vec![input.parse::<Ident>()?];
|
||||
while input.parse::<Comma>().is_ok() {
|
||||
idents.push(input.parse::<Ident>()?);
|
||||
}
|
||||
|
||||
Ok(AllTuples {
|
||||
macro_ident,
|
||||
start,
|
||||
end,
|
||||
idents,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn all_tuples(input: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(input as AllTuples);
|
||||
let len = input.end - input.start;
|
||||
let mut ident_tuples = Vec::with_capacity(len);
|
||||
for i in input.start..=input.end {
|
||||
let idents = input
|
||||
.idents
|
||||
.iter()
|
||||
.map(|ident| format_ident!("{}{}", ident, i));
|
||||
if input.idents.len() < 2 {
|
||||
ident_tuples.push(quote! {
|
||||
#(#idents)*
|
||||
});
|
||||
} else {
|
||||
ident_tuples.push(quote! {
|
||||
(#(#idents),*)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let macro_ident = &input.macro_ident;
|
||||
let invocations = (input.start..=input.end).map(|i| {
|
||||
let ident_tuples = &ident_tuples[..i];
|
||||
quote! {
|
||||
#macro_ident!(#(#ident_tuples),*);
|
||||
}
|
||||
});
|
||||
TokenStream::from(quote! {
|
||||
#(
|
||||
#invocations
|
||||
)*
|
||||
})
|
||||
}
|
||||
|
||||
enum BundleFieldKind {
|
||||
Component,
|
||||
Ignore,
|
||||
|
|
|
@ -15,8 +15,8 @@ use crate::{
|
|||
storage::{SparseSetIndex, SparseSets, Storages, Table, TableRow},
|
||||
TypeIdMap,
|
||||
};
|
||||
use bevy_ecs_macros::all_tuples;
|
||||
use bevy_ptr::OwningPtr;
|
||||
use bevy_utils::all_tuples;
|
||||
use std::any::TypeId;
|
||||
|
||||
/// The `Bundle` trait enables insertion and removal of [`Component`]s from an entity.
|
||||
|
|
|
@ -52,7 +52,7 @@ pub mod prelude {
|
|||
};
|
||||
}
|
||||
|
||||
pub use bevy_ecs_macros::all_tuples;
|
||||
pub use bevy_utils::all_tuples;
|
||||
|
||||
/// A specialized hashmap type with Key of `TypeId`
|
||||
type TypeIdMap<V> = rustc_hash::FxHashMap<TypeId, V>;
|
||||
|
|
|
@ -7,9 +7,9 @@ use crate::{
|
|||
storage::{ComponentSparseSet, Table, TableRow},
|
||||
world::{Mut, Ref, World},
|
||||
};
|
||||
use bevy_ecs_macros::all_tuples;
|
||||
pub use bevy_ecs_macros::WorldQuery;
|
||||
use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref};
|
||||
use bevy_utils::all_tuples;
|
||||
use std::{cell::UnsafeCell, marker::PhantomData};
|
||||
|
||||
/// Types that can be fetched from a [`World`] using a [`Query`].
|
||||
|
|
|
@ -6,8 +6,8 @@ use crate::{
|
|||
storage::{Column, ComponentSparseSet, Table, TableRow},
|
||||
world::World,
|
||||
};
|
||||
use bevy_ecs_macros::all_tuples;
|
||||
use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref};
|
||||
use bevy_utils::all_tuples;
|
||||
use std::{cell::UnsafeCell, marker::PhantomData};
|
||||
|
||||
use super::ReadOnlyWorldQuery;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use bevy_ecs_macros::all_tuples;
|
||||
use bevy_utils::all_tuples;
|
||||
|
||||
use crate::{
|
||||
schedule::{
|
||||
|
|
|
@ -9,7 +9,8 @@ use crate::{
|
|||
},
|
||||
world::{World, WorldId},
|
||||
};
|
||||
use bevy_ecs_macros::all_tuples;
|
||||
|
||||
use bevy_utils::all_tuples;
|
||||
use std::{any::TypeId, borrow::Cow, marker::PhantomData};
|
||||
|
||||
/// A function system that runs with exclusive [`World`] access.
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
|||
system::{Local, SystemMeta, SystemParam, SystemState},
|
||||
world::World,
|
||||
};
|
||||
use bevy_ecs_macros::all_tuples;
|
||||
use bevy_utils::all_tuples;
|
||||
use bevy_utils::synccell::SyncCell;
|
||||
|
||||
pub trait ExclusiveSystemParam: Sized {
|
||||
|
|
|
@ -7,7 +7,8 @@ use crate::{
|
|||
system::{check_system_change_tick, ReadOnlySystemParam, System, SystemParam, SystemParamItem},
|
||||
world::{World, WorldId},
|
||||
};
|
||||
use bevy_ecs_macros::all_tuples;
|
||||
|
||||
use bevy_utils::all_tuples;
|
||||
use std::{any::TypeId, borrow::Cow, marker::PhantomData};
|
||||
|
||||
use super::ReadOnlySystem;
|
||||
|
|
|
@ -11,11 +11,11 @@ use crate::{
|
|||
system::{Query, SystemMeta},
|
||||
world::{FromWorld, World},
|
||||
};
|
||||
use bevy_ecs_macros::impl_param_set;
|
||||
pub use bevy_ecs_macros::Resource;
|
||||
pub use bevy_ecs_macros::SystemParam;
|
||||
use bevy_ecs_macros::{all_tuples, impl_param_set};
|
||||
use bevy_ptr::UnsafeCellDeref;
|
||||
use bevy_utils::synccell::SyncCell;
|
||||
use bevy_utils::{all_tuples, synccell::SyncCell};
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
fmt::Debug,
|
||||
|
|
|
@ -30,11 +30,13 @@ mod type_uuid;
|
|||
mod utility;
|
||||
|
||||
use crate::derive_data::{ReflectDerive, ReflectMeta, ReflectStruct};
|
||||
use crate::type_uuid::gen_impl_type_uuid;
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use reflect_value::ReflectValueDef;
|
||||
use syn::spanned::Spanned;
|
||||
use syn::{parse_macro_input, DeriveInput};
|
||||
use type_uuid::TypeUuidDef;
|
||||
|
||||
pub(crate) static REFLECT_ATTRIBUTE_NAME: &str = "reflect";
|
||||
pub(crate) static REFLECT_VALUE_ATTRIBUTE_NAME: &str = "reflect_value";
|
||||
|
@ -185,3 +187,10 @@ pub fn impl_from_reflect_value(input: TokenStream) -> TokenStream {
|
|||
def.traits.unwrap_or_default(),
|
||||
))
|
||||
}
|
||||
|
||||
/// Derives `TypeUuid` for the given type. This is used internally to implement `TypeUuid` on foreign types, such as those in the std. This macro should be used in the format of `<[Generic Params]> [Type (Path)], [Uuid (String Literal)]`.
|
||||
#[proc_macro]
|
||||
pub fn impl_type_uuid(input: TokenStream) -> TokenStream {
|
||||
let def = parse_macro_input!(input as TypeUuidDef);
|
||||
gen_impl_type_uuid(def)
|
||||
}
|
||||
|
|
|
@ -2,25 +2,17 @@ extern crate proc_macro;
|
|||
|
||||
use bevy_macro_utils::BevyManifest;
|
||||
use quote::quote;
|
||||
use syn::parse::{Parse, ParseStream};
|
||||
use syn::*;
|
||||
use uuid::Uuid;
|
||||
|
||||
/// Parses input from a derive of `TypeUuid`.
|
||||
pub(crate) fn type_uuid_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
// Construct a representation of Rust code as a syntax tree
|
||||
// that we can manipulate
|
||||
let mut ast: DeriveInput = syn::parse(input).unwrap();
|
||||
let bevy_reflect_path: Path = BevyManifest::default().get_path("bevy_reflect");
|
||||
|
||||
let ast: DeriveInput = syn::parse(input).unwrap();
|
||||
// Build the trait implementation
|
||||
let name = &ast.ident;
|
||||
|
||||
ast.generics.type_params_mut().for_each(|param| {
|
||||
param
|
||||
.bounds
|
||||
.push(syn::parse_quote!(#bevy_reflect_path::TypeUuid));
|
||||
});
|
||||
|
||||
let (impl_generics, type_generics, where_clause) = &ast.generics.split_for_impl();
|
||||
let type_ident = ast.ident;
|
||||
|
||||
let mut uuid = None;
|
||||
for attribute in ast.attrs.iter().filter_map(|attr| attr.parse_meta().ok()) {
|
||||
|
@ -50,24 +42,73 @@ pub(crate) fn type_uuid_derive(input: proc_macro::TokenStream) -> proc_macro::To
|
|||
|
||||
let uuid =
|
||||
uuid.expect("No `#[uuid = \"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"` attribute found.");
|
||||
gen_impl_type_uuid(TypeUuidDef {
|
||||
type_ident,
|
||||
generics: ast.generics,
|
||||
uuid,
|
||||
})
|
||||
}
|
||||
|
||||
/// Generates an implementation of `TypeUuid`. If there any generics, the `TYPE_UUID` will be a composite of the generic types' `TYPE_UUID`.
|
||||
pub(crate) fn gen_impl_type_uuid(def: TypeUuidDef) -> proc_macro::TokenStream {
|
||||
let uuid = def.uuid;
|
||||
let mut generics = def.generics;
|
||||
let ty = def.type_ident;
|
||||
|
||||
let bevy_reflect_path: Path = BevyManifest::default().get_path("bevy_reflect");
|
||||
|
||||
generics.type_params_mut().for_each(|param| {
|
||||
param
|
||||
.bounds
|
||||
.push(syn::parse_quote!(#bevy_reflect_path::TypeUuid));
|
||||
});
|
||||
|
||||
let bytes = uuid
|
||||
.as_bytes()
|
||||
.iter()
|
||||
.map(|byte| format!("{byte:#X}"))
|
||||
.map(|byte_str| syn::parse_str::<LitInt>(&byte_str).unwrap());
|
||||
|
||||
let (impl_generics, type_generics, where_clause) = generics.split_for_impl();
|
||||
|
||||
let base = quote! { #bevy_reflect_path::Uuid::from_bytes([#( #bytes ),*]) };
|
||||
let type_uuid = ast.generics.type_params().fold(base, |acc, param| {
|
||||
let type_uuid = generics.type_params().enumerate().fold(base, |acc, (index, param)| {
|
||||
let ident = ¶m.ident;
|
||||
let param_uuid = quote!(
|
||||
#bevy_reflect_path::Uuid::from_u128(<#ident as #bevy_reflect_path::TypeUuid>::TYPE_UUID.as_u128().wrapping_add(#index as u128))
|
||||
);
|
||||
quote! {
|
||||
#bevy_reflect_path::__macro_exports::generate_composite_uuid(#acc, <#ident as #bevy_reflect_path::TypeUuid>::TYPE_UUID)
|
||||
#bevy_reflect_path::__macro_exports::generate_composite_uuid(#acc, #param_uuid)
|
||||
}
|
||||
});
|
||||
|
||||
let gen = quote! {
|
||||
impl #impl_generics #bevy_reflect_path::TypeUuid for #name #type_generics #where_clause {
|
||||
impl #impl_generics #bevy_reflect_path::TypeUuid for #ty #type_generics #where_clause {
|
||||
const TYPE_UUID: #bevy_reflect_path::Uuid = #type_uuid;
|
||||
}
|
||||
};
|
||||
gen.into()
|
||||
}
|
||||
|
||||
/// A struct containing the data required to generate an implementation of `TypeUuid`. This can be generated by either [`impl_type_uuid!`][crate::impl_type_uuid!] or [`type_uuid_derive`].
|
||||
pub(crate) struct TypeUuidDef {
|
||||
pub type_ident: Ident,
|
||||
pub generics: Generics,
|
||||
pub uuid: Uuid,
|
||||
}
|
||||
|
||||
impl Parse for TypeUuidDef {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let type_ident = input.parse::<Ident>()?;
|
||||
let generics = input.parse::<Generics>()?;
|
||||
input.parse::<Token![,]>()?;
|
||||
let uuid = input.parse::<LitStr>()?.value();
|
||||
let uuid = Uuid::parse_str(&uuid).map_err(|err| input.error(format!("{}", err)))?;
|
||||
|
||||
Ok(Self {
|
||||
type_ident,
|
||||
generics,
|
||||
uuid,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ mod tuple_struct;
|
|||
mod type_info;
|
||||
mod type_registry;
|
||||
mod type_uuid;
|
||||
mod type_uuid_impl;
|
||||
mod impls {
|
||||
#[cfg(feature = "glam")]
|
||||
mod glam;
|
||||
|
|
|
@ -122,4 +122,36 @@ mod test {
|
|||
|
||||
assert_eq!(uuid_a, uuid_b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multiple_generic_uuid() {
|
||||
#[derive(TypeUuid)]
|
||||
#[uuid = "35c8a7d3-d4b3-4bd7-b847-1118dc78092f"]
|
||||
struct TestGeneric<A, B> {
|
||||
_value_a: A,
|
||||
_value_b: B,
|
||||
}
|
||||
assert_ne!(
|
||||
TestGeneric::<f32, bool>::TYPE_UUID,
|
||||
TestGeneric::<bool, f32>::TYPE_UUID
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_primitive_generic_uuid() {
|
||||
test_impl_type_uuid(&true);
|
||||
test_impl_type_uuid(&Some(true));
|
||||
test_impl_type_uuid(&TestDeriveStruct::<bool> { _value: true });
|
||||
|
||||
assert_ne!(Option::<bool>::TYPE_UUID, Option::<f32>::TYPE_UUID);
|
||||
|
||||
assert_ne!(<[bool; 0]>::TYPE_UUID, <[bool; 1]>::TYPE_UUID);
|
||||
assert_ne!(<[bool; 0]>::TYPE_UUID, <[f32; 0]>::TYPE_UUID);
|
||||
|
||||
assert_ne!(
|
||||
<(bool, bool)>::TYPE_UUID,
|
||||
<(bool, bool, bool, bool)>::TYPE_UUID
|
||||
);
|
||||
assert_ne!(<(bool, f32)>::TYPE_UUID, <(f32, bool)>::TYPE_UUID);
|
||||
}
|
||||
}
|
||||
|
|
80
crates/bevy_reflect/src/type_uuid_impl.rs
Normal file
80
crates/bevy_reflect/src/type_uuid_impl.rs
Normal file
|
@ -0,0 +1,80 @@
|
|||
use crate::TypeUuid;
|
||||
use crate::{self as bevy_reflect, __macro_exports::generate_composite_uuid};
|
||||
use bevy_reflect_derive::impl_type_uuid;
|
||||
use bevy_utils::{all_tuples, Duration, HashMap, HashSet, Instant, Uuid};
|
||||
#[cfg(feature = "smallvec")]
|
||||
use smallvec::SmallVec;
|
||||
#[cfg(any(unix, windows))]
|
||||
use std::ffi::OsString;
|
||||
use std::{
|
||||
num::{
|
||||
NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
|
||||
NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize,
|
||||
},
|
||||
ops::{RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive},
|
||||
path::PathBuf,
|
||||
};
|
||||
impl<T: TypeUuid, const N: usize> TypeUuid for [T; N] {
|
||||
const TYPE_UUID: Uuid = generate_composite_uuid(
|
||||
Uuid::from_u128(0x18d33c78e63c47b9bbf8f095008ab693),
|
||||
generate_composite_uuid(Uuid::from_u128(N as u128), T::TYPE_UUID),
|
||||
);
|
||||
}
|
||||
impl_type_uuid!(bool, "eb1ad0ee2dff473285bc54ebbdef682c");
|
||||
impl_type_uuid!(char, "45a4710278ba48f8b31f0d72ff7f9d46");
|
||||
impl_type_uuid!(u8, "fdf1a88a3e0543ca9f51ad5978ca519f");
|
||||
impl_type_uuid!(u16, "ddeb93f791074860aaac1540de254edc");
|
||||
impl_type_uuid!(u32, "fc565ea2367f405591e1c55f91cb60bd");
|
||||
impl_type_uuid!(u64, "6c74b6a983eb44b096a9169baa6af0a1");
|
||||
impl_type_uuid!(u128, "f837371a4f534b7381ed776d5056d0c1");
|
||||
impl_type_uuid!(usize, "0129e1d8cff041f9b23aa99c6e1006b8");
|
||||
impl_type_uuid!(i8, "af7a5411661e43b0b1631ea43a825fd2");
|
||||
impl_type_uuid!(i16, "68592d5de5be4a608603c6988edfdf9c");
|
||||
impl_type_uuid!(i32, "439ff07f96c94aa5a86352ded71e4730");
|
||||
impl_type_uuid!(i64, "7f9534793ad24ab2b9f05d8254f4204a");
|
||||
impl_type_uuid!(i128, "6e5009be5845460daf814e052cc9fcf0");
|
||||
impl_type_uuid!(isize, "d3d52630da45497faf86859051c79e7d");
|
||||
impl_type_uuid!(f32, "006607124a8148e1910c86f0c18c9015");
|
||||
impl_type_uuid!(f64, "a5bc32f5632b478c92a0939b821fff80");
|
||||
impl_type_uuid!(Result<T, E>, "d5960af2e8a743dfb7427dd59b70df95");
|
||||
impl_type_uuid!(String, "c9f90d31b52d4bcd8b5c1d8b6fc1bcba");
|
||||
impl_type_uuid!(PathBuf, "aa79933abd1743698583a3acad3b8989");
|
||||
impl_type_uuid!(Vec<T>, "ab98f5408b974475b643662247fb3886");
|
||||
impl_type_uuid!(HashMap<K, V>,"f37bfad9ca8c4f6ea7448f1c39e05f98");
|
||||
impl_type_uuid!(Option<T>, "8d5ba9a9031347078955fba01ff439f0");
|
||||
#[cfg(feature = "smallvec")]
|
||||
impl_type_uuid!(
|
||||
SmallVec<T: smallvec::Array>,
|
||||
"26fd5c1bed7144fbb8d1546c02ba255a"
|
||||
);
|
||||
impl_type_uuid!(HashSet<K>, "5ebd2379ece44ef2b1478262962617a3");
|
||||
impl_type_uuid!(RangeInclusive<T>, "79613b729ca9490881c7f47b24b22b60");
|
||||
impl_type_uuid!(RangeFrom<T>, "1bd8c975f122486c9ed443e277964642");
|
||||
impl_type_uuid!(RangeTo<T>, "7d938903749a4d198f496cb354929b9b");
|
||||
impl_type_uuid!(RangeToInclusive<T>, "2fec56936206462fa5f35c99a62c5ed1");
|
||||
impl_type_uuid!(RangeFull, "227af17f65db448782a2f6980ceae25d");
|
||||
impl_type_uuid!(Duration, "cee5978c60f74a53b6848cb9c46a6e1c");
|
||||
impl_type_uuid!(Instant, "9b0194a1d31c44c1afd2f6fd80ab8dfb");
|
||||
impl_type_uuid!(NonZeroI128, "915a1e7fcaeb433982cebf58c2ac20e7");
|
||||
impl_type_uuid!(NonZeroU128, "286de521146042cda31dfbef8f3f6cdc");
|
||||
impl_type_uuid!(NonZeroIsize, "9318740a9fd14603b709b8fbc6fd2812");
|
||||
impl_type_uuid!(NonZeroUsize, "a26533ed16324189878263d5e7a294ce");
|
||||
impl_type_uuid!(NonZeroI64, "1aa38623127a42419cca4992e6fc3152");
|
||||
impl_type_uuid!(NonZeroU64, "46be65e669a2477d942e2ec39d0d2af7");
|
||||
impl_type_uuid!(NonZeroU32, "cf53a46d9efe4022967160cb61762c91");
|
||||
impl_type_uuid!(NonZeroI32, "a69fbd659bef4322b88b15ff3263f530");
|
||||
impl_type_uuid!(NonZeroI16, "8744c2ec8a10491fae40f8bafa58b30d");
|
||||
impl_type_uuid!(NonZeroU16, "c7b8b60780a6495bab4fda2bdfedabcc");
|
||||
impl_type_uuid!(NonZeroU8, "635ee104ef7947fb9d7f79dad47255a3");
|
||||
impl_type_uuid!(NonZeroI8, "2d3f1570b7f64779826d44da5c7ba069");
|
||||
#[cfg(any(unix, windows))]
|
||||
impl_type_uuid!(OsString, "809e7b3c1ea240979ecd832f91eb842a");
|
||||
macro_rules! impl_tuple {
|
||||
( $($name: ident),* ) => {
|
||||
const _: () = {
|
||||
type Tuple< $($name),* > = ( $($name,)* );
|
||||
impl_type_uuid!(Tuple< $($name),* > , "35c8a7d3d4b34bd7b8471118dc78092f");
|
||||
};
|
||||
};
|
||||
}
|
||||
all_tuples!(impl_tuple, 0, 12, A);
|
|
@ -1,13 +1,12 @@
|
|||
use crate::render_phase::{PhaseItem, TrackedRenderPass};
|
||||
use bevy_app::App;
|
||||
use bevy_ecs::{
|
||||
all_tuples,
|
||||
entity::Entity,
|
||||
query::{QueryState, ROQueryItem, ReadOnlyWorldQuery},
|
||||
system::{ReadOnlySystemParam, Resource, SystemParam, SystemParamItem, SystemState},
|
||||
world::World,
|
||||
};
|
||||
use bevy_utils::HashMap;
|
||||
use bevy_utils::{all_tuples, HashMap};
|
||||
use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
use std::{any::TypeId, fmt::Debug, hash::Hash};
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ tracing = { version = "0.1", default-features = false, features = ["std"] }
|
|||
instant = { version = "0.1", features = ["wasm-bindgen"] }
|
||||
uuid = { version = "1.1", features = ["v4", "serde"] }
|
||||
hashbrown = { version = "0.12", features = ["serde"] }
|
||||
bevy_utils_proc_macros = {version = "0.9.0", path = "macros"}
|
||||
petgraph = "0.6"
|
||||
thiserror = "1.0"
|
||||
|
||||
|
|
14
crates/bevy_utils/macros/Cargo.toml
Normal file
14
crates/bevy_utils/macros/Cargo.toml
Normal file
|
@ -0,0 +1,14 @@
|
|||
[package]
|
||||
name = "bevy_utils_proc_macros"
|
||||
version = "0.9.0"
|
||||
description = "Bevy Utils Proc Macros"
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
syn = "1.0"
|
||||
quote = "1.0"
|
||||
proc-macro2 = "1.0"
|
71
crates/bevy_utils/macros/src/lib.rs
Normal file
71
crates/bevy_utils/macros/src/lib.rs
Normal file
|
@ -0,0 +1,71 @@
|
|||
use proc_macro::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use syn::{
|
||||
parse::{Parse, ParseStream},
|
||||
parse_macro_input,
|
||||
token::Comma,
|
||||
Ident, LitInt, Result,
|
||||
};
|
||||
struct AllTuples {
|
||||
macro_ident: Ident,
|
||||
start: usize,
|
||||
end: usize,
|
||||
idents: Vec<Ident>,
|
||||
}
|
||||
|
||||
impl Parse for AllTuples {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let macro_ident = input.parse::<Ident>()?;
|
||||
input.parse::<Comma>()?;
|
||||
let start = input.parse::<LitInt>()?.base10_parse()?;
|
||||
input.parse::<Comma>()?;
|
||||
let end = input.parse::<LitInt>()?.base10_parse()?;
|
||||
input.parse::<Comma>()?;
|
||||
let mut idents = vec![input.parse::<Ident>()?];
|
||||
while input.parse::<Comma>().is_ok() {
|
||||
idents.push(input.parse::<Ident>()?);
|
||||
}
|
||||
|
||||
Ok(AllTuples {
|
||||
macro_ident,
|
||||
start,
|
||||
end,
|
||||
idents,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn all_tuples(input: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(input as AllTuples);
|
||||
let len = input.end - input.start;
|
||||
let mut ident_tuples = Vec::with_capacity(len);
|
||||
for i in input.start..=input.end {
|
||||
let idents = input
|
||||
.idents
|
||||
.iter()
|
||||
.map(|ident| format_ident!("{}{}", ident, i));
|
||||
if input.idents.len() < 2 {
|
||||
ident_tuples.push(quote! {
|
||||
#(#idents)*
|
||||
});
|
||||
} else {
|
||||
ident_tuples.push(quote! {
|
||||
(#(#idents),*)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let macro_ident = &input.macro_ident;
|
||||
let invocations = (input.start..=input.end).map(|i| {
|
||||
let ident_tuples = &ident_tuples[..i];
|
||||
quote! {
|
||||
#macro_ident!(#(#ident_tuples),*);
|
||||
}
|
||||
});
|
||||
TokenStream::from(quote! {
|
||||
#(
|
||||
#invocations
|
||||
)*
|
||||
})
|
||||
}
|
|
@ -21,6 +21,7 @@ mod default;
|
|||
mod float_ord;
|
||||
|
||||
pub use ahash::AHasher;
|
||||
pub use bevy_utils_proc_macros::*;
|
||||
pub use default::default;
|
||||
pub use float_ord::*;
|
||||
pub use hashbrown;
|
||||
|
|
Loading…
Reference in a new issue