Use bevy_reflect as path in case of no direct references (#1875)

Fixes #1844


Co-authored-by: Carter Anderson <mcanders1@gmail.com>
This commit is contained in:
Yoh Deadfall 2021-05-19 19:03:36 +00:00
parent a42343d847
commit 653c10371e
25 changed files with 128 additions and 213 deletions

View file

@ -16,8 +16,9 @@ keywords = ["bevy"]
proc-macro = true
[dependencies]
bevy_macro_utils = { path = "../bevy_macro_utils", version = "0.5.0" }
Inflector = { version = "0.11.4", default-features = false }
find-crate = "0.6"
proc-macro2 = "1.0"
quote = "1.0"
syn = "1.0"

View file

@ -1,4 +1,4 @@
use crate::modules::{get_modules, get_path};
use bevy_macro_utils::BevyManifest;
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Fields};
@ -13,8 +13,7 @@ pub fn derive_bytes(input: TokenStream) -> TokenStream {
_ => panic!("Expected a struct with named fields."),
};
let modules = get_modules(&ast.attrs);
let bevy_core_path = get_path(&modules.bevy_core);
let bevy_core_path = BevyManifest::default().get_path(crate::modules::BEVY_CORE);
let fields = fields
.iter()

View file

@ -1,4 +1,4 @@
use crate::modules::{get_modules, get_path};
use bevy_macro_utils::BevyManifest;
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Data, DeriveInput};
@ -10,8 +10,7 @@ pub fn derive_enum_variant_meta(input: TokenStream) -> TokenStream {
_ => panic!("Expected an enum."),
};
let modules = get_modules(&ast.attrs);
let bevy_util_path = get_path(&modules.bevy_utils);
let bevy_util_path = BevyManifest::default().get_path(crate::modules::BEVY_UTILS);
let generics = ast.generics;
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

View file

@ -14,33 +14,33 @@ use proc_macro::TokenStream;
/// Derives the FromResources trait. Each field must also implement the FromResources trait or this
/// will fail. FromResources is automatically implemented for types that implement Default.
#[proc_macro_derive(FromResources, attributes(as_crate))]
#[proc_macro_derive(FromResources)]
pub fn derive_from_resources(input: TokenStream) -> TokenStream {
resource::derive_from_resources(input)
}
/// Derives the Bytes trait. Each field must also implements Bytes or this will fail.
#[proc_macro_derive(Bytes, attributes(as_crate))]
#[proc_macro_derive(Bytes)]
pub fn derive_bytes(input: TokenStream) -> TokenStream {
bytes::derive_bytes(input)
}
/// Derives the RenderResources trait. Each field must implement RenderResource or this will fail.
/// You can ignore fields using `#[render_resources(ignore)]`.
#[proc_macro_derive(RenderResources, attributes(render_resources, as_crate))]
#[proc_macro_derive(RenderResources, attributes(render_resources))]
pub fn derive_render_resources(input: TokenStream) -> TokenStream {
render_resources::derive_render_resources(input)
}
/// Derives the RenderResource trait. The type must also implement `Bytes` or this will fail.
#[proc_macro_derive(RenderResource, attributes(as_crate))]
#[proc_macro_derive(RenderResource)]
pub fn derive_render_resource(input: TokenStream) -> TokenStream {
render_resource::derive_render_resource(input)
}
/// Derives the ShaderDefs trait. Each field must implement ShaderDef or this will fail.
/// You can ignore fields using `#[shader_defs(ignore)]`.
#[proc_macro_derive(ShaderDefs, attributes(shader_def, as_crate))]
#[proc_macro_derive(ShaderDefs, attributes(shader_def))]
pub fn derive_shader_defs(input: TokenStream) -> TokenStream {
shader_defs::derive_shader_defs(input)
}
@ -56,7 +56,7 @@ pub fn bevy_main(attr: TokenStream, item: TokenStream) -> TokenStream {
bevy_main::bevy_main(attr, item)
}
#[proc_macro_derive(EnumVariantMeta, attributes(as_crate))]
#[proc_macro_derive(EnumVariantMeta)]
pub fn derive_enum_variant_meta(input: TokenStream) -> TokenStream {
enum_variant_meta::derive_enum_variant_meta(input)
}

View file

@ -1,71 +1,5 @@
use find_crate::Manifest;
use proc_macro::TokenStream;
use syn::{Attribute, Path};
#[derive(Debug)]
pub struct Modules {
pub bevy_render: String,
pub bevy_asset: String,
pub bevy_core: String,
pub bevy_utils: String,
pub bevy_app: String,
}
impl Modules {
pub fn meta(name: &str) -> Modules {
Modules {
bevy_asset: format!("{}::asset", name),
bevy_render: format!("{}::render", name),
bevy_core: format!("{}::core", name),
bevy_utils: format!("{}::utils", name),
bevy_app: format!("{}::app", name),
}
}
pub fn external() -> Modules {
Modules {
bevy_asset: "bevy_asset".to_string(),
bevy_render: "bevy_render".to_string(),
bevy_core: "bevy_core".to_string(),
bevy_utils: "bevy_utils".to_string(),
bevy_app: "bevy_app".to_string(),
}
}
}
fn get_meta() -> Option<Modules> {
let manifest = Manifest::new().unwrap();
if let Some(package) = manifest.find(|name| name == "bevy") {
Some(Modules::meta(&package.name))
} else if let Some(package) = manifest.find(|name| name == "bevy_internal") {
Some(Modules::meta(&package.name))
} else {
None
}
}
const AS_CRATE_ATTRIBUTE_NAME: &str = "as_crate";
fn validate_as_crate_attribute(tokens: &str) -> bool {
tokens.len() > 2 && tokens.starts_with('(') && tokens.ends_with(')')
}
pub fn get_modules(attributes: &[Attribute]) -> Modules {
let mut modules = get_meta().unwrap_or_else(Modules::external);
for attribute in attributes.iter() {
if *attribute.path.get_ident().as_ref().unwrap() == AS_CRATE_ATTRIBUTE_NAME {
let value = attribute.tokens.to_string();
if !validate_as_crate_attribute(&value) {
panic!("The attribute `#[as_crate{}]` is invalid. It must follow the format `#[as_crate(<crate name>)]`", value);
} else if value[1..value.len() - 1] == modules.bevy_render {
modules.bevy_render = "crate".to_string();
}
}
}
modules
}
pub fn get_path(path_str: &str) -> Path {
syn::parse(path_str.parse::<TokenStream>().unwrap()).unwrap()
}
pub const BEVY_APP: &str = "bevy_app";
pub const BEVY_ASSET: &str = "bevy_asset";
pub const BEVY_CORE: &str = "bevy_core";
pub const BEVY_RENDER: &str = "bevy_render";
pub const BEVY_UTILS: &str = "bevy_utils";

View file

@ -1,15 +1,15 @@
use crate::modules::{get_modules, get_path};
use bevy_macro_utils::BevyManifest;
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput, Path};
pub fn derive_render_resource(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let modules = get_modules(&ast.attrs);
let manifest = BevyManifest::default();
let bevy_render_path: Path = get_path(&modules.bevy_render);
let bevy_asset_path: Path = get_path(&modules.bevy_asset);
let bevy_core_path: Path = get_path(&modules.bevy_core);
let bevy_render_path: Path = manifest.get_path(crate::modules::BEVY_RENDER);
let bevy_asset_path: Path = manifest.get_path(crate::modules::BEVY_ASSET);
let bevy_core_path: Path = manifest.get_path(crate::modules::BEVY_CORE);
let struct_name = &ast.ident;
let (impl_generics, type_generics, where_clause) = &ast.generics.split_for_impl();

View file

@ -1,4 +1,4 @@
use crate::modules::{get_modules, get_path};
use bevy_macro_utils::BevyManifest;
use proc_macro::TokenStream;
use quote::{format_ident, quote};
use syn::{
@ -21,9 +21,8 @@ static RENDER_RESOURCE_ATTRIBUTE_NAME: &str = "render_resources";
pub fn derive_render_resources(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let modules = get_modules(&ast.attrs);
let bevy_render_path: Path = get_path(&modules.bevy_render);
let bevy_render_path: Path = BevyManifest::default().get_path(crate::modules::BEVY_RENDER);
let attributes = ast
.attrs
.iter()

View file

@ -1,4 +1,4 @@
use crate::modules::{get_modules, get_path};
use bevy_macro_utils::BevyManifest;
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Fields};
@ -13,16 +13,11 @@ pub fn derive_from_resources(input: TokenStream) -> TokenStream {
_ => panic!("Expected a struct with named fields."),
};
let modules = get_modules(&ast.attrs);
let bevy_app_path = get_path(&modules.bevy_app);
let bevy_app_path = BevyManifest::default().get_path(crate::modules::BEVY_APP);
let field_types = fields.iter().map(|field| &field.ty);
let fields = fields.iter().map(|field| field.ident.as_ref().unwrap());
let generics = ast.generics;
let (impl_generics, ty_generics, _where_clause) = generics.split_for_impl();
let struct_name = &ast.ident;
TokenStream::from(quote! {

View file

@ -1,4 +1,4 @@
use crate::modules::{get_modules, get_path};
use bevy_macro_utils::BevyManifest;
use inflector::Inflector;
use proc_macro::TokenStream;
use proc_macro2::Ident;
@ -9,8 +9,7 @@ static SHADER_DEF_ATTRIBUTE_NAME: &str = "shader_def";
pub fn derive_shader_defs(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let modules = get_modules(&ast.attrs);
let bevy_render_path: Path = get_path(&modules.bevy_render);
let bevy_render_path: Path = BevyManifest::default().get_path(crate::modules::BEVY_RENDER);
let fields = match &ast.data {
Data::Struct(DataStruct {

View file

@ -13,7 +13,8 @@ license = "MIT"
proc-macro = true
[dependencies]
bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.5.0" }
syn = "1.0"
quote = "1.0"
proc-macro2 = "1.0"
find-crate = "0.6"

View file

@ -1,6 +1,6 @@
extern crate proc_macro;
use find_crate::{Dependencies, Manifest};
use bevy_macro_utils::BevyManifest;
use proc_macro::TokenStream;
use proc_macro2::{Span, TokenStream as TokenStream2};
use quote::{format_ident, quote};
@ -471,24 +471,5 @@ fn derive_label(input: DeriveInput, label_type: Ident) -> TokenStream2 {
}
fn bevy_ecs_path() -> syn::Path {
fn find_in_manifest(manifest: &mut Manifest, dependencies: Dependencies) -> Option<String> {
manifest.dependencies = dependencies;
if let Some(package) = manifest.find(|name| name == "bevy") {
Some(format!("{}::ecs", package.name))
} else if let Some(package) = manifest.find(|name| name == "bevy_internal") {
Some(format!("{}::ecs", package.name))
} else if let Some(package) = manifest.find(|name| name == "bevy_ecs") {
Some(package.name)
} else {
None
}
}
let mut manifest = Manifest::new().unwrap();
let path_str = find_in_manifest(&mut manifest, Dependencies::Release)
.or_else(|| find_in_manifest(&mut manifest, Dependencies::Dev))
.unwrap_or_else(|| "bevy_ecs".to_string());
let path: Path = syn::parse(path_str.parse::<TokenStream>().unwrap()).unwrap();
path
BevyManifest::default().get_path("bevy_ecs")
}

View file

@ -36,6 +36,7 @@ pub mod prelude {
#[cfg(test)]
mod tests {
use crate as bevy_ecs;
use crate::{
bundle::Bundle,
component::{Component, ComponentDescriptor, ComponentId, StorageType, TypeInfo},
@ -78,7 +79,6 @@ mod tests {
#[test]
fn bundle_derive() {
use crate as bevy_ecs;
#[derive(Bundle, PartialEq, Debug)]
struct Foo {
x: &'static str,

View file

@ -0,0 +1,18 @@
[package]
name = "bevy_macro_utils"
version = "0.5.0"
edition = "2018"
authors = [
"Bevy Contributors <bevyengine@gmail.com>",
"Carter Anderson <mcanders1@gmail.com>",
]
description = "A collection of utils for Bevy Engine"
homepage = "https://bevyengine.org"
repository = "https://github.com/bevyengine/bevy"
license = "MIT"
keywords = ["bevy"]
[dependencies]
cargo-manifest = "0.2.3"
proc-macro2 = "1.0"
syn = "1.0"

View file

@ -0,0 +1,61 @@
extern crate proc_macro;
use cargo_manifest::{DepsSet, Manifest};
use proc_macro::TokenStream;
use std::{env, path::PathBuf};
pub struct BevyManifest {
manifest: Manifest,
}
impl Default for BevyManifest {
fn default() -> Self {
Self {
manifest: env::var_os("CARGO_MANIFEST_DIR")
.map(PathBuf::from)
.map(|mut path| {
path.push("Cargo.toml");
Manifest::from_path(path).unwrap()
})
.unwrap(),
}
}
}
impl BevyManifest {
pub fn get_path(&self, name: &str) -> syn::Path {
const BEVY: &str = "bevy";
const BEVY_INTERNAL: &str = "bevy_internal";
let find_in_deps = |deps: &DepsSet| -> Option<syn::Path> {
let package = if let Some(dep) = deps.get(BEVY) {
dep.package().unwrap_or(BEVY)
} else if let Some(dep) = deps.get(BEVY_INTERNAL) {
dep.package().unwrap_or(BEVY_INTERNAL)
} else {
return None;
};
let mut path = get_path(package);
if let Some(module) = name.strip_prefix("bevy_") {
path.segments.push(parse_str(module));
}
Some(path)
};
let deps = self.manifest.dependencies.as_ref();
let deps_dev = self.manifest.dev_dependencies.as_ref();
deps.and_then(find_in_deps)
.or_else(|| deps_dev.and_then(find_in_deps))
.unwrap_or_else(|| get_path(name))
}
}
fn get_path(path: &str) -> syn::Path {
parse_str(path)
}
fn parse_str<T: syn::parse::Parse>(path: &str) -> T {
syn::parse(path.parse::<TokenStream>().unwrap()).unwrap()
}

View file

@ -16,8 +16,9 @@ keywords = ["bevy"]
proc-macro = true
[dependencies]
bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.5.0" }
syn = "1.0"
proc-macro2 = "1.0"
quote = "1.0"
find-crate = "0.6"
uuid = { version = "0.8", features = ["v4", "serde"] }

View file

@ -1,11 +1,9 @@
extern crate proc_macro;
mod modules;
mod reflect_trait;
mod type_uuid;
use find_crate::Manifest;
use modules::{get_modules, get_path};
use bevy_macro_utils::BevyManifest;
use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::quote;
@ -106,8 +104,7 @@ pub fn derive_reflect(input: TokenStream) -> TokenStream {
.map(|(f, _attr, i)| (*f, *i))
.collect::<Vec<(&Field, usize)>>();
let modules = get_modules();
let bevy_reflect_path = get_path(&modules.bevy_reflect);
let bevy_reflect_path = BevyManifest::default().get_path("bevy_reflect");
let type_name = &ast.ident;
let mut reflect_attrs = ReflectAttrs::default();
@ -558,15 +555,7 @@ impl Parse for ReflectDef {
pub fn impl_reflect_value(input: TokenStream) -> TokenStream {
let reflect_value_def = parse_macro_input!(input as ReflectDef);
let manifest = Manifest::new().unwrap();
let crate_path = if let Some(package) = manifest.find(|name| name == "bevy") {
format!("{}::reflect", package.name)
} else if let Some(package) = manifest.find(|name| name == "bevy_reflect") {
package.name
} else {
"crate".to_string()
};
let bevy_reflect_path = get_path(&crate_path);
let bevy_reflect_path = BevyManifest::default().get_path("bevy_reflect");
let ty = &reflect_value_def.type_name;
let reflect_attrs = reflect_value_def
.attrs

View file

@ -1,60 +0,0 @@
use find_crate::{Dependencies, Manifest};
use proc_macro::TokenStream;
use syn::Path;
#[derive(Debug)]
pub struct Modules {
pub bevy_reflect: String,
}
impl Modules {
pub fn meta(name: &str) -> Modules {
Modules {
bevy_reflect: format!("{}::reflect", name),
}
}
pub fn external() -> Modules {
Modules {
bevy_reflect: "bevy_reflect".to_string(),
}
}
pub fn internal() -> Modules {
Modules {
bevy_reflect: "crate".to_string(),
}
}
}
pub fn get_modules() -> Modules {
let mut manifest = Manifest::new().unwrap();
// Only look for regular dependencies in the first pass.
manifest.dependencies = Dependencies::Release;
if let Some(package) = manifest.find(|name| name == "bevy") {
Modules::meta(&package.name)
} else if let Some(package) = manifest.find(|name| name == "bevy_internal") {
Modules::meta(&package.name)
} else if let Some(_package) = manifest.find(|name| name == "bevy_reflect") {
Modules::external()
} else {
// If reflect is not found as a regular dependency,
// try dev-dependencies.
manifest.dependencies = Dependencies::Dev;
if let Some(package) = manifest.find(|name| name == "bevy") {
Modules::meta(&package.name)
} else if let Some(package) = manifest.find(|name| name == "bevy_internal") {
Modules::meta(&package.name)
} else if let Some(_package) = manifest.find(|name| name == "bevy_reflect") {
Modules::external()
} else {
Modules::internal()
}
}
}
pub fn get_path(path_str: &str) -> Path {
syn::parse(path_str.parse::<TokenStream>().unwrap()).unwrap()
}

View file

@ -1,10 +1,9 @@
use bevy_macro_utils::BevyManifest;
use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::quote;
use syn::{parse::Parse, parse_macro_input, Attribute, Ident, ItemTrait, Token};
use crate::modules::{get_modules, get_path};
pub struct TraitInfo {
item_trait: ItemTrait,
}
@ -29,8 +28,7 @@ pub fn reflect_trait(_args: TokenStream, input: TokenStream) -> TokenStream {
let trait_ident = &item_trait.ident;
let reflect_trait_ident =
Ident::new(&format!("Reflect{}", item_trait.ident), Span::call_site());
let modules = get_modules();
let bevy_reflect_path = get_path(&modules.bevy_reflect);
let bevy_reflect_path = BevyManifest::default().get_path("bevy_reflect");
TokenStream::from(quote! {
#item_trait

View file

@ -1,17 +1,15 @@
extern crate proc_macro;
use bevy_macro_utils::BevyManifest;
use quote::{quote, ToTokens};
use syn::{parse::*, *};
use uuid::Uuid;
use crate::modules::{get_modules, get_path};
pub 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 ast: DeriveInput = syn::parse(input).unwrap();
let modules = get_modules();
let bevy_reflect_path: Path = get_path(&modules.bevy_reflect);
let bevy_reflect_path: Path = BevyManifest::default().get_path("bevy_reflect");
// Build the trait implementation
let name = &ast.ident;

View file

@ -1,3 +1,4 @@
use crate as bevy_reflect;
use crate::ReflectDeserialize;
use bevy_reflect_derive::impl_reflect_value;
use glam::{IVec2, IVec3, IVec4, Mat3, Mat4, Quat, UVec2, UVec3, UVec4, Vec2, Vec3, Vec4};

View file

@ -1,3 +1,4 @@
use crate as bevy_reflect;
use crate::{
map_partial_eq, serde::Serializable, DynamicMap, FromType, GetTypeRegistration, List, ListIter,
Map, MapIter, Reflect, ReflectDeserialize, ReflectMut, ReflectRef, TypeRegistration,

View file

@ -54,9 +54,9 @@ mod tests {
Deserializer,
};
use crate::serde::{ReflectDeserializer, ReflectSerializer};
use super::*;
use crate as bevy_reflect;
use crate::serde::{ReflectDeserializer, ReflectSerializer};
#[test]
fn reflect_struct() {

View file

@ -308,6 +308,7 @@ fn next_token<'a>(path: &'a str, index: &mut usize) -> Option<Token<'a>> {
#[allow(clippy::float_cmp, clippy::approx_constant)]
mod tests {
use super::GetPath;
use crate as bevy_reflect;
use crate::*;
#[test]
fn reflect_path() {

View file

@ -277,9 +277,9 @@ impl RenderResources for bevy_transform::prelude::GlobalTransform {
#[cfg(test)]
mod test {
use super::*;
use crate as bevy_render;
#[derive(RenderResource, Bytes)]
#[as_crate(bevy_render)]
struct GenericRenderResource<T>
where
T: Bytes + Send + Sync + 'static,
@ -288,7 +288,6 @@ mod test {
}
#[derive(RenderResources)]
#[as_crate(bevy_render)]
struct GenericRenderResources<T>
where
T: RenderResource + Send + Sync + 'static,
@ -298,7 +297,6 @@ mod test {
#[derive(Bytes, RenderResource, RenderResources)]
#[render_resources(from_self)]
#[as_crate(bevy_render)]
struct FromSelfGenericRenderResources<T>
where
T: Bytes + Send + Sync + 'static,

View file

@ -1,6 +1,7 @@
# if crate A depends on crate B, B must come before A in this list
crates=(
bevy_utils
bevy_macro_utils
bevy_derive
bevy_math
bevy_tasks