2021-05-19 19:03:36 +00:00
|
|
|
extern crate proc_macro;
|
|
|
|
|
2021-10-03 19:23:44 +00:00
|
|
|
mod attrs;
|
2022-01-15 22:14:43 +00:00
|
|
|
mod shape;
|
2021-10-03 19:23:44 +00:00
|
|
|
mod symbol;
|
|
|
|
|
|
|
|
pub use attrs::*;
|
2022-01-15 22:14:43 +00:00
|
|
|
pub use shape::*;
|
2021-10-03 19:23:44 +00:00
|
|
|
pub use symbol::*;
|
|
|
|
|
2021-05-19 19:03:36 +00:00
|
|
|
use cargo_manifest::{DepsSet, Manifest};
|
|
|
|
use proc_macro::TokenStream;
|
2021-08-24 00:31:21 +00:00
|
|
|
use quote::quote;
|
2021-05-19 19:03:36 +00:00
|
|
|
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 {
|
2021-12-23 22:49:12 +00:00
|
|
|
pub fn maybe_get_path(&self, name: &str) -> Option<syn::Path> {
|
2021-05-19 19:03:36 +00:00
|
|
|
const BEVY: &str = "bevy";
|
|
|
|
const BEVY_INTERNAL: &str = "bevy_internal";
|
|
|
|
|
|
|
|
let find_in_deps = |deps: &DepsSet| -> Option<syn::Path> {
|
Fix path used by macro not considering that we can use a sub-crate (#3178)
# Problem
Let's say I am writting a simple bevy plugin, and I want to depend on `bevy_ecs` crate instead of depending on the full `bevy`.
So I write the following:
*Cargo.toml*:
```toml
[dependencies]
bevy_ecs = { git = "https://github.com/bevyengine/bevy.git", rev = "94db0176fecfac7e7e9763f2dc7458a54c105886" }
```
*lib.rs*:
```rust
use bevy_ecs::prelude::*;
#[derive(Debug, Default, Component)
pub struct MyFancyComponent;
```
So far, so good. Everything works. But let's say I want to write some examples for using my plugin. And for theses I'd like to use the `bevy` crate, so that I can write complete examples (rendering stuff, etc.) that are simple and look like what the consumer of my plugin will do (`use bevy::prelude::*` and `DefaultPlugins`)
So I amend my *Cargo.toml*:
```toml
[dependencies]
bevy_ecs = { git = "https://github.com/bevyengine/bevy.git", rev = "94db0176fecfac7e7e9763f2dc7458a54c105886" }
[dev-dependencies]
bevy = { git = "https://github.com/bevyengine/bevy.git", rev = "94db0176fecfac7e7e9763f2dc7458a54c105886", default-features = false }
```
And that leads to a complilation error
```
error[E0433]: failed to resolve: use of undeclared crate or module `bevy`
```
Basically, because `bevy` is in the `dev-dependencies`, the macro (of the production code) decides to use the `bevy::ecs` path instead of `bevy_ecs`. But `bevy` is not available there.
## Solution
This PR fixes the problem. I amend the macro utility responsible of finding the path of a module.
If we try to find a path, we first test if this correspond to a crate that the user directly depend on. (Like, if we search for `bevy_ecs`, we first check if there is a `bevy_ecs` dependency). If yes, we can depend on that directly. Otherwise, we proceed with the existing logic (testing `bevy` and `bevy_internal`)
2021-11-29 23:10:31 +00:00
|
|
|
let package = if let Some(dep) = deps.get(name) {
|
2021-12-23 22:49:12 +00:00
|
|
|
return Some(Self::parse_str(dep.package().unwrap_or(name)));
|
Fix path used by macro not considering that we can use a sub-crate (#3178)
# Problem
Let's say I am writting a simple bevy plugin, and I want to depend on `bevy_ecs` crate instead of depending on the full `bevy`.
So I write the following:
*Cargo.toml*:
```toml
[dependencies]
bevy_ecs = { git = "https://github.com/bevyengine/bevy.git", rev = "94db0176fecfac7e7e9763f2dc7458a54c105886" }
```
*lib.rs*:
```rust
use bevy_ecs::prelude::*;
#[derive(Debug, Default, Component)
pub struct MyFancyComponent;
```
So far, so good. Everything works. But let's say I want to write some examples for using my plugin. And for theses I'd like to use the `bevy` crate, so that I can write complete examples (rendering stuff, etc.) that are simple and look like what the consumer of my plugin will do (`use bevy::prelude::*` and `DefaultPlugins`)
So I amend my *Cargo.toml*:
```toml
[dependencies]
bevy_ecs = { git = "https://github.com/bevyengine/bevy.git", rev = "94db0176fecfac7e7e9763f2dc7458a54c105886" }
[dev-dependencies]
bevy = { git = "https://github.com/bevyengine/bevy.git", rev = "94db0176fecfac7e7e9763f2dc7458a54c105886", default-features = false }
```
And that leads to a complilation error
```
error[E0433]: failed to resolve: use of undeclared crate or module `bevy`
```
Basically, because `bevy` is in the `dev-dependencies`, the macro (of the production code) decides to use the `bevy::ecs` path instead of `bevy_ecs`. But `bevy` is not available there.
## Solution
This PR fixes the problem. I amend the macro utility responsible of finding the path of a module.
If we try to find a path, we first test if this correspond to a crate that the user directly depend on. (Like, if we search for `bevy_ecs`, we first check if there is a `bevy_ecs` dependency). If yes, we can depend on that directly. Otherwise, we proceed with the existing logic (testing `bevy` and `bevy_internal`)
2021-11-29 23:10:31 +00:00
|
|
|
} else if let Some(dep) = deps.get(BEVY) {
|
2021-05-19 19:03:36 +00:00
|
|
|
dep.package().unwrap_or(BEVY)
|
|
|
|
} else if let Some(dep) = deps.get(BEVY_INTERNAL) {
|
|
|
|
dep.package().unwrap_or(BEVY_INTERNAL)
|
|
|
|
} else {
|
|
|
|
return None;
|
|
|
|
};
|
|
|
|
|
2021-12-23 22:49:12 +00:00
|
|
|
let mut path = Self::parse_str::<syn::Path>(package);
|
2021-05-19 19:03:36 +00:00
|
|
|
if let Some(module) = name.strip_prefix("bevy_") {
|
2021-12-23 22:49:12 +00:00
|
|
|
path.segments.push(Self::parse_str(module));
|
2021-05-19 19:03:36 +00:00
|
|
|
}
|
|
|
|
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))
|
|
|
|
}
|
2021-12-23 22:49:12 +00:00
|
|
|
pub fn get_path(&self, name: &str) -> syn::Path {
|
|
|
|
self.maybe_get_path(name)
|
|
|
|
.unwrap_or_else(|| Self::parse_str(name))
|
|
|
|
}
|
2021-05-19 19:03:36 +00:00
|
|
|
|
2021-12-23 22:49:12 +00:00
|
|
|
pub fn parse_str<T: syn::parse::Parse>(path: &str) -> T {
|
|
|
|
syn::parse(path.parse::<TokenStream>().unwrap()).unwrap()
|
|
|
|
}
|
2021-05-19 19:03:36 +00:00
|
|
|
}
|
2021-08-24 00:31:21 +00:00
|
|
|
|
|
|
|
/// Derive a label trait
|
|
|
|
///
|
|
|
|
/// # Args
|
|
|
|
///
|
|
|
|
/// - `input`: The [`syn::DeriveInput`] for struct that is deriving the label trait
|
|
|
|
/// - `trait_path`: The path [`syn::Path`] to the label trait
|
2022-02-13 22:33:55 +00:00
|
|
|
pub fn derive_label(input: syn::DeriveInput, trait_path: &syn::Path) -> TokenStream {
|
2021-08-24 00:31:21 +00:00
|
|
|
let ident = input.ident;
|
|
|
|
|
|
|
|
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
|
|
|
|
let mut where_clause = where_clause.cloned().unwrap_or_else(|| syn::WhereClause {
|
|
|
|
where_token: Default::default(),
|
|
|
|
predicates: Default::default(),
|
|
|
|
});
|
|
|
|
where_clause.predicates.push(syn::parse2(quote! { Self: Eq + ::std::fmt::Debug + ::std::hash::Hash + Clone + Send + Sync + 'static }).unwrap());
|
|
|
|
|
|
|
|
(quote! {
|
|
|
|
impl #impl_generics #trait_path for #ident #ty_generics #where_clause {
|
2022-01-04 19:49:37 +00:00
|
|
|
fn dyn_clone(&self) -> std::boxed::Box<dyn #trait_path> {
|
|
|
|
std::boxed::Box::new(std::clone::Clone::clone(self))
|
2021-08-24 00:31:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.into()
|
|
|
|
}
|