Skip to content

Commit

Permalink
Use bevy_reflect as path in case of no direct references (#1875)
Browse files Browse the repository at this point in the history
Fixes #1844


Co-authored-by: Carter Anderson <mcanders1@gmail.com>
  • Loading branch information
YohDeadfall and cart committed May 19, 2021
1 parent a42343d commit 653c103
Show file tree
Hide file tree
Showing 25 changed files with 128 additions and 213 deletions.
3 changes: 2 additions & 1 deletion crates/bevy_derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
5 changes: 2 additions & 3 deletions crates/bevy_derive/src/bytes.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand All @@ -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()
Expand Down
5 changes: 2 additions & 3 deletions crates/bevy_derive/src/enum_variant_meta.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand All @@ -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();
Expand Down
12 changes: 6 additions & 6 deletions crates/bevy_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand All @@ -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)
}
76 changes: 5 additions & 71 deletions crates/bevy_derive/src/modules.rs
Original file line number Diff line number Diff line change
@@ -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";
10 changes: 5 additions & 5 deletions crates/bevy_derive/src/render_resource.rs
Original file line number Diff line number Diff line change
@@ -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();

Expand Down
5 changes: 2 additions & 3 deletions crates/bevy_derive/src/render_resources.rs
Original file line number Diff line number Diff line change
@@ -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::{
Expand All @@ -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()
Expand Down
9 changes: 2 additions & 7 deletions crates/bevy_derive/src/resource.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand All @@ -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! {
Expand Down
5 changes: 2 additions & 3 deletions crates/bevy_derive/src/shader_defs.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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 {
Expand Down
3 changes: 2 additions & 1 deletion crates/bevy_ecs/macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
23 changes: 2 additions & 21 deletions crates/bevy_ecs/macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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")
}
2 changes: 1 addition & 1 deletion crates/bevy_ecs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down Expand Up @@ -78,7 +79,6 @@ mod tests {

#[test]
fn bundle_derive() {
use crate as bevy_ecs;
#[derive(Bundle, PartialEq, Debug)]
struct Foo {
x: &'static str,
Expand Down
18 changes: 18 additions & 0 deletions crates/bevy_macro_utils/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"
61 changes: 61 additions & 0 deletions crates/bevy_macro_utils/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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()
}
3 changes: 2 additions & 1 deletion crates/bevy_reflect/bevy_reflect_derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"] }
Loading

0 comments on commit 653c103

Please sign in to comment.