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 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};
|
2022-04-27 19:08:11 +00:00
|
|
|
use toml::{map::Map, Value};
|
2021-05-19 19:03:36 +00:00
|
|
|
|
|
|
|
pub struct BevyManifest {
|
2022-04-27 19:08:11 +00:00
|
|
|
manifest: Map<String, Value>,
|
2021-05-19 19:03:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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");
|
2022-04-27 19:08:11 +00:00
|
|
|
let manifest = std::fs::read_to_string(path).unwrap();
|
|
|
|
toml::from_str(&manifest).unwrap()
|
2021-05-19 19:03:36 +00:00
|
|
|
})
|
|
|
|
.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";
|
|
|
|
|
2022-04-27 19:08:11 +00:00
|
|
|
fn dep_package(dep: &Value) -> Option<&str> {
|
|
|
|
if dep.as_str().is_some() {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
dep.as_table()
|
|
|
|
.unwrap()
|
|
|
|
.get("package")
|
|
|
|
.map(|name| name.as_str().unwrap())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let find_in_deps = |deps: &Map<String, Value>| -> 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) {
|
2022-04-27 19:08:11 +00:00
|
|
|
return Some(Self::parse_str(dep_package(dep).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) {
|
2022-04-27 19:08:11 +00:00
|
|
|
dep_package(dep).unwrap_or(BEVY)
|
2021-05-19 19:03:36 +00:00
|
|
|
} else if let Some(dep) = deps.get(BEVY_INTERNAL) {
|
2022-04-27 19:08:11 +00:00
|
|
|
dep_package(dep).unwrap_or(BEVY_INTERNAL)
|
2021-05-19 19:03:36 +00:00
|
|
|
} 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)
|
|
|
|
};
|
|
|
|
|
2022-04-27 19:08:11 +00:00
|
|
|
let deps = self
|
|
|
|
.manifest
|
|
|
|
.get("dependencies")
|
|
|
|
.map(|deps| deps.as_table().unwrap());
|
|
|
|
let deps_dev = self
|
|
|
|
.manifest
|
|
|
|
.get("dev-dependencies")
|
|
|
|
.map(|deps| deps.as_table().unwrap());
|
2021-05-19 19:03:36 +00:00
|
|
|
|
|
|
|
deps.and_then(find_in_deps)
|
|
|
|
.or_else(|| deps_dev.and_then(find_in_deps))
|
|
|
|
}
|
bevy_reflect_derive: Tidying up the code (#4712)
# Objective
The `bevy_reflect_derive` crate is not the cleanest or easiest to follow/maintain. The `lib.rs` file is especially difficult with over 1000 lines of code written in a confusing order. This is just a result of growth within the crate and it would be nice to clean it up for future work.
## Solution
Split `bevy_reflect_derive` into many more submodules. The submodules include:
* `container_attributes` - Code relating to container attributes
* `derive_data` - Code relating to reflection-based derive metadata
* `field_attributes` - Code relating to field attributes
* `impls` - Code containing actual reflection implementations
* `reflect_value` - Code relating to reflection-based value metadata
* `registration` - Code relating to type registration
* `utility` - General-purpose utility functions
This leaves the `lib.rs` file to contain only the public macros, making it much easier to digest (and fewer than 200 lines).
By breaking up the code into smaller modules, we make it easier for future contributors to find the code they're looking for or identify which module best fits their own additions.
### Metadata Structs
This cleanup also adds two big metadata structs: `ReflectFieldAttr` and `ReflectDeriveData`. The former is used to store all attributes for a struct field (if any). The latter is used to store all metadata for struct-based derive inputs.
Both significantly reduce code duplication and make editing these macros much simpler. The tradeoff is that we may collect more metadata than needed. However, this is usually a small thing (such as checking for attributes when they're not really needed or creating a `ReflectFieldAttr` for every field regardless of whether they actually have an attribute).
We could try to remove these tradeoffs and squeeze some more performance out, but doing so might come at the cost of developer experience. Personally, I think it's much nicer to create a `ReflectFieldAttr` for every field since it means I don't have to do two `Option` checks. Others may disagree, though, and so we can discuss changing this either in this PR or in a future one.
### Out of Scope
_Some_ documentation has been added or improved, but ultimately good docs are probably best saved for a dedicated PR.
## 🔍 Focus Points (for reviewers)
I know it's a lot to sift through, so here is a list of **key points for reviewers**:
- The following files contain code that was mostly just relocated:
- `reflect_value.rs`
- `registration.rs`
- `container_attributes.rs` was also mostly moved but features some general cleanup (reducing nesting, removing hardcoded strings, etc.) and lots of doc comments
- Most impl logic was moved from `lib.rs` to `impls.rs`, but they have been significantly modified to use the new `ReflectDeriveData` metadata struct in order to reduce duplication.
- `derive_data.rs` and `field_attributes.rs` contain almost entirely new code and should probably be given the most attention.
- Likewise, `from_reflect.rs` saw major changes using `ReflectDeriveData` so it should also be given focus.
- There was no change to the `lib.rs` exports so the end-user API should be the same.
## Prior Work
This task was initially tackled by @NathanSWard in #2377 (which was closed in favor of this PR), so hats off to them for beating me to the punch by nearly a year!
---
## Changelog
* **[INTERNAL]** Split `bevy_reflect_derive` into smaller submodules
* **[INTERNAL]** Add `ReflectFieldAttr`
* **[INTERNAL]** Add `ReflectDeriveData`
* Add `BevyManifest::get_path_direct()` method (`bevy_macro_utils`)
Co-authored-by: MrGVSV <49806985+MrGVSV@users.noreply.github.com>
2022-05-12 19:43:23 +00:00
|
|
|
|
|
|
|
/// Returns the path for the crate with the given name.
|
|
|
|
///
|
|
|
|
/// This is a convenience method for constructing a [manifest] and
|
|
|
|
/// calling the [`get_path`] method.
|
|
|
|
///
|
|
|
|
/// This method should only be used where you just need the path and can't
|
|
|
|
/// cache the [manifest]. If caching is possible, it's recommended to create
|
|
|
|
/// the [manifest] yourself and use the [`get_path`] method.
|
|
|
|
///
|
|
|
|
/// [`get_path`]: Self::get_path
|
|
|
|
/// [manifest]: Self
|
|
|
|
pub fn get_path_direct(name: &str) -> syn::Path {
|
|
|
|
Self::default().get_path(name)
|
|
|
|
}
|
|
|
|
|
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(),
|
|
|
|
});
|
Simplify design for `*Label`s (#4957)
# Objective
- Closes #4954
- Reduce the complexity of the `{System, App, *}Label` APIs.
## Solution
For the sake of brevity I will only refer to `SystemLabel`, but everything applies to all of the other label types as well.
- Add `SystemLabelId`, a lightweight, `copy` struct.
- Convert custom types into `SystemLabelId` using the trait `SystemLabel`.
## Changelog
- String literals implement `SystemLabel` for now, but this should be changed with #4409 .
## Migration Guide
- Any previous use of `Box<dyn SystemLabel>` should be replaced with `SystemLabelId`.
- `AsSystemLabel` trait has been modified.
- No more output generics.
- Method `as_system_label` now returns `SystemLabelId`, removing an unnecessary level of indirection.
- If you *need* a label that is determined at runtime, you can use `Box::leak`. Not recommended.
## Questions for later
* Should we generate a `Debug` impl along with `#[derive(*Label)]`?
* Should we rename `as_str()`?
* Should we remove the extra derives (such as `Hash`) from builtin `*Label` types?
* Should we automatically derive types like `Clone, Copy, PartialEq, Eq`?
* More-ergonomic comparisons between `Label` and `LabelId`.
* Move `Dyn{Eq, Hash,Clone}` somewhere else.
* Some API to make interning dynamic labels easier.
* Optimize string representation
* Empty string for unit structs -- no debug info but faster comparisons
* Don't show enum types -- same tradeoffs as asbove.
2022-07-14 18:23:01 +00:00
|
|
|
where_clause
|
|
|
|
.predicates
|
|
|
|
.push(syn::parse2(quote! { Self: 'static }).unwrap());
|
|
|
|
|
|
|
|
let as_str = match input.data {
|
|
|
|
syn::Data::Struct(d) => match d.fields {
|
|
|
|
syn::Fields::Unit => {
|
|
|
|
let lit = ident.to_string();
|
|
|
|
quote! { #lit }
|
|
|
|
}
|
|
|
|
_ => panic!("Labels cannot contain data."),
|
|
|
|
},
|
|
|
|
syn::Data::Enum(d) => {
|
|
|
|
let arms = d.variants.iter().map(|v| match v.fields {
|
|
|
|
syn::Fields::Unit => {
|
|
|
|
let mut path = syn::Path::from(ident.clone());
|
|
|
|
path.segments.push(v.ident.clone().into());
|
|
|
|
let lit = format!("{ident}::{}", v.ident.clone());
|
|
|
|
quote! { #path => #lit }
|
|
|
|
}
|
|
|
|
_ => panic!("Label variants cannot contain data."),
|
|
|
|
});
|
|
|
|
quote! {
|
|
|
|
match self {
|
|
|
|
#(#arms),*
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
syn::Data::Union(_) => panic!("Unions cannot be used as labels."),
|
|
|
|
};
|
2021-08-24 00:31:21 +00:00
|
|
|
|
|
|
|
(quote! {
|
|
|
|
impl #impl_generics #trait_path for #ident #ty_generics #where_clause {
|
Simplify design for `*Label`s (#4957)
# Objective
- Closes #4954
- Reduce the complexity of the `{System, App, *}Label` APIs.
## Solution
For the sake of brevity I will only refer to `SystemLabel`, but everything applies to all of the other label types as well.
- Add `SystemLabelId`, a lightweight, `copy` struct.
- Convert custom types into `SystemLabelId` using the trait `SystemLabel`.
## Changelog
- String literals implement `SystemLabel` for now, but this should be changed with #4409 .
## Migration Guide
- Any previous use of `Box<dyn SystemLabel>` should be replaced with `SystemLabelId`.
- `AsSystemLabel` trait has been modified.
- No more output generics.
- Method `as_system_label` now returns `SystemLabelId`, removing an unnecessary level of indirection.
- If you *need* a label that is determined at runtime, you can use `Box::leak`. Not recommended.
## Questions for later
* Should we generate a `Debug` impl along with `#[derive(*Label)]`?
* Should we rename `as_str()`?
* Should we remove the extra derives (such as `Hash`) from builtin `*Label` types?
* Should we automatically derive types like `Clone, Copy, PartialEq, Eq`?
* More-ergonomic comparisons between `Label` and `LabelId`.
* Move `Dyn{Eq, Hash,Clone}` somewhere else.
* Some API to make interning dynamic labels easier.
* Optimize string representation
* Empty string for unit structs -- no debug info but faster comparisons
* Don't show enum types -- same tradeoffs as asbove.
2022-07-14 18:23:01 +00:00
|
|
|
fn as_str(&self) -> &'static str {
|
|
|
|
#as_str
|
2021-08-24 00:31:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.into()
|
|
|
|
}
|