Decouple some dependencies (#3886)

# Objective

Reduce from scratch build time.

## Solution

Reduce the size of the critical path by removing dependencies between crates where not necessary. For `cargo check --no-default-features` this reduced build time from ~51s to ~45s. For some commits I am not completely sure if the tradeoff between build time reduction and convenience caused by the commit is acceptable. If not, I can drop them.
This commit is contained in:
bjorn3 2022-04-27 19:08:11 +00:00
parent f1aae380ab
commit ddce22b614
16 changed files with 138 additions and 60 deletions

View File

@ -1,4 +1,3 @@
use bevy_macro_utils::BevyManifest;
use proc_macro::{Span, TokenStream}; use proc_macro::{Span, TokenStream};
use quote::quote; use quote::quote;
use syn::{parse_macro_input, Data, DeriveInput}; use syn::{parse_macro_input, Data, DeriveInput};
@ -14,8 +13,6 @@ pub fn derive_enum_variant_meta(input: TokenStream) -> TokenStream {
} }
}; };
let bevy_util_path = BevyManifest::default().get_path(crate::modules::BEVY_UTILS);
let generics = ast.generics; let generics = ast.generics;
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
@ -25,13 +22,13 @@ pub fn derive_enum_variant_meta(input: TokenStream) -> TokenStream {
let indices = 0..names.len(); let indices = 0..names.len();
TokenStream::from(quote! { TokenStream::from(quote! {
impl #impl_generics #bevy_util_path::EnumVariantMeta for #struct_name #ty_generics #where_clause { impl #impl_generics #struct_name #ty_generics #where_clause {
fn enum_variant_index(&self) -> usize { pub fn enum_variant_index(&self) -> usize {
match self { match self {
#(#struct_name::#idents {..} => #indices,)* #(#struct_name::#idents {..} => #indices,)*
} }
} }
fn enum_variant_name(&self) -> &'static str { pub fn enum_variant_name(&self) -> &'static str {
static variants: &[&str] = &[ static variants: &[&str] = &[
#(#names,)* #(#names,)*
]; ];

View File

@ -4,13 +4,12 @@ mod app_plugin;
mod bevy_main; mod bevy_main;
mod derefs; mod derefs;
mod enum_variant_meta; mod enum_variant_meta;
mod modules;
use bevy_macro_utils::{derive_label, BevyManifest}; use bevy_macro_utils::{derive_label, BevyManifest};
use proc_macro::TokenStream; use proc_macro::TokenStream;
use quote::format_ident; use quote::format_ident;
/// Generates a dynamic plugin entry point function for the given `Plugin` type. /// Generates a dynamic plugin entry point function for the given `Plugin` type.
#[proc_macro_derive(DynamicPlugin)] #[proc_macro_derive(DynamicPlugin)]
pub fn derive_dynamic_plugin(input: TokenStream) -> TokenStream { pub fn derive_dynamic_plugin(input: TokenStream) -> TokenStream {
app_plugin::derive_dynamic_plugin(input) app_plugin::derive_dynamic_plugin(input)

View File

@ -1 +0,0 @@
pub const BEVY_UTILS: &str = "bevy_utils";

View File

@ -22,7 +22,6 @@ bevy_ecs_macros = { path = "macros", version = "0.8.0-dev" }
async-channel = "1.4" async-channel = "1.4"
fixedbitset = "0.4" fixedbitset = "0.4"
fxhash = "0.2" fxhash = "0.2"
thiserror = "1.0"
downcast-rs = "1.2" downcast-rs = "1.2"
serde = "1" serde = "1"

View File

@ -1,13 +1,24 @@
use crate::entity::Entity; use crate::entity::Entity;
use bevy_utils::{Entry, HashMap}; use bevy_utils::{Entry, HashMap};
use thiserror::Error; use std::fmt;
#[derive(Error, Debug)] #[derive(Debug)]
pub enum MapEntitiesError { pub enum MapEntitiesError {
#[error("the given entity does not exist in the map")]
EntityNotFound(Entity), EntityNotFound(Entity),
} }
impl std::error::Error for MapEntitiesError {}
impl fmt::Display for MapEntitiesError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
MapEntitiesError::EntityNotFound(_) => {
write!(f, "the given entity does not exist in the map")
}
}
}
}
pub trait MapEntities { pub trait MapEntities {
fn map_entities(&mut self, entity_map: &EntityMap) -> Result<(), MapEntitiesError>; fn map_entities(&mut self, entity_map: &EntityMap) -> Result<(), MapEntitiesError>;
} }

View File

@ -12,7 +12,7 @@ use crate::{
}; };
use bevy_tasks::TaskPool; use bevy_tasks::TaskPool;
use fixedbitset::FixedBitSet; use fixedbitset::FixedBitSet;
use thiserror::Error; use std::fmt;
/// Provides scoped access to a [`World`] state according to a given [`WorldQuery`] and query filter. /// Provides scoped access to a [`World`] state according to a given [`WorldQuery`] and query filter.
pub struct QueryState<Q: WorldQuery, F: WorldQuery = ()> pub struct QueryState<Q: WorldQuery, F: WorldQuery = ()>
@ -936,16 +936,29 @@ where
/// An error that occurs when retrieving a specific [`Entity`]'s query result. /// An error that occurs when retrieving a specific [`Entity`]'s query result.
// TODO: return the type_name as part of this error // TODO: return the type_name as part of this error
#[derive(Error, Debug, PartialEq, Clone, Copy)] #[derive(Debug, PartialEq, Clone, Copy)]
pub enum QueryEntityError { pub enum QueryEntityError {
#[error("The given entity does not have the requested component.")]
QueryDoesNotMatch(Entity), QueryDoesNotMatch(Entity),
#[error("The requested entity does not exist.")]
NoSuchEntity(Entity), NoSuchEntity(Entity),
#[error("The entity was requested mutably more than once.")]
AliasedMutability(Entity), AliasedMutability(Entity),
} }
impl std::error::Error for QueryEntityError {}
impl fmt::Display for QueryEntityError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
QueryEntityError::QueryDoesNotMatch(_) => {
write!(f, "The given entity does not have the requested component.")
}
QueryEntityError::NoSuchEntity(_) => write!(f, "The requested entity does not exist."),
QueryEntityError::AliasedMutability(_) => {
write!(f, "The entity was requested mutably more than once.")
}
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{prelude::*, query::QueryEntityError}; use crate::{prelude::*, query::QueryEntityError};

View File

@ -5,8 +5,11 @@ use crate::{
}, },
system::{In, IntoChainSystem, Local, Res, ResMut}, system::{In, IntoChainSystem, Local, Res, ResMut},
}; };
use std::{any::TypeId, fmt::Debug, hash::Hash}; use std::{
use thiserror::Error; any::TypeId,
fmt::{self, Debug},
hash::Hash,
};
pub trait StateData: Send + Sync + Clone + Eq + Debug + Hash + 'static {} pub trait StateData: Send + Sync + Clone + Eq + Debug + Hash + 'static {}
impl<T> StateData for T where T: Send + Sync + Clone + Eq + Debug + Hash + 'static {} impl<T> StateData for T where T: Send + Sync + Clone + Eq + Debug + Hash + 'static {}
@ -399,16 +402,32 @@ where
} }
} }
#[derive(Debug, Error)] #[derive(Debug)]
pub enum StateError { pub enum StateError {
#[error("Attempted to change the state to the current state.")]
AlreadyInState, AlreadyInState,
#[error("Attempted to queue a state change, but there was already a state queued.")]
StateAlreadyQueued, StateAlreadyQueued,
#[error("Attempted to queue a pop, but there is nothing to pop.")]
StackEmpty, StackEmpty,
} }
impl std::error::Error for StateError {}
impl fmt::Display for StateError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
StateError::AlreadyInState => {
write!(f, "Attempted to change the state to the current state.")
}
StateError::StateAlreadyQueued => write!(
f,
"Attempted to queue a state change, but there was already a state queued."
),
StateError::StackEmpty => {
write!(f, "Attempted to queue a pop, but there is nothing to pop.")
}
}
}
}
fn should_run_adapter<T: StateData>(In(cmp_result): In<bool>, state: Res<State<T>>) -> ShouldRun { fn should_run_adapter<T: StateData>(In(cmp_result): In<bool>, state: Res<State<T>>) -> ShouldRun {
if state.end_next_loop { if state.end_next_loop {
return ShouldRun::No; return ShouldRun::No;

View File

@ -9,7 +9,6 @@ use crate::{
}; };
use bevy_tasks::TaskPool; use bevy_tasks::TaskPool;
use std::{any::TypeId, fmt::Debug}; use std::{any::TypeId, fmt::Debug};
use thiserror::Error;
/// Provides scoped access to components in a [`World`]. /// Provides scoped access to components in a [`World`].
/// ///
@ -670,7 +669,7 @@ where
/// for (targeting_entity, targets, origin) in targeting_query.iter(){ /// for (targeting_entity, targets, origin) in targeting_query.iter(){
/// // We can use "destructuring" to unpack the results nicely /// // We can use "destructuring" to unpack the results nicely
/// let [target_1, target_2, target_3] = targets_query.many(targets.0); /// let [target_1, target_2, target_3] = targets_query.many(targets.0);
/// ///
/// assert!(target_1.distance(origin) <= 5); /// assert!(target_1.distance(origin) <= 5);
/// assert!(target_2.distance(origin) <= 5); /// assert!(target_2.distance(origin) <= 5);
/// assert!(target_3.distance(origin) <= 5); /// assert!(target_3.distance(origin) <= 5);
@ -779,10 +778,10 @@ where
/// for spring in spring_query.iter(){ /// for spring in spring_query.iter(){
/// // We can use "destructuring" to unpack our query items nicely /// // We can use "destructuring" to unpack our query items nicely
/// let [(position_1, mut force_1), (position_2, mut force_2)] = mass_query.many_mut(spring.connected_entities); /// let [(position_1, mut force_1), (position_2, mut force_2)] = mass_query.many_mut(spring.connected_entities);
/// ///
/// force_1.x += spring.strength * (position_1.x - position_2.x); /// force_1.x += spring.strength * (position_1.x - position_2.x);
/// force_1.y += spring.strength * (position_1.y - position_2.y); /// force_1.y += spring.strength * (position_1.y - position_2.y);
/// ///
/// // Silence borrow-checker: I have split your mutable borrow! /// // Silence borrow-checker: I have split your mutable borrow!
/// force_2.x += spring.strength * (position_2.x - position_1.x); /// force_2.x += spring.strength * (position_2.x - position_1.x);
/// force_2.y += spring.strength * (position_2.y - position_1.y); /// force_2.y += spring.strength * (position_2.y - position_1.y);
@ -1157,28 +1156,61 @@ where
} }
/// An error that occurs when retrieving a specific [`Entity`]'s component from a [`Query`] /// An error that occurs when retrieving a specific [`Entity`]'s component from a [`Query`]
#[derive(Error, Debug)] #[derive(Debug)]
pub enum QueryComponentError { pub enum QueryComponentError {
#[error("This query does not have read access to the requested component.")]
MissingReadAccess, MissingReadAccess,
#[error("This query does not have write access to the requested component.")]
MissingWriteAccess, MissingWriteAccess,
#[error("The given entity does not have the requested component.")]
MissingComponent, MissingComponent,
#[error("The requested entity does not exist.")]
NoSuchEntity, NoSuchEntity,
} }
impl std::error::Error for QueryComponentError {}
impl std::fmt::Display for QueryComponentError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
QueryComponentError::MissingReadAccess => {
write!(
f,
"This query does not have read access to the requested component."
)
}
QueryComponentError::MissingWriteAccess => {
write!(
f,
"This query does not have write access to the requested component."
)
}
QueryComponentError::MissingComponent => {
write!(f, "The given entity does not have the requested component.")
}
QueryComponentError::NoSuchEntity => {
write!(f, "The requested entity does not exist.")
}
}
}
}
/// An error that occurs when evaluating a [`Query`] as a single expected resulted via /// An error that occurs when evaluating a [`Query`] as a single expected resulted via
/// [`Query::single`] or [`Query::single_mut`]. /// [`Query::single`] or [`Query::single_mut`].
#[derive(Debug, Error)] #[derive(Debug)]
pub enum QuerySingleError { pub enum QuerySingleError {
#[error("No entities fit the query {0}")]
NoEntities(&'static str), NoEntities(&'static str),
#[error("Multiple entities fit the query {0}!")]
MultipleEntities(&'static str), MultipleEntities(&'static str),
} }
impl std::error::Error for QuerySingleError {}
impl std::fmt::Display for QuerySingleError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
QuerySingleError::NoEntities(query) => write!(f, "No entities fit the query {}", query),
QuerySingleError::MultipleEntities(query) => {
write!(f, "Multiple entities fit the query {}!", query)
}
}
}
}
impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F> impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F>
where where
F::Fetch: FilterFetch, F::Fetch: FilterFetch,

View File

@ -9,6 +9,6 @@ license = "MIT OR Apache-2.0"
keywords = ["bevy"] keywords = ["bevy"]
[dependencies] [dependencies]
cargo-manifest = "0.2.6" toml = "0.5.8"
syn = "1.0" syn = "1.0"
quote = "1.0" quote = "1.0"

View File

@ -8,13 +8,13 @@ pub use attrs::*;
pub use shape::*; pub use shape::*;
pub use symbol::*; pub use symbol::*;
use cargo_manifest::{DepsSet, Manifest};
use proc_macro::TokenStream; use proc_macro::TokenStream;
use quote::quote; use quote::quote;
use std::{env, path::PathBuf}; use std::{env, path::PathBuf};
use toml::{map::Map, Value};
pub struct BevyManifest { pub struct BevyManifest {
manifest: Manifest, manifest: Map<String, Value>,
} }
impl Default for BevyManifest { impl Default for BevyManifest {
@ -24,7 +24,8 @@ impl Default for BevyManifest {
.map(PathBuf::from) .map(PathBuf::from)
.map(|mut path| { .map(|mut path| {
path.push("Cargo.toml"); path.push("Cargo.toml");
Manifest::from_path(path).unwrap() let manifest = std::fs::read_to_string(path).unwrap();
toml::from_str(&manifest).unwrap()
}) })
.unwrap(), .unwrap(),
} }
@ -36,13 +37,24 @@ impl BevyManifest {
const BEVY: &str = "bevy"; const BEVY: &str = "bevy";
const BEVY_INTERNAL: &str = "bevy_internal"; const BEVY_INTERNAL: &str = "bevy_internal";
let find_in_deps = |deps: &DepsSet| -> Option<syn::Path> { 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> {
let package = if let Some(dep) = deps.get(name) { let package = if let Some(dep) = deps.get(name) {
return Some(Self::parse_str(dep.package().unwrap_or(name))); return Some(Self::parse_str(dep_package(dep).unwrap_or(name)));
} else if let Some(dep) = deps.get(BEVY) { } else if let Some(dep) = deps.get(BEVY) {
dep.package().unwrap_or(BEVY) dep_package(dep).unwrap_or(BEVY)
} else if let Some(dep) = deps.get(BEVY_INTERNAL) { } else if let Some(dep) = deps.get(BEVY_INTERNAL) {
dep.package().unwrap_or(BEVY_INTERNAL) dep_package(dep).unwrap_or(BEVY_INTERNAL)
} else { } else {
return None; return None;
}; };
@ -54,8 +66,14 @@ impl BevyManifest {
Some(path) Some(path)
}; };
let deps = self.manifest.dependencies.as_ref(); let deps = self
let deps_dev = self.manifest.dev_dependencies.as_ref(); .manifest
.get("dependencies")
.map(|deps| deps.as_table().unwrap());
let deps_dev = self
.manifest
.get("dev-dependencies")
.map(|deps| deps.as_table().unwrap());
deps.and_then(find_in_deps) deps.and_then(find_in_deps)
.or_else(|| deps_dev.and_then(find_in_deps)) .or_else(|| deps_dev.and_then(find_in_deps))

View File

@ -17,4 +17,4 @@ bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.8.0-dev" }
syn = { version = "1.0", features = ["full"] } syn = { version = "1.0", features = ["full"] }
proc-macro2 = "1.0" proc-macro2 = "1.0"
quote = "1.0" quote = "1.0"
uuid = { version = "0.8", features = ["v4", "serde"] } uuid = { version = "0.8", features = ["v4"] }

View File

@ -25,7 +25,6 @@
//! ``` //! ```
use crate::mesh::VertexAttributeValues; use crate::mesh::VertexAttributeValues;
use bevy_utils::EnumVariantMeta;
use thiserror::Error; use thiserror::Error;
#[derive(Debug, Clone, Error)] #[derive(Debug, Clone, Error)]

View File

@ -9,10 +9,11 @@ use crate::{
renderer::RenderDevice, renderer::RenderDevice,
}; };
use bevy_core::cast_slice; use bevy_core::cast_slice;
use bevy_derive::EnumVariantMeta;
use bevy_ecs::system::{lifetimeless::SRes, SystemParamItem}; use bevy_ecs::system::{lifetimeless::SRes, SystemParamItem};
use bevy_math::*; use bevy_math::*;
use bevy_reflect::TypeUuid; use bevy_reflect::TypeUuid;
use bevy_utils::{EnumVariantMeta, Hashed}; use bevy_utils::Hashed;
use std::{collections::BTreeMap, hash::Hash}; use std::{collections::BTreeMap, hash::Hash};
use thiserror::Error; use thiserror::Error;
use wgpu::{ use wgpu::{

View File

@ -9,9 +9,8 @@ license = "MIT OR Apache-2.0"
keywords = ["bevy"] keywords = ["bevy"]
[dependencies] [dependencies]
bevy_derive = { path = "../bevy_derive", version = "0.8.0-dev" }
ahash = "0.7.0" ahash = "0.7.0"
tracing = { version = "0.1" } tracing = { version = "0.1", default-features = false, features = ["std"] }
instant = { version = "0.1", features = ["wasm-bindgen"] } instant = { version = "0.1", features = ["wasm-bindgen"] }
uuid = { version = "0.8", features = ["v4", "serde"] } uuid = { version = "0.8", features = ["v4", "serde"] }
hashbrown = { version = "0.11", features = ["serde"] } hashbrown = { version = "0.11", features = ["serde"] }

View File

@ -1,6 +0,0 @@
pub use bevy_derive::EnumVariantMeta;
pub trait EnumVariantMeta {
fn enum_variant_index(&self) -> usize;
fn enum_variant_name(&self) -> &'static str;
}

View File

@ -6,12 +6,10 @@ pub mod futures;
pub mod label; pub mod label;
mod default; mod default;
mod enum_variant_meta;
mod float_ord; mod float_ord;
pub use ahash::AHasher; pub use ahash::AHasher;
pub use default::default; pub use default::default;
pub use enum_variant_meta::*;
pub use float_ord::*; pub use float_ord::*;
pub use hashbrown; pub use hashbrown;
pub use instant::{Duration, Instant}; pub use instant::{Duration, Instant};
@ -201,7 +199,7 @@ pub type PreHashMap<K, V> = hashbrown::HashMap<Hashed<K>, V, PassHash>;
pub trait PreHashMapExt<K, V> { pub trait PreHashMapExt<K, V> {
/// Tries to get or insert the value for the given `key` using the pre-computed hash first. /// Tries to get or insert the value for the given `key` using the pre-computed hash first.
/// If the [`PreHashMap`] does not already contain the `key`, it will clone it and insert /// If the [`PreHashMap`] does not already contain the `key`, it will clone it and insert
/// the value returned by `func`. /// the value returned by `func`.
fn get_or_insert_with<F: FnOnce() -> V>(&mut self, key: &Hashed<K>, func: F) -> &mut V; fn get_or_insert_with<F: FnOnce() -> V>(&mut self, key: &Hashed<K>, func: F) -> &mut V;
} }