ECS: put strings only used for debug behind a feature (#19558)
# Objective - Many strings in bevy_ecs are created but only used for debug: system name, component name, ... - Those strings make a significant part of the final binary and are no use in a released game ## Solution - Use [`strings`](https://linux.die.net/man/1/strings) to find ... strings in a binary - Try to find where they come from - Many are made from `type_name::<T>()` and only used in error / debug messages - Add a new structure `DebugName` that holds no value if `debug` feature is disabled - Replace `core::any::type_name::<T>()` by `DebugName::type_name::<T>()` ## Testing Measurements were taken without the new feature being enabled by default, to help with commands ### File Size I tried building the `breakout` example with `cargo run --release --example breakout` |`debug` enabled|`debug` disabled| |-|-| |81621776 B|77735728B| |77.84MB|74.13MB| ### Compilation time `hyperfine --min-runs 15 --prepare "cargo clean && sleep 5" 'RUSTC_WRAPPER="" cargo build --release --example breakout' 'RUSTC_WRAPPER="" cargo build --release --example breakout --features debug'` ``` breakout' 'RUSTC_WRAPPER="" cargo build --release --example breakout --features debug' Benchmark 1: RUSTC_WRAPPER="" cargo build --release --example breakout Time (mean ± σ): 84.856 s ± 3.565 s [User: 1093.817 s, System: 32.547 s] Range (min … max): 78.038 s … 89.214 s 15 runs Benchmark 2: RUSTC_WRAPPER="" cargo build --release --example breakout --features debug Time (mean ± σ): 92.303 s ± 2.466 s [User: 1193.443 s, System: 33.803 s] Range (min … max): 90.619 s … 99.684 s 15 runs Summary RUSTC_WRAPPER="" cargo build --release --example breakout ran 1.09 ± 0.05 times faster than RUSTC_WRAPPER="" cargo build --release --example breakout --features debug ```
This commit is contained in:
parent
2119838e27
commit
4e694aea53
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -95,7 +95,7 @@ jobs:
|
||||
- name: CI job
|
||||
# To run the tests one item at a time for troubleshooting, use
|
||||
# cargo --quiet test --lib -- --list | sed 's/: test$//' | MIRIFLAGS="-Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation" xargs -n1 cargo miri test -p bevy_ecs --lib -- --exact
|
||||
run: cargo miri test -p bevy_ecs
|
||||
run: cargo miri test -p bevy_ecs --features bevy_utils/debug
|
||||
env:
|
||||
# -Zrandomize-layout makes sure we dont rely on the layout of anything that might change
|
||||
RUSTFLAGS: -Zrandomize-layout
|
||||
|
10
Cargo.toml
10
Cargo.toml
@ -165,6 +165,7 @@ default = [
|
||||
"vorbis",
|
||||
"webgl2",
|
||||
"x11",
|
||||
"debug",
|
||||
]
|
||||
|
||||
# Recommended defaults for no_std applications
|
||||
@ -507,7 +508,10 @@ file_watcher = ["bevy_internal/file_watcher"]
|
||||
embedded_watcher = ["bevy_internal/embedded_watcher"]
|
||||
|
||||
# Enable stepping-based debugging of Bevy systems
|
||||
bevy_debug_stepping = ["bevy_internal/bevy_debug_stepping"]
|
||||
bevy_debug_stepping = [
|
||||
"bevy_internal/bevy_debug_stepping",
|
||||
"bevy_internal/debug",
|
||||
]
|
||||
|
||||
# Enables the meshlet renderer for dense high-poly scenes (experimental)
|
||||
meshlet = ["bevy_internal/meshlet"]
|
||||
@ -551,6 +555,9 @@ web = ["bevy_internal/web"]
|
||||
# Enable hotpatching of Bevy systems
|
||||
hotpatching = ["bevy_internal/hotpatching"]
|
||||
|
||||
# Enable collecting debug information about systems and components to help with diagnostics
|
||||
debug = ["bevy_internal/debug"]
|
||||
|
||||
[dependencies]
|
||||
bevy_internal = { path = "crates/bevy_internal", version = "0.16.0-dev", default-features = false }
|
||||
tracing = { version = "0.1", default-features = false, optional = true }
|
||||
@ -2098,6 +2105,7 @@ wasm = false
|
||||
name = "dynamic"
|
||||
path = "examples/ecs/dynamic.rs"
|
||||
doc-scrape-examples = true
|
||||
required-features = ["debug"]
|
||||
|
||||
[package.metadata.example.dynamic]
|
||||
name = "Dynamic ECS"
|
||||
|
@ -35,7 +35,7 @@ backtrace = ["std"]
|
||||
|
||||
## Enables `tracing` integration, allowing spans and other metrics to be reported
|
||||
## through that framework.
|
||||
trace = ["std", "dep:tracing"]
|
||||
trace = ["std", "dep:tracing", "bevy_utils/debug"]
|
||||
|
||||
## Enables a more detailed set of traces which may be noisy if left on by default.
|
||||
detailed_trace = ["trace"]
|
||||
@ -63,9 +63,9 @@ std = [
|
||||
"bevy_reflect?/std",
|
||||
"bevy_tasks/std",
|
||||
"bevy_utils/parallel",
|
||||
"bevy_utils/std",
|
||||
"bitflags/std",
|
||||
"concurrent-queue/std",
|
||||
"disqualified/alloc",
|
||||
"fixedbitset/std",
|
||||
"indexmap/std",
|
||||
"serde?/std",
|
||||
@ -98,7 +98,6 @@ bevy_platform = { path = "../bevy_platform", version = "0.16.0-dev", default-fea
|
||||
] }
|
||||
|
||||
bitflags = { version = "2.3", default-features = false }
|
||||
disqualified = { version = "1.0", default-features = false }
|
||||
fixedbitset = { version = "0.5", default-features = false }
|
||||
serde = { version = "1", default-features = false, features = [
|
||||
"alloc",
|
||||
|
@ -550,10 +550,9 @@ impl BundleInfo {
|
||||
// SAFETY: the caller ensures component_id is valid.
|
||||
unsafe { components.get_info_unchecked(id).name() }
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
panic!("Bundle {bundle_type_name} has duplicate components: {names}");
|
||||
panic!("Bundle {bundle_type_name} has duplicate components: {names:?}");
|
||||
}
|
||||
|
||||
// handle explicit components
|
||||
|
@ -24,7 +24,7 @@ use bevy_platform::{
|
||||
use bevy_ptr::{OwningPtr, UnsafeCellDeref};
|
||||
#[cfg(feature = "bevy_reflect")]
|
||||
use bevy_reflect::Reflect;
|
||||
use bevy_utils::TypeIdMap;
|
||||
use bevy_utils::{prelude::DebugName, TypeIdMap};
|
||||
use core::{
|
||||
alloc::Layout,
|
||||
any::{Any, TypeId},
|
||||
@ -34,7 +34,6 @@ use core::{
|
||||
mem::needs_drop,
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
use disqualified::ShortName;
|
||||
use smallvec::SmallVec;
|
||||
use thiserror::Error;
|
||||
|
||||
@ -678,8 +677,8 @@ impl ComponentInfo {
|
||||
|
||||
/// Returns the name of the current component.
|
||||
#[inline]
|
||||
pub fn name(&self) -> &str {
|
||||
&self.descriptor.name
|
||||
pub fn name(&self) -> DebugName {
|
||||
self.descriptor.name.clone()
|
||||
}
|
||||
|
||||
/// Returns `true` if the current component is mutable.
|
||||
@ -836,7 +835,7 @@ impl SparseSetIndex for ComponentId {
|
||||
/// A value describing a component or resource, which may or may not correspond to a Rust type.
|
||||
#[derive(Clone)]
|
||||
pub struct ComponentDescriptor {
|
||||
name: Cow<'static, str>,
|
||||
name: DebugName,
|
||||
// SAFETY: This must remain private. It must match the statically known StorageType of the
|
||||
// associated rust component type if one exists.
|
||||
storage_type: StorageType,
|
||||
@ -882,7 +881,7 @@ impl ComponentDescriptor {
|
||||
/// Create a new `ComponentDescriptor` for the type `T`.
|
||||
pub fn new<T: Component>() -> Self {
|
||||
Self {
|
||||
name: Cow::Borrowed(core::any::type_name::<T>()),
|
||||
name: DebugName::type_name::<T>(),
|
||||
storage_type: T::STORAGE_TYPE,
|
||||
is_send_and_sync: true,
|
||||
type_id: Some(TypeId::of::<T>()),
|
||||
@ -907,7 +906,7 @@ impl ComponentDescriptor {
|
||||
clone_behavior: ComponentCloneBehavior,
|
||||
) -> Self {
|
||||
Self {
|
||||
name: name.into(),
|
||||
name: name.into().into(),
|
||||
storage_type,
|
||||
is_send_and_sync: true,
|
||||
type_id: None,
|
||||
@ -923,7 +922,7 @@ impl ComponentDescriptor {
|
||||
/// The [`StorageType`] for resources is always [`StorageType::Table`].
|
||||
pub fn new_resource<T: Resource>() -> Self {
|
||||
Self {
|
||||
name: Cow::Borrowed(core::any::type_name::<T>()),
|
||||
name: DebugName::type_name::<T>(),
|
||||
// PERF: `SparseStorage` may actually be a more
|
||||
// reasonable choice as `storage_type` for resources.
|
||||
storage_type: StorageType::Table,
|
||||
@ -938,7 +937,7 @@ impl ComponentDescriptor {
|
||||
|
||||
fn new_non_send<T: Any>(storage_type: StorageType) -> Self {
|
||||
Self {
|
||||
name: Cow::Borrowed(core::any::type_name::<T>()),
|
||||
name: DebugName::type_name::<T>(),
|
||||
storage_type,
|
||||
is_send_and_sync: false,
|
||||
type_id: Some(TypeId::of::<T>()),
|
||||
@ -964,8 +963,8 @@ impl ComponentDescriptor {
|
||||
|
||||
/// Returns the name of the current component.
|
||||
#[inline]
|
||||
pub fn name(&self) -> &str {
|
||||
self.name.as_ref()
|
||||
pub fn name(&self) -> DebugName {
|
||||
self.name.clone()
|
||||
}
|
||||
|
||||
/// Returns whether this component is mutable.
|
||||
@ -1854,13 +1853,10 @@ impl Components {
|
||||
///
|
||||
/// This will return an incorrect result if `id` did not come from the same world as `self`. It may return `None` or a garbage value.
|
||||
#[inline]
|
||||
pub fn get_name<'a>(&'a self, id: ComponentId) -> Option<Cow<'a, str>> {
|
||||
pub fn get_name<'a>(&'a self, id: ComponentId) -> Option<DebugName> {
|
||||
self.components
|
||||
.get(id.0)
|
||||
.and_then(|info| {
|
||||
info.as_ref()
|
||||
.map(|info| Cow::Borrowed(info.descriptor.name()))
|
||||
})
|
||||
.and_then(|info| info.as_ref().map(|info| info.descriptor.name()))
|
||||
.or_else(|| {
|
||||
let queued = self.queued.read().unwrap_or_else(PoisonError::into_inner);
|
||||
// first check components, then resources, then dynamic
|
||||
@ -2813,13 +2809,13 @@ pub fn enforce_no_required_components_recursion(
|
||||
"Recursive required components detected: {}\nhelp: {}",
|
||||
recursion_check_stack
|
||||
.iter()
|
||||
.map(|id| format!("{}", ShortName(&components.get_name(*id).unwrap())))
|
||||
.map(|id| format!("{}", components.get_name(*id).unwrap().shortname()))
|
||||
.collect::<Vec<_>>()
|
||||
.join(" → "),
|
||||
if direct_recursion {
|
||||
format!(
|
||||
"Remove require({}).",
|
||||
ShortName(&components.get_name(requiree).unwrap())
|
||||
components.get_name(requiree).unwrap().shortname()
|
||||
)
|
||||
} else {
|
||||
"If this is intentional, consider merging the components.".into()
|
||||
|
@ -1,6 +1,7 @@
|
||||
use alloc::{borrow::ToOwned, boxed::Box, collections::VecDeque, vec::Vec};
|
||||
use bevy_platform::collections::{HashMap, HashSet};
|
||||
use bevy_ptr::{Ptr, PtrMut};
|
||||
use bevy_utils::prelude::DebugName;
|
||||
use bumpalo::Bump;
|
||||
use core::any::TypeId;
|
||||
|
||||
@ -171,7 +172,8 @@ impl<'a, 'b> ComponentCloneCtx<'a, 'b> {
|
||||
/// - `ComponentId` of component being written does not match expected `ComponentId`.
|
||||
pub fn write_target_component<C: Component>(&mut self, mut component: C) {
|
||||
C::map_entities(&mut component, &mut self.mapper);
|
||||
let short_name = disqualified::ShortName::of::<C>();
|
||||
let debug_name = DebugName::type_name::<C>();
|
||||
let short_name = debug_name.shortname();
|
||||
if self.target_component_written {
|
||||
panic!("Trying to write component '{short_name}' multiple times")
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
use core::{any::type_name, fmt};
|
||||
use core::fmt;
|
||||
|
||||
use bevy_utils::prelude::DebugName;
|
||||
|
||||
use crate::{
|
||||
entity::Entity,
|
||||
@ -31,7 +33,7 @@ where
|
||||
Err(err) => (error_handler)(
|
||||
err.into(),
|
||||
ErrorContext::Command {
|
||||
name: type_name::<C>().into(),
|
||||
name: DebugName::type_name::<C>(),
|
||||
},
|
||||
),
|
||||
}
|
||||
@ -43,7 +45,7 @@ where
|
||||
Err(err) => world.default_error_handler()(
|
||||
err.into(),
|
||||
ErrorContext::Command {
|
||||
name: type_name::<C>().into(),
|
||||
name: DebugName::type_name::<C>(),
|
||||
},
|
||||
),
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use core::fmt::Display;
|
||||
|
||||
use crate::{component::Tick, error::BevyError, prelude::Resource};
|
||||
use alloc::borrow::Cow;
|
||||
use bevy_utils::prelude::DebugName;
|
||||
use derive_more::derive::{Deref, DerefMut};
|
||||
|
||||
/// Context for a [`BevyError`] to aid in debugging.
|
||||
@ -10,26 +10,26 @@ pub enum ErrorContext {
|
||||
/// The error occurred in a system.
|
||||
System {
|
||||
/// The name of the system that failed.
|
||||
name: Cow<'static, str>,
|
||||
name: DebugName,
|
||||
/// The last tick that the system was run.
|
||||
last_run: Tick,
|
||||
},
|
||||
/// The error occurred in a run condition.
|
||||
RunCondition {
|
||||
/// The name of the run condition that failed.
|
||||
name: Cow<'static, str>,
|
||||
name: DebugName,
|
||||
/// The last tick that the run condition was evaluated.
|
||||
last_run: Tick,
|
||||
},
|
||||
/// The error occurred in a command.
|
||||
Command {
|
||||
/// The name of the command that failed.
|
||||
name: Cow<'static, str>,
|
||||
name: DebugName,
|
||||
},
|
||||
/// The error occurred in an observer.
|
||||
Observer {
|
||||
/// The name of the observer that failed.
|
||||
name: Cow<'static, str>,
|
||||
name: DebugName,
|
||||
/// The last tick that the observer was run.
|
||||
last_run: Tick,
|
||||
},
|
||||
@ -54,12 +54,12 @@ impl Display for ErrorContext {
|
||||
|
||||
impl ErrorContext {
|
||||
/// The name of the ECS construct that failed.
|
||||
pub fn name(&self) -> &str {
|
||||
pub fn name(&self) -> DebugName {
|
||||
match self {
|
||||
Self::System { name, .. }
|
||||
| Self::Command { name, .. }
|
||||
| Self::Observer { name, .. }
|
||||
| Self::RunCondition { name, .. } => name,
|
||||
| Self::RunCondition { name, .. } => name.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,9 +22,9 @@ use alloc::{format, string::String, vec::Vec};
|
||||
use bevy_reflect::std_traits::ReflectDefault;
|
||||
#[cfg(all(feature = "serialize", feature = "bevy_reflect"))]
|
||||
use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
|
||||
use bevy_utils::prelude::DebugName;
|
||||
use core::ops::Deref;
|
||||
use core::slice;
|
||||
use disqualified::ShortName;
|
||||
use log::warn;
|
||||
|
||||
/// Stores the parent entity of this child entity with this component.
|
||||
@ -461,11 +461,12 @@ pub fn validate_parent_has_component<C: Component>(
|
||||
{
|
||||
// TODO: print name here once Name lives in bevy_ecs
|
||||
let name: Option<String> = None;
|
||||
let debug_name = DebugName::type_name::<C>();
|
||||
warn!(
|
||||
"warning[B0004]: {}{name} with the {ty_name} component has a parent without {ty_name}.\n\
|
||||
This will cause inconsistent behaviors! See: https://bevy.org/learn/errors/b0004",
|
||||
caller.map(|c| format!("{c}: ")).unwrap_or_default(),
|
||||
ty_name = ShortName::of::<C>(),
|
||||
ty_name = debug_name.shortname(),
|
||||
name = name.map_or_else(
|
||||
|| format!("Entity {entity}"),
|
||||
|s| format!("The {s} entity")
|
||||
|
@ -1,4 +1,5 @@
|
||||
use alloc::{borrow::Cow, boxed::Box, vec};
|
||||
use alloc::{boxed::Box, vec};
|
||||
use bevy_utils::prelude::DebugName;
|
||||
use core::any::Any;
|
||||
|
||||
use crate::{
|
||||
@ -301,7 +302,7 @@ impl Observer {
|
||||
}
|
||||
|
||||
/// Returns the name of the [`Observer`]'s system .
|
||||
pub fn system_name(&self) -> Cow<'static, str> {
|
||||
pub fn system_name(&self) -> DebugName {
|
||||
self.system.system_name()
|
||||
}
|
||||
}
|
||||
@ -420,11 +421,11 @@ fn observer_system_runner<E: Event, B: Bundle, S: ObserverSystem<E, B>>(
|
||||
}
|
||||
|
||||
trait AnyNamedSystem: Any + Send + Sync + 'static {
|
||||
fn system_name(&self) -> Cow<'static, str>;
|
||||
fn system_name(&self) -> DebugName;
|
||||
}
|
||||
|
||||
impl<T: Any + System> AnyNamedSystem for T {
|
||||
fn system_name(&self) -> Cow<'static, str> {
|
||||
fn system_name(&self) -> DebugName {
|
||||
self.name()
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ use crate::world::World;
|
||||
use alloc::{format, string::String, vec, vec::Vec};
|
||||
use core::{fmt, fmt::Debug, marker::PhantomData};
|
||||
use derive_more::From;
|
||||
use disqualified::ShortName;
|
||||
use fixedbitset::FixedBitSet;
|
||||
use thiserror::Error;
|
||||
|
||||
@ -999,12 +998,11 @@ impl AccessConflicts {
|
||||
.map(|index| {
|
||||
format!(
|
||||
"{}",
|
||||
ShortName(
|
||||
&world
|
||||
.components
|
||||
.get_name(ComponentId::get_sparse_set_index(index))
|
||||
.unwrap()
|
||||
)
|
||||
world
|
||||
.components
|
||||
.get_name(ComponentId::get_sparse_set_index(index))
|
||||
.unwrap()
|
||||
.shortname()
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
|
@ -1,3 +1,4 @@
|
||||
use bevy_utils::prelude::DebugName;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::{
|
||||
@ -54,10 +55,10 @@ impl core::fmt::Display for QueryEntityError {
|
||||
pub enum QuerySingleError {
|
||||
/// No entity fits the query.
|
||||
#[error("No entities fit the query {0}")]
|
||||
NoEntities(&'static str),
|
||||
NoEntities(DebugName),
|
||||
/// Multiple entities fit the query.
|
||||
#[error("Multiple entities fit the query {0}")]
|
||||
MultipleEntities(&'static str),
|
||||
MultipleEntities(DebugName),
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -12,6 +12,7 @@ use crate::{
|
||||
},
|
||||
};
|
||||
use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref};
|
||||
use bevy_utils::prelude::DebugName;
|
||||
use core::{cell::UnsafeCell, marker::PhantomData, panic::Location};
|
||||
use smallvec::SmallVec;
|
||||
use variadics_please::all_tuples;
|
||||
@ -1232,7 +1233,7 @@ where
|
||||
assert!(
|
||||
access.is_compatible(&my_access),
|
||||
"`EntityRefExcept<{}>` conflicts with a previous access in this query.",
|
||||
core::any::type_name::<B>(),
|
||||
DebugName::type_name::<B>(),
|
||||
);
|
||||
access.extend(&my_access);
|
||||
}
|
||||
@ -1343,7 +1344,7 @@ where
|
||||
assert!(
|
||||
access.is_compatible(&my_access),
|
||||
"`EntityMutExcept<{}>` conflicts with a previous access in this query.",
|
||||
core::any::type_name::<B>()
|
||||
DebugName::type_name::<B>()
|
||||
);
|
||||
access.extend(&my_access);
|
||||
}
|
||||
@ -1589,7 +1590,7 @@ unsafe impl<T: Component> WorldQuery for &T {
|
||||
assert!(
|
||||
!access.access().has_component_write(component_id),
|
||||
"&{} conflicts with a previous access in this query. Shared access cannot coincide with exclusive access.",
|
||||
core::any::type_name::<T>(),
|
||||
DebugName::type_name::<T>(),
|
||||
);
|
||||
access.add_component_read(component_id);
|
||||
}
|
||||
@ -1775,7 +1776,7 @@ unsafe impl<'__w, T: Component> WorldQuery for Ref<'__w, T> {
|
||||
assert!(
|
||||
!access.access().has_component_write(component_id),
|
||||
"&{} conflicts with a previous access in this query. Shared access cannot coincide with exclusive access.",
|
||||
core::any::type_name::<T>(),
|
||||
DebugName::type_name::<T>(),
|
||||
);
|
||||
access.add_component_read(component_id);
|
||||
}
|
||||
@ -1984,7 +1985,7 @@ unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T {
|
||||
assert!(
|
||||
!access.access().has_component_read(component_id),
|
||||
"&mut {} conflicts with a previous access in this query. Mutable component access must be unique.",
|
||||
core::any::type_name::<T>(),
|
||||
DebugName::type_name::<T>(),
|
||||
);
|
||||
access.add_component_write(component_id);
|
||||
}
|
||||
@ -2134,7 +2135,7 @@ unsafe impl<'__w, T: Component> WorldQuery for Mut<'__w, T> {
|
||||
assert!(
|
||||
!access.access().has_component_read(component_id),
|
||||
"Mut<{}> conflicts with a previous access in this query. Mutable component access mut be unique.",
|
||||
core::any::type_name::<T>(),
|
||||
DebugName::type_name::<T>(),
|
||||
);
|
||||
access.add_component_write(component_id);
|
||||
}
|
||||
@ -2401,7 +2402,7 @@ pub struct Has<T>(PhantomData<T>);
|
||||
|
||||
impl<T> core::fmt::Debug for Has<T> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
|
||||
write!(f, "Has<{}>", core::any::type_name::<T>())
|
||||
write!(f, "Has<{}>", DebugName::type_name::<T>())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ use crate::{
|
||||
world::{unsafe_world_cell::UnsafeWorldCell, World},
|
||||
};
|
||||
use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref};
|
||||
use bevy_utils::prelude::DebugName;
|
||||
use core::{cell::UnsafeCell, marker::PhantomData};
|
||||
use variadics_please::all_tuples;
|
||||
|
||||
@ -792,7 +793,7 @@ unsafe impl<T: Component> WorldQuery for Added<T> {
|
||||
#[inline]
|
||||
fn update_component_access(&id: &ComponentId, access: &mut FilteredAccess<ComponentId>) {
|
||||
if access.access().has_component_write(id) {
|
||||
panic!("$state_name<{}> conflicts with a previous access in this query. Shared access cannot coincide with exclusive access.",core::any::type_name::<T>());
|
||||
panic!("$state_name<{}> conflicts with a previous access in this query. Shared access cannot coincide with exclusive access.", DebugName::type_name::<T>());
|
||||
}
|
||||
access.add_component_read(id);
|
||||
}
|
||||
@ -1020,7 +1021,7 @@ unsafe impl<T: Component> WorldQuery for Changed<T> {
|
||||
#[inline]
|
||||
fn update_component_access(&id: &ComponentId, access: &mut FilteredAccess<ComponentId>) {
|
||||
if access.access().has_component_write(id) {
|
||||
panic!("$state_name<{}> conflicts with a previous access in this query. Shared access cannot coincide with exclusive access.",core::any::type_name::<T>());
|
||||
panic!("$state_name<{}> conflicts with a previous access in this query. Shared access cannot coincide with exclusive access.", DebugName::type_name::<T>());
|
||||
}
|
||||
access.add_component_read(id);
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ use crate::{
|
||||
use crate::entity::UniqueEntityEquivalentSlice;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use bevy_utils::prelude::DebugName;
|
||||
use core::{fmt, ptr};
|
||||
use fixedbitset::FixedBitSet;
|
||||
use log::warn;
|
||||
@ -672,7 +673,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
assert!(
|
||||
component_access.is_subset(&self_access),
|
||||
"Transmuted state for {} attempts to access terms that are not allowed by original state {}.",
|
||||
core::any::type_name::<(NewD, NewF)>(), core::any::type_name::<(D, F)>()
|
||||
DebugName::type_name::<(NewD, NewF)>(), DebugName::type_name::<(D, F)>()
|
||||
);
|
||||
|
||||
QueryState {
|
||||
@ -791,7 +792,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
assert!(
|
||||
component_access.is_subset(&joined_component_access),
|
||||
"Joined state for {} attempts to access terms that are not allowed by state {} joined with {}.",
|
||||
core::any::type_name::<(NewD, NewF)>(), core::any::type_name::<(D, F)>(), core::any::type_name::<(OtherD, OtherF)>()
|
||||
DebugName::type_name::<(NewD, NewF)>(), DebugName::type_name::<(D, F)>(), DebugName::type_name::<(OtherD, OtherF)>()
|
||||
);
|
||||
|
||||
if self.archetype_generation != other.archetype_generation {
|
||||
|
@ -5,6 +5,7 @@
|
||||
//!
|
||||
//! Same as [`super::component`], but for bundles.
|
||||
use alloc::boxed::Box;
|
||||
use bevy_utils::prelude::DebugName;
|
||||
use core::any::{Any, TypeId};
|
||||
|
||||
use crate::{
|
||||
@ -172,7 +173,7 @@ impl<B: Bundle + Reflect + TypePath + BundleFromComponents> FromType<B> for Refl
|
||||
_ => panic!(
|
||||
"expected bundle `{}` to be named struct or tuple",
|
||||
// FIXME: once we have unique reflect, use `TypePath`.
|
||||
core::any::type_name::<B>(),
|
||||
DebugName::type_name::<B>(),
|
||||
),
|
||||
}
|
||||
}
|
||||
@ -215,7 +216,7 @@ impl<B: Bundle + Reflect + TypePath + BundleFromComponents> FromType<B> for Refl
|
||||
_ => panic!(
|
||||
"expected bundle `{}` to be a named struct or tuple",
|
||||
// FIXME: once we have unique reflect, use `TypePath`.
|
||||
core::any::type_name::<B>(),
|
||||
DebugName::type_name::<B>(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ use crate::{
|
||||
},
|
||||
};
|
||||
use bevy_reflect::{FromReflect, FromType, PartialReflect, Reflect, TypePath, TypeRegistry};
|
||||
use disqualified::ShortName;
|
||||
use bevy_utils::prelude::DebugName;
|
||||
|
||||
/// A struct used to operate on reflected [`Component`] trait of a type.
|
||||
///
|
||||
@ -308,7 +308,8 @@ impl<C: Component + Reflect + TypePath> FromType<C> for ReflectComponent {
|
||||
},
|
||||
apply: |mut entity, reflected_component| {
|
||||
if !C::Mutability::MUTABLE {
|
||||
let name = ShortName::of::<C>();
|
||||
let name = DebugName::type_name::<C>();
|
||||
let name = name.shortname();
|
||||
panic!("Cannot call `ReflectComponent::apply` on component {name}. It is immutable, and cannot modified through reflection");
|
||||
}
|
||||
|
||||
@ -357,7 +358,8 @@ impl<C: Component + Reflect + TypePath> FromType<C> for ReflectComponent {
|
||||
reflect: |entity| entity.get::<C>().map(|c| c as &dyn Reflect),
|
||||
reflect_mut: |entity| {
|
||||
if !C::Mutability::MUTABLE {
|
||||
let name = ShortName::of::<C>();
|
||||
let name = DebugName::type_name::<C>();
|
||||
let name = name.shortname();
|
||||
panic!("Cannot call `ReflectComponent::reflect_mut` on component {name}. It is immutable, and cannot modified through reflection");
|
||||
}
|
||||
|
||||
@ -370,7 +372,8 @@ impl<C: Component + Reflect + TypePath> FromType<C> for ReflectComponent {
|
||||
},
|
||||
reflect_unchecked_mut: |entity| {
|
||||
if !C::Mutability::MUTABLE {
|
||||
let name = ShortName::of::<C>();
|
||||
let name = DebugName::type_name::<C>();
|
||||
let name = name.shortname();
|
||||
panic!("Cannot call `ReflectComponent::reflect_unchecked_mut` on component {name}. It is immutable, and cannot modified through reflection");
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@ mod from_world;
|
||||
mod map_entities;
|
||||
mod resource;
|
||||
|
||||
use bevy_utils::prelude::DebugName;
|
||||
pub use bundle::{ReflectBundle, ReflectBundleFns};
|
||||
pub use component::{ReflectComponent, ReflectComponentFns};
|
||||
pub use entity_commands::ReflectCommandExt;
|
||||
@ -136,7 +137,7 @@ pub fn from_reflect_with_fallback<T: Reflect + TypePath>(
|
||||
`Default` or `FromWorld` traits. Are you perhaps missing a `#[reflect(Default)]` \
|
||||
or `#[reflect(FromWorld)]`?",
|
||||
// FIXME: once we have unique reflect, use `TypePath`.
|
||||
core::any::type_name::<T>(),
|
||||
DebugName::type_name::<T>(),
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -6,6 +6,7 @@ mod relationship_source_collection;
|
||||
|
||||
use alloc::format;
|
||||
|
||||
use bevy_utils::prelude::DebugName;
|
||||
pub use related_methods::*;
|
||||
pub use relationship_query::*;
|
||||
pub use relationship_source_collection::*;
|
||||
@ -105,8 +106,8 @@ pub trait Relationship: Component + Sized {
|
||||
warn!(
|
||||
"{}The {}({target_entity:?}) relationship on entity {entity:?} points to itself. The invalid {} relationship has been removed.",
|
||||
caller.map(|location|format!("{location}: ")).unwrap_or_default(),
|
||||
core::any::type_name::<Self>(),
|
||||
core::any::type_name::<Self>()
|
||||
DebugName::type_name::<Self>(),
|
||||
DebugName::type_name::<Self>()
|
||||
);
|
||||
world.commands().entity(entity).remove::<Self>();
|
||||
return;
|
||||
@ -125,8 +126,8 @@ pub trait Relationship: Component + Sized {
|
||||
warn!(
|
||||
"{}The {}({target_entity:?}) relationship on entity {entity:?} relates to an entity that does not exist. The invalid {} relationship has been removed.",
|
||||
caller.map(|location|format!("{location}: ")).unwrap_or_default(),
|
||||
core::any::type_name::<Self>(),
|
||||
core::any::type_name::<Self>()
|
||||
DebugName::type_name::<Self>(),
|
||||
DebugName::type_name::<Self>()
|
||||
);
|
||||
world.commands().entity(entity).remove::<Self>();
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
use alloc::{borrow::Cow, boxed::Box, format};
|
||||
use alloc::{boxed::Box, format};
|
||||
use bevy_utils::prelude::DebugName;
|
||||
use core::ops::Not;
|
||||
|
||||
use crate::system::{
|
||||
@ -154,7 +155,7 @@ pub trait SystemCondition<Marker, In: SystemInput = (), Out = bool>:
|
||||
let a = IntoSystem::into_system(self);
|
||||
let b = IntoSystem::into_system(and);
|
||||
let name = format!("{} && {}", a.name(), b.name());
|
||||
CombinatorSystem::new(a, b, Cow::Owned(name))
|
||||
CombinatorSystem::new(a, b, DebugName::owned(name))
|
||||
}
|
||||
|
||||
/// Returns a new run condition that only returns `false`
|
||||
@ -206,7 +207,7 @@ pub trait SystemCondition<Marker, In: SystemInput = (), Out = bool>:
|
||||
let a = IntoSystem::into_system(self);
|
||||
let b = IntoSystem::into_system(nand);
|
||||
let name = format!("!({} && {})", a.name(), b.name());
|
||||
CombinatorSystem::new(a, b, Cow::Owned(name))
|
||||
CombinatorSystem::new(a, b, DebugName::owned(name))
|
||||
}
|
||||
|
||||
/// Returns a new run condition that only returns `true`
|
||||
@ -258,7 +259,7 @@ pub trait SystemCondition<Marker, In: SystemInput = (), Out = bool>:
|
||||
let a = IntoSystem::into_system(self);
|
||||
let b = IntoSystem::into_system(nor);
|
||||
let name = format!("!({} || {})", a.name(), b.name());
|
||||
CombinatorSystem::new(a, b, Cow::Owned(name))
|
||||
CombinatorSystem::new(a, b, DebugName::owned(name))
|
||||
}
|
||||
|
||||
/// Returns a new run condition that returns `true`
|
||||
@ -305,7 +306,7 @@ pub trait SystemCondition<Marker, In: SystemInput = (), Out = bool>:
|
||||
let a = IntoSystem::into_system(self);
|
||||
let b = IntoSystem::into_system(or);
|
||||
let name = format!("{} || {}", a.name(), b.name());
|
||||
CombinatorSystem::new(a, b, Cow::Owned(name))
|
||||
CombinatorSystem::new(a, b, DebugName::owned(name))
|
||||
}
|
||||
|
||||
/// Returns a new run condition that only returns `true`
|
||||
@ -357,7 +358,7 @@ pub trait SystemCondition<Marker, In: SystemInput = (), Out = bool>:
|
||||
let a = IntoSystem::into_system(self);
|
||||
let b = IntoSystem::into_system(xnor);
|
||||
let name = format!("!({} ^ {})", a.name(), b.name());
|
||||
CombinatorSystem::new(a, b, Cow::Owned(name))
|
||||
CombinatorSystem::new(a, b, DebugName::owned(name))
|
||||
}
|
||||
|
||||
/// Returns a new run condition that only returns `true`
|
||||
@ -399,7 +400,7 @@ pub trait SystemCondition<Marker, In: SystemInput = (), Out = bool>:
|
||||
let a = IntoSystem::into_system(self);
|
||||
let b = IntoSystem::into_system(xor);
|
||||
let name = format!("({} ^ {})", a.name(), b.name());
|
||||
CombinatorSystem::new(a, b, Cow::Owned(name))
|
||||
CombinatorSystem::new(a, b, DebugName::owned(name))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,8 @@ mod multi_threaded;
|
||||
mod simple;
|
||||
mod single_threaded;
|
||||
|
||||
use alloc::{borrow::Cow, vec, vec::Vec};
|
||||
use alloc::{vec, vec::Vec};
|
||||
use bevy_utils::prelude::DebugName;
|
||||
use core::any::TypeId;
|
||||
|
||||
#[expect(deprecated, reason = "We still need to support this.")]
|
||||
@ -158,8 +159,8 @@ impl System for ApplyDeferred {
|
||||
type In = ();
|
||||
type Out = Result<()>;
|
||||
|
||||
fn name(&self) -> Cow<'static, str> {
|
||||
Cow::Borrowed("bevy_ecs::apply_deferred")
|
||||
fn name(&self) -> DebugName {
|
||||
DebugName::borrowed("bevy_ecs::apply_deferred")
|
||||
}
|
||||
|
||||
fn flags(&self) -> SystemStateFlags {
|
||||
|
@ -342,7 +342,7 @@ impl<'scope, 'env: 'scope, 'sys> Context<'scope, 'env, 'sys> {
|
||||
#[cfg(feature = "std")]
|
||||
#[expect(clippy::print_stderr, reason = "Allowed behind `std` feature gate.")]
|
||||
{
|
||||
eprintln!("Encountered a panic in system `{}`!", &*system.name());
|
||||
eprintln!("Encountered a panic in system `{}`!", system.name());
|
||||
}
|
||||
// set the payload to propagate the error
|
||||
{
|
||||
@ -799,7 +799,7 @@ fn apply_deferred(
|
||||
{
|
||||
eprintln!(
|
||||
"Encountered a panic when applying buffers for system `{}`!",
|
||||
&*system.name()
|
||||
system.name()
|
||||
);
|
||||
}
|
||||
return Err(payload);
|
||||
|
@ -73,7 +73,7 @@ impl SystemExecutor for SimpleExecutor {
|
||||
#[cfg(feature = "trace")]
|
||||
let name = schedule.systems[system_index].system.name();
|
||||
#[cfg(feature = "trace")]
|
||||
let should_run_span = info_span!("check_conditions", name = &*name).entered();
|
||||
let should_run_span = info_span!("check_conditions", name = name.as_string()).entered();
|
||||
|
||||
let mut should_run = !self.completed_systems.contains(system_index);
|
||||
for set_idx in schedule.sets_with_conditions_of_systems[system_index].ones() {
|
||||
@ -161,7 +161,7 @@ impl SystemExecutor for SimpleExecutor {
|
||||
#[expect(clippy::print_stderr, reason = "Allowed behind `std` feature gate.")]
|
||||
{
|
||||
if let Err(payload) = std::panic::catch_unwind(f) {
|
||||
eprintln!("Encountered a panic in system `{}`!", &*system.name());
|
||||
eprintln!("Encountered a panic in system `{}`!", system.name());
|
||||
std::panic::resume_unwind(payload);
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ impl SystemExecutor for SingleThreadedExecutor {
|
||||
#[cfg(feature = "trace")]
|
||||
let name = schedule.systems[system_index].system.name();
|
||||
#[cfg(feature = "trace")]
|
||||
let should_run_span = info_span!("check_conditions", name = &*name).entered();
|
||||
let should_run_span = info_span!("check_conditions", name = name.as_string()).entered();
|
||||
|
||||
let mut should_run = !self.completed_systems.contains(system_index);
|
||||
for set_idx in schedule.sets_with_conditions_of_systems[system_index].ones() {
|
||||
@ -166,7 +166,7 @@ impl SystemExecutor for SingleThreadedExecutor {
|
||||
#[expect(clippy::print_stderr, reason = "Allowed behind `std` feature gate.")]
|
||||
{
|
||||
if let Err(payload) = std::panic::catch_unwind(f) {
|
||||
eprintln!("Encountered a panic in system `{}`!", &*system.name());
|
||||
eprintln!("Encountered a panic in system `{}`!", system.name());
|
||||
std::panic::resume_unwind(payload);
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
clippy::module_inception,
|
||||
reason = "This instance of module inception is being discussed; see #17344."
|
||||
)]
|
||||
use alloc::borrow::Cow;
|
||||
use alloc::{
|
||||
boxed::Box,
|
||||
collections::{BTreeMap, BTreeSet},
|
||||
@ -12,12 +11,11 @@ use alloc::{
|
||||
vec::Vec,
|
||||
};
|
||||
use bevy_platform::collections::{HashMap, HashSet};
|
||||
use bevy_utils::{default, TypeIdMap};
|
||||
use bevy_utils::{default, prelude::DebugName, TypeIdMap};
|
||||
use core::{
|
||||
any::{Any, TypeId},
|
||||
fmt::{Debug, Write},
|
||||
};
|
||||
use disqualified::ShortName;
|
||||
use fixedbitset::FixedBitSet;
|
||||
use log::{error, info, warn};
|
||||
use pass::ScheduleBuildPassObj;
|
||||
@ -1694,14 +1692,14 @@ impl ScheduleGraph {
|
||||
|
||||
#[inline]
|
||||
fn get_node_name_inner(&self, id: &NodeId, report_sets: bool) -> String {
|
||||
let name = match id {
|
||||
match id {
|
||||
NodeId::System(_) => {
|
||||
let name = self.systems[id.index()]
|
||||
.get()
|
||||
.unwrap()
|
||||
.system
|
||||
.name()
|
||||
.to_string();
|
||||
let name = self.systems[id.index()].get().unwrap().system.name();
|
||||
let name = if self.settings.use_shortnames {
|
||||
name.shortname().to_string()
|
||||
} else {
|
||||
name.to_string()
|
||||
};
|
||||
if report_sets {
|
||||
let sets = self.names_of_sets_containing_node(id);
|
||||
if sets.is_empty() {
|
||||
@ -1723,11 +1721,6 @@ impl ScheduleGraph {
|
||||
set.name()
|
||||
}
|
||||
}
|
||||
};
|
||||
if self.settings.use_shortnames {
|
||||
ShortName(&name).to_string()
|
||||
} else {
|
||||
name
|
||||
}
|
||||
}
|
||||
|
||||
@ -2007,7 +2000,7 @@ impl ScheduleGraph {
|
||||
&'a self,
|
||||
ambiguities: &'a [(NodeId, NodeId, Vec<ComponentId>)],
|
||||
components: &'a Components,
|
||||
) -> impl Iterator<Item = (String, String, Vec<Cow<'a, str>>)> + 'a {
|
||||
) -> impl Iterator<Item = (String, String, Vec<DebugName>)> + 'a {
|
||||
ambiguities
|
||||
.iter()
|
||||
.map(move |(system_a, system_b, conflicts)| {
|
||||
|
@ -1,4 +1,5 @@
|
||||
use alloc::boxed::Box;
|
||||
use bevy_utils::prelude::DebugName;
|
||||
use core::{
|
||||
any::TypeId,
|
||||
fmt::Debug,
|
||||
@ -196,7 +197,7 @@ impl<T: 'static> SystemTypeSet<T> {
|
||||
impl<T> Debug for SystemTypeSet<T> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_tuple("SystemTypeSet")
|
||||
.field(&format_args!("fn {}()", &core::any::type_name::<T>()))
|
||||
.field(&format_args!("fn {}()", DebugName::type_name::<T>()))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
@ -895,9 +895,9 @@ mod tests {
|
||||
($schedule:expr, $skipped_systems:expr, $($system:expr),*) => {
|
||||
// pull an ordered list of systems in the schedule, and save the
|
||||
// system TypeId, and name.
|
||||
let systems: Vec<(TypeId, alloc::borrow::Cow<'static, str>)> = $schedule.systems().unwrap()
|
||||
let systems: Vec<(TypeId, alloc::string::String)> = $schedule.systems().unwrap()
|
||||
.map(|(_, system)| {
|
||||
(system.type_id(), system.name())
|
||||
(system.type_id(), system.name().as_string())
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
@ -3,8 +3,8 @@ use crate::{
|
||||
component::{CheckChangeTicks, ComponentId, ComponentTicks, Components, Tick, TickCells},
|
||||
storage::{blob_vec::BlobVec, SparseSet},
|
||||
};
|
||||
use alloc::string::String;
|
||||
use bevy_ptr::{OwningPtr, Ptr, UnsafeCellDeref};
|
||||
use bevy_utils::prelude::DebugName;
|
||||
use core::{cell::UnsafeCell, mem::ManuallyDrop, panic::Location};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
@ -23,7 +23,7 @@ pub struct ResourceData<const SEND: bool> {
|
||||
not(feature = "std"),
|
||||
expect(dead_code, reason = "currently only used with the std feature")
|
||||
)]
|
||||
type_name: String,
|
||||
type_name: DebugName,
|
||||
#[cfg(feature = "std")]
|
||||
origin_thread_id: Option<ThreadId>,
|
||||
changed_by: MaybeLocation<UnsafeCell<&'static Location<'static>>>,
|
||||
@ -385,7 +385,7 @@ impl<const SEND: bool> Resources<SEND> {
|
||||
data: ManuallyDrop::new(data),
|
||||
added_ticks: UnsafeCell::new(Tick::new(0)),
|
||||
changed_ticks: UnsafeCell::new(Tick::new(0)),
|
||||
type_name: String::from(component_info.name()),
|
||||
type_name: component_info.name(),
|
||||
#[cfg(feature = "std")]
|
||||
origin_thread_id: None,
|
||||
changed_by: MaybeLocation::caller().map(UnsafeCell::new),
|
||||
|
@ -1,4 +1,5 @@
|
||||
use alloc::{borrow::Cow, vec::Vec};
|
||||
use alloc::vec::Vec;
|
||||
use bevy_utils::prelude::DebugName;
|
||||
|
||||
use super::{IntoSystem, ReadOnlySystem, System, SystemParamValidationError};
|
||||
use crate::{
|
||||
@ -101,7 +102,7 @@ where
|
||||
pub struct AdapterSystem<Func, S> {
|
||||
func: Func,
|
||||
system: S,
|
||||
name: Cow<'static, str>,
|
||||
name: DebugName,
|
||||
}
|
||||
|
||||
impl<Func, S> AdapterSystem<Func, S>
|
||||
@ -110,7 +111,7 @@ where
|
||||
S: System,
|
||||
{
|
||||
/// Creates a new [`System`] that uses `func` to adapt `system`, via the [`Adapt`] trait.
|
||||
pub const fn new(func: Func, system: S, name: Cow<'static, str>) -> Self {
|
||||
pub const fn new(func: Func, system: S, name: DebugName) -> Self {
|
||||
Self { func, system, name }
|
||||
}
|
||||
}
|
||||
@ -123,7 +124,7 @@ where
|
||||
type In = Func::In;
|
||||
type Out = Func::Out;
|
||||
|
||||
fn name(&self) -> Cow<'static, str> {
|
||||
fn name(&self) -> DebugName {
|
||||
self.name.clone()
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
use alloc::{borrow::Cow, format, vec::Vec};
|
||||
use alloc::{format, vec::Vec};
|
||||
use bevy_utils::prelude::DebugName;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use crate::{
|
||||
@ -55,7 +56,7 @@ use super::{IntoSystem, ReadOnlySystem, System};
|
||||
/// IntoSystem::into_system(resource_equals(A(1))),
|
||||
/// IntoSystem::into_system(resource_equals(B(1))),
|
||||
/// // The name of the combined system.
|
||||
/// std::borrow::Cow::Borrowed("a ^ b"),
|
||||
/// "a ^ b".into(),
|
||||
/// )));
|
||||
/// # fn my_system(mut flag: ResMut<RanFlag>) { flag.0 = true; }
|
||||
/// #
|
||||
@ -112,14 +113,14 @@ pub struct CombinatorSystem<Func, A, B> {
|
||||
_marker: PhantomData<fn() -> Func>,
|
||||
a: A,
|
||||
b: B,
|
||||
name: Cow<'static, str>,
|
||||
name: DebugName,
|
||||
}
|
||||
|
||||
impl<Func, A, B> CombinatorSystem<Func, A, B> {
|
||||
/// Creates a new system that combines two inner systems.
|
||||
///
|
||||
/// The returned system will only be usable if `Func` implements [`Combine<A, B>`].
|
||||
pub fn new(a: A, b: B, name: Cow<'static, str>) -> Self {
|
||||
pub fn new(a: A, b: B, name: DebugName) -> Self {
|
||||
Self {
|
||||
_marker: PhantomData,
|
||||
a,
|
||||
@ -138,7 +139,7 @@ where
|
||||
type In = Func::In;
|
||||
type Out = Func::Out;
|
||||
|
||||
fn name(&self) -> Cow<'static, str> {
|
||||
fn name(&self) -> DebugName {
|
||||
self.name.clone()
|
||||
}
|
||||
|
||||
@ -271,7 +272,7 @@ where
|
||||
let system_a = IntoSystem::into_system(this.a);
|
||||
let system_b = IntoSystem::into_system(this.b);
|
||||
let name = format!("Pipe({}, {})", system_a.name(), system_b.name());
|
||||
PipeSystem::new(system_a, system_b, Cow::Owned(name))
|
||||
PipeSystem::new(system_a, system_b, DebugName::owned(name))
|
||||
}
|
||||
}
|
||||
|
||||
@ -317,7 +318,7 @@ where
|
||||
pub struct PipeSystem<A, B> {
|
||||
a: A,
|
||||
b: B,
|
||||
name: Cow<'static, str>,
|
||||
name: DebugName,
|
||||
}
|
||||
|
||||
impl<A, B> PipeSystem<A, B>
|
||||
@ -327,7 +328,7 @@ where
|
||||
for<'a> B::In: SystemInput<Inner<'a> = A::Out>,
|
||||
{
|
||||
/// Creates a new system that pipes two inner systems.
|
||||
pub fn new(a: A, b: B, name: Cow<'static, str>) -> Self {
|
||||
pub fn new(a: A, b: B, name: DebugName) -> Self {
|
||||
Self { a, b, name }
|
||||
}
|
||||
}
|
||||
@ -341,7 +342,7 @@ where
|
||||
type In = A::In;
|
||||
type Out = B::Out;
|
||||
|
||||
fn name(&self) -> Cow<'static, str> {
|
||||
fn name(&self) -> DebugName {
|
||||
self.name.clone()
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ use crate::{
|
||||
};
|
||||
|
||||
use alloc::{borrow::Cow, vec, vec::Vec};
|
||||
use bevy_utils::prelude::DebugName;
|
||||
use core::marker::PhantomData;
|
||||
use variadics_please::all_tuples;
|
||||
|
||||
@ -42,7 +43,7 @@ where
|
||||
///
|
||||
/// Useful to give closure systems more readable and unique names for debugging and tracing.
|
||||
pub fn with_name(mut self, new_name: impl Into<Cow<'static, str>>) -> Self {
|
||||
self.system_meta.set_name(new_name.into());
|
||||
self.system_meta.set_name(new_name);
|
||||
self
|
||||
}
|
||||
}
|
||||
@ -83,7 +84,7 @@ where
|
||||
type Out = F::Out;
|
||||
|
||||
#[inline]
|
||||
fn name(&self) -> Cow<'static, str> {
|
||||
fn name(&self) -> DebugName {
|
||||
self.system_meta.name.clone()
|
||||
}
|
||||
|
||||
@ -181,7 +182,7 @@ where
|
||||
check_system_change_tick(
|
||||
&mut self.system_meta.last_run,
|
||||
check,
|
||||
self.system_meta.name.as_ref(),
|
||||
self.system_meta.name.clone(),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@ use crate::{
|
||||
};
|
||||
|
||||
use alloc::{borrow::Cow, vec, vec::Vec};
|
||||
use bevy_utils::prelude::DebugName;
|
||||
use core::marker::PhantomData;
|
||||
use variadics_please::all_tuples;
|
||||
|
||||
@ -24,7 +25,7 @@ use super::{
|
||||
/// The metadata of a [`System`].
|
||||
#[derive(Clone)]
|
||||
pub struct SystemMeta {
|
||||
pub(crate) name: Cow<'static, str>,
|
||||
pub(crate) name: DebugName,
|
||||
// NOTE: this must be kept private. making a SystemMeta non-send is irreversible to prevent
|
||||
// SystemParams from overriding each other
|
||||
flags: SystemStateFlags,
|
||||
@ -37,21 +38,21 @@ pub struct SystemMeta {
|
||||
|
||||
impl SystemMeta {
|
||||
pub(crate) fn new<T>() -> Self {
|
||||
let name = core::any::type_name::<T>();
|
||||
let name = DebugName::type_name::<T>();
|
||||
Self {
|
||||
name: name.into(),
|
||||
#[cfg(feature = "trace")]
|
||||
system_span: info_span!("system", name = name.clone().as_string()),
|
||||
#[cfg(feature = "trace")]
|
||||
commands_span: info_span!("system_commands", name = name.clone().as_string()),
|
||||
name,
|
||||
flags: SystemStateFlags::empty(),
|
||||
last_run: Tick::new(0),
|
||||
#[cfg(feature = "trace")]
|
||||
system_span: info_span!("system", name = name),
|
||||
#[cfg(feature = "trace")]
|
||||
commands_span: info_span!("system_commands", name = name),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the system's name
|
||||
#[inline]
|
||||
pub fn name(&self) -> &str {
|
||||
pub fn name(&self) -> &DebugName {
|
||||
&self.name
|
||||
}
|
||||
|
||||
@ -67,7 +68,7 @@ impl SystemMeta {
|
||||
self.system_span = info_span!("system", name = name);
|
||||
self.commands_span = info_span!("system_commands", name = name);
|
||||
}
|
||||
self.name = new_name;
|
||||
self.name = new_name.into();
|
||||
}
|
||||
|
||||
/// Returns true if the system is [`Send`].
|
||||
@ -600,7 +601,7 @@ where
|
||||
type Out = F::Out;
|
||||
|
||||
#[inline]
|
||||
fn name(&self) -> Cow<'static, str> {
|
||||
fn name(&self) -> DebugName {
|
||||
self.system_meta.name.clone()
|
||||
}
|
||||
|
||||
@ -712,7 +713,7 @@ where
|
||||
check_system_change_tick(
|
||||
&mut self.system_meta.last_run,
|
||||
check,
|
||||
self.system_meta.name.as_ref(),
|
||||
self.system_meta.name.clone(),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
use alloc::{borrow::Cow, vec::Vec};
|
||||
use alloc::vec::Vec;
|
||||
use bevy_utils::prelude::DebugName;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use crate::{
|
||||
@ -112,7 +113,7 @@ where
|
||||
type Out = Result;
|
||||
|
||||
#[inline]
|
||||
fn name(&self) -> Cow<'static, str> {
|
||||
fn name(&self) -> DebugName {
|
||||
self.observer.name()
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
use bevy_utils::prelude::DebugName;
|
||||
|
||||
use crate::{
|
||||
batching::BatchingStrategy,
|
||||
component::Tick,
|
||||
@ -1949,8 +1951,8 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
||||
|
||||
match (first, extra) {
|
||||
(Some(r), false) => Ok(r),
|
||||
(None, _) => Err(QuerySingleError::NoEntities(core::any::type_name::<Self>())),
|
||||
(Some(_), _) => Err(QuerySingleError::MultipleEntities(core::any::type_name::<
|
||||
(None, _) => Err(QuerySingleError::NoEntities(DebugName::type_name::<Self>())),
|
||||
(Some(_), _) => Err(QuerySingleError::MultipleEntities(DebugName::type_name::<
|
||||
Self,
|
||||
>())),
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
use alloc::{borrow::Cow, vec::Vec};
|
||||
use alloc::vec::Vec;
|
||||
use bevy_utils::prelude::DebugName;
|
||||
|
||||
use crate::{
|
||||
component::{CheckChangeTicks, ComponentId, Tick},
|
||||
@ -25,7 +26,7 @@ impl<S: System<In = ()>> System for InfallibleSystemWrapper<S> {
|
||||
type Out = Result;
|
||||
|
||||
#[inline]
|
||||
fn name(&self) -> Cow<'static, str> {
|
||||
fn name(&self) -> DebugName {
|
||||
self.0.name()
|
||||
}
|
||||
|
||||
@ -139,7 +140,7 @@ where
|
||||
type In = ();
|
||||
type Out = S::Out;
|
||||
|
||||
fn name(&self) -> Cow<'static, str> {
|
||||
fn name(&self) -> DebugName {
|
||||
self.system.name()
|
||||
}
|
||||
|
||||
@ -232,7 +233,7 @@ where
|
||||
type In = ();
|
||||
type Out = S::Out;
|
||||
|
||||
fn name(&self) -> Cow<'static, str> {
|
||||
fn name(&self) -> DebugName {
|
||||
self.system.name()
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
clippy::module_inception,
|
||||
reason = "This instance of module inception is being discussed; see #17353."
|
||||
)]
|
||||
use bevy_utils::prelude::DebugName;
|
||||
use bitflags::bitflags;
|
||||
use core::fmt::Debug;
|
||||
use log::warn;
|
||||
@ -15,7 +16,7 @@ use crate::{
|
||||
world::{unsafe_world_cell::UnsafeWorldCell, DeferredWorld, World},
|
||||
};
|
||||
|
||||
use alloc::{borrow::Cow, boxed::Box, vec::Vec};
|
||||
use alloc::{boxed::Box, vec::Vec};
|
||||
use core::any::TypeId;
|
||||
|
||||
use super::{IntoSystem, SystemParamValidationError};
|
||||
@ -49,8 +50,9 @@ pub trait System: Send + Sync + 'static {
|
||||
type In: SystemInput;
|
||||
/// The system's output.
|
||||
type Out;
|
||||
|
||||
/// Returns the system's name.
|
||||
fn name(&self) -> Cow<'static, str>;
|
||||
fn name(&self) -> DebugName;
|
||||
/// Returns the [`TypeId`] of the underlying system type.
|
||||
#[inline]
|
||||
fn type_id(&self) -> TypeId {
|
||||
@ -227,7 +229,7 @@ pub type BoxedSystem<In = (), Out = ()> = Box<dyn System<In = In, Out = Out>>;
|
||||
pub(crate) fn check_system_change_tick(
|
||||
last_run: &mut Tick,
|
||||
check: CheckChangeTicks,
|
||||
system_name: &str,
|
||||
system_name: DebugName,
|
||||
) {
|
||||
if last_run.check_tick(check) {
|
||||
let age = check.present_tick().relative_to(*last_run).get();
|
||||
@ -398,7 +400,7 @@ pub enum RunSystemError {
|
||||
#[error("System {system} did not run due to failed parameter validation: {err}")]
|
||||
InvalidParams {
|
||||
/// The identifier of the system that was run.
|
||||
system: Cow<'static, str>,
|
||||
system: DebugName,
|
||||
/// The returned parameter validation error.
|
||||
err: SystemParamValidationError,
|
||||
},
|
||||
|
@ -5,9 +5,8 @@ use crate::{
|
||||
system::{ExclusiveSystemParam, ReadOnlySystemParam, SystemMeta, SystemParam},
|
||||
world::unsafe_world_cell::UnsafeWorldCell,
|
||||
};
|
||||
use alloc::borrow::Cow;
|
||||
use core::ops::Deref;
|
||||
use derive_more::derive::{AsRef, Display, Into};
|
||||
use bevy_utils::prelude::DebugName;
|
||||
use derive_more::derive::{Display, Into};
|
||||
|
||||
/// [`SystemParam`] that returns the name of the system which it is used in.
|
||||
///
|
||||
@ -35,21 +34,13 @@ use derive_more::derive::{AsRef, Display, Into};
|
||||
/// logger.log("Hello");
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug, Into, Display, AsRef)]
|
||||
#[as_ref(str)]
|
||||
pub struct SystemName(Cow<'static, str>);
|
||||
#[derive(Debug, Into, Display)]
|
||||
pub struct SystemName(DebugName);
|
||||
|
||||
impl SystemName {
|
||||
/// Gets the name of the system.
|
||||
pub fn name(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for SystemName {
|
||||
type Target = str;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.name()
|
||||
pub fn name(&self) -> DebugName {
|
||||
self.0.clone()
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,7 +95,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_system_name_regular_param() {
|
||||
fn testing(name: SystemName) -> String {
|
||||
name.name().to_owned()
|
||||
name.name().as_string()
|
||||
}
|
||||
|
||||
let mut world = World::default();
|
||||
@ -116,7 +107,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_system_name_exclusive_param() {
|
||||
fn testing(_world: &mut World, name: SystemName) -> String {
|
||||
name.name().to_owned()
|
||||
name.name().as_string()
|
||||
}
|
||||
|
||||
let mut world = World::default();
|
||||
@ -130,7 +121,7 @@ mod tests {
|
||||
let mut world = World::default();
|
||||
let system =
|
||||
IntoSystem::into_system(|name: SystemName| name.name().to_owned()).with_name("testing");
|
||||
let name = world.run_system_once(system).unwrap();
|
||||
let name = world.run_system_once(system).unwrap().as_string();
|
||||
assert_eq!(name, "testing");
|
||||
}
|
||||
|
||||
@ -140,7 +131,7 @@ mod tests {
|
||||
let system =
|
||||
IntoSystem::into_system(|_world: &mut World, name: SystemName| name.name().to_owned())
|
||||
.with_name("testing");
|
||||
let name = world.run_system_once(system).unwrap();
|
||||
let name = world.run_system_once(system).unwrap().as_string();
|
||||
assert_eq!(name, "testing");
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ use alloc::{
|
||||
pub use bevy_ecs_macros::SystemParam;
|
||||
use bevy_platform::cell::SyncCell;
|
||||
use bevy_ptr::UnsafeCellDeref;
|
||||
use bevy_utils::prelude::DebugName;
|
||||
use core::{
|
||||
any::Any,
|
||||
fmt::{Debug, Display},
|
||||
@ -32,7 +33,6 @@ use core::{
|
||||
ops::{Deref, DerefMut},
|
||||
panic::Location,
|
||||
};
|
||||
use disqualified::ShortName;
|
||||
use thiserror::Error;
|
||||
|
||||
use super::Populated;
|
||||
@ -343,8 +343,8 @@ unsafe impl<D: QueryData + 'static, F: QueryFilter + 'static> SystemParam for Qu
|
||||
) {
|
||||
assert_component_access_compatibility(
|
||||
&system_meta.name,
|
||||
core::any::type_name::<D>(),
|
||||
core::any::type_name::<F>(),
|
||||
DebugName::type_name::<D>(),
|
||||
DebugName::type_name::<F>(),
|
||||
component_access_set,
|
||||
&state.component_access,
|
||||
world,
|
||||
@ -368,9 +368,9 @@ unsafe impl<D: QueryData + 'static, F: QueryFilter + 'static> SystemParam for Qu
|
||||
}
|
||||
|
||||
fn assert_component_access_compatibility(
|
||||
system_name: &str,
|
||||
query_type: &'static str,
|
||||
filter_type: &'static str,
|
||||
system_name: &DebugName,
|
||||
query_type: DebugName,
|
||||
filter_type: DebugName,
|
||||
system_access: &FilteredAccessSet<ComponentId>,
|
||||
current: &FilteredAccess<ComponentId>,
|
||||
world: &World,
|
||||
@ -384,7 +384,7 @@ fn assert_component_access_compatibility(
|
||||
if !accesses.is_empty() {
|
||||
accesses.push(' ');
|
||||
}
|
||||
panic!("error[B0001]: Query<{}, {}> in system {system_name} accesses component(s) {accesses}in a way that conflicts with a previous system parameter. Consider using `Without<T>` to create disjoint Queries or merging conflicting Queries into a `ParamSet`. See: https://bevy.org/learn/errors/b0001", ShortName(query_type), ShortName(filter_type));
|
||||
panic!("error[B0001]: Query<{}, {}> in system {system_name} accesses component(s) {accesses}in a way that conflicts with a previous system parameter. Consider using `Without<T>` to create disjoint Queries or merging conflicting Queries into a `ParamSet`. See: https://bevy.org/learn/errors/b0001", query_type.shortname(), filter_type.shortname());
|
||||
}
|
||||
|
||||
// SAFETY: Relevant query ComponentId access is applied to SystemMeta. If
|
||||
@ -767,9 +767,10 @@ unsafe impl<'a, T: Resource> SystemParam for Res<'a, T> {
|
||||
assert!(
|
||||
!combined_access.has_resource_write(component_id),
|
||||
"error[B0002]: Res<{}> in system {} conflicts with a previous ResMut<{0}> access. Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
|
||||
core::any::type_name::<T>(),
|
||||
DebugName::type_name::<T>(),
|
||||
system_meta.name,
|
||||
);
|
||||
|
||||
component_access_set.add_unfiltered_resource_read(component_id);
|
||||
}
|
||||
|
||||
@ -807,8 +808,8 @@ unsafe impl<'a, T: Resource> SystemParam for Res<'a, T> {
|
||||
panic!(
|
||||
"Resource requested by {} does not exist: {}",
|
||||
system_meta.name,
|
||||
core::any::type_name::<T>()
|
||||
)
|
||||
DebugName::type_name::<T>()
|
||||
);
|
||||
});
|
||||
Res {
|
||||
value: ptr.deref(),
|
||||
@ -843,11 +844,11 @@ unsafe impl<'a, T: Resource> SystemParam for ResMut<'a, T> {
|
||||
if combined_access.has_resource_write(component_id) {
|
||||
panic!(
|
||||
"error[B0002]: ResMut<{}> in system {} conflicts with a previous ResMut<{0}> access. Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
|
||||
core::any::type_name::<T>(), system_meta.name);
|
||||
DebugName::type_name::<T>(), system_meta.name);
|
||||
} else if combined_access.has_resource_read(component_id) {
|
||||
panic!(
|
||||
"error[B0002]: ResMut<{}> in system {} conflicts with a previous Res<{0}> access. Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
|
||||
core::any::type_name::<T>(), system_meta.name);
|
||||
DebugName::type_name::<T>(), system_meta.name);
|
||||
}
|
||||
component_access_set.add_unfiltered_resource_write(component_id);
|
||||
}
|
||||
@ -885,8 +886,8 @@ unsafe impl<'a, T: Resource> SystemParam for ResMut<'a, T> {
|
||||
panic!(
|
||||
"Resource requested by {} does not exist: {}",
|
||||
system_meta.name,
|
||||
core::any::type_name::<T>()
|
||||
)
|
||||
DebugName::type_name::<T>()
|
||||
);
|
||||
});
|
||||
ResMut {
|
||||
value: value.value.deref_mut::<T>(),
|
||||
@ -1435,7 +1436,7 @@ unsafe impl<'a, T: 'static> SystemParam for NonSend<'a, T> {
|
||||
assert!(
|
||||
!combined_access.has_resource_write(component_id),
|
||||
"error[B0002]: NonSend<{}> in system {} conflicts with a previous mutable resource access ({0}). Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
|
||||
core::any::type_name::<T>(),
|
||||
DebugName::type_name::<T>(),
|
||||
system_meta.name,
|
||||
);
|
||||
component_access_set.add_unfiltered_resource_read(component_id);
|
||||
@ -1475,7 +1476,7 @@ unsafe impl<'a, T: 'static> SystemParam for NonSend<'a, T> {
|
||||
panic!(
|
||||
"Non-send resource requested by {} does not exist: {}",
|
||||
system_meta.name,
|
||||
core::any::type_name::<T>()
|
||||
DebugName::type_name::<T>()
|
||||
)
|
||||
});
|
||||
|
||||
@ -1511,11 +1512,11 @@ unsafe impl<'a, T: 'static> SystemParam for NonSendMut<'a, T> {
|
||||
if combined_access.has_component_write(component_id) {
|
||||
panic!(
|
||||
"error[B0002]: NonSendMut<{}> in system {} conflicts with a previous mutable resource access ({0}). Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
|
||||
core::any::type_name::<T>(), system_meta.name);
|
||||
DebugName::type_name::<T>(), system_meta.name);
|
||||
} else if combined_access.has_component_read(component_id) {
|
||||
panic!(
|
||||
"error[B0002]: NonSendMut<{}> in system {} conflicts with a previous immutable resource access ({0}). Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
|
||||
core::any::type_name::<T>(), system_meta.name);
|
||||
DebugName::type_name::<T>(), system_meta.name);
|
||||
}
|
||||
component_access_set.add_unfiltered_resource_write(component_id);
|
||||
}
|
||||
@ -1554,8 +1555,8 @@ unsafe impl<'a, T: 'static> SystemParam for NonSendMut<'a, T> {
|
||||
panic!(
|
||||
"Non-send resource requested by {} does not exist: {}",
|
||||
system_meta.name,
|
||||
core::any::type_name::<T>()
|
||||
)
|
||||
DebugName::type_name::<T>()
|
||||
);
|
||||
});
|
||||
NonSendMut {
|
||||
value: ptr.assert_unique().deref_mut(),
|
||||
@ -2786,7 +2787,7 @@ pub struct SystemParamValidationError {
|
||||
|
||||
/// A string identifying the invalid parameter.
|
||||
/// This is usually the type name of the parameter.
|
||||
pub param: Cow<'static, str>,
|
||||
pub param: DebugName,
|
||||
|
||||
/// A string identifying the field within a parameter using `#[derive(SystemParam)]`.
|
||||
/// This will be an empty string for other parameters.
|
||||
@ -2818,7 +2819,7 @@ impl SystemParamValidationError {
|
||||
Self {
|
||||
skipped,
|
||||
message: message.into(),
|
||||
param: Cow::Borrowed(core::any::type_name::<T>()),
|
||||
param: DebugName::type_name::<T>(),
|
||||
field: field.into(),
|
||||
}
|
||||
}
|
||||
@ -2829,7 +2830,7 @@ impl Display for SystemParamValidationError {
|
||||
write!(
|
||||
fmt,
|
||||
"Parameter `{}{}` failed validation: {}",
|
||||
ShortName(&self.param),
|
||||
self.param.shortname(),
|
||||
self.field,
|
||||
self.message
|
||||
)?;
|
||||
|
@ -1,5 +1,7 @@
|
||||
use core::ops::Deref;
|
||||
|
||||
use bevy_utils::prelude::DebugName;
|
||||
|
||||
use crate::{
|
||||
archetype::Archetype,
|
||||
change_detection::{MaybeLocation, MutUntyped},
|
||||
@ -451,7 +453,7 @@ impl<'w> DeferredWorld<'w> {
|
||||
Did you forget to add it using `app.insert_resource` / `app.init_resource`?
|
||||
Resources are also implicitly added via `app.add_event`,
|
||||
and can be added by plugins.",
|
||||
core::any::type_name::<R>()
|
||||
DebugName::type_name::<R>()
|
||||
),
|
||||
}
|
||||
}
|
||||
@ -480,7 +482,7 @@ impl<'w> DeferredWorld<'w> {
|
||||
"Requested non-send resource {} does not exist in the `World`.
|
||||
Did you forget to add it using `app.insert_non_send_resource` / `app.init_non_send_resource`?
|
||||
Non-send resources can also be added by plugins.",
|
||||
core::any::type_name::<R>()
|
||||
DebugName::type_name::<R>()
|
||||
),
|
||||
}
|
||||
}
|
||||
@ -523,7 +525,7 @@ impl<'w> DeferredWorld<'w> {
|
||||
let Some(mut events_resource) = self.get_resource_mut::<Events<E>>() else {
|
||||
log::error!(
|
||||
"Unable to send event `{}`\n\tEvent must be added to the app with `add_event()`\n\thttps://docs.rs/bevy/*/bevy/app/struct.App.html#method.add_event ",
|
||||
core::any::type_name::<E>()
|
||||
DebugName::type_name::<E>()
|
||||
);
|
||||
return None;
|
||||
};
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! Contains error types returned by bevy's schedule.
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use bevy_utils::prelude::DebugName;
|
||||
|
||||
use crate::{
|
||||
component::ComponentId,
|
||||
@ -24,7 +25,7 @@ pub struct TryRunScheduleError(pub InternedScheduleLabel);
|
||||
#[error("Could not insert bundles of type {bundle_type} into the entities with the following IDs because they do not exist: {entities:?}")]
|
||||
pub struct TryInsertBatchError {
|
||||
/// The bundles' type name.
|
||||
pub bundle_type: &'static str,
|
||||
pub bundle_type: DebugName,
|
||||
/// The IDs of the provided entities that do not exist.
|
||||
pub entities: Vec<Entity>,
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ use crate::{
|
||||
prelude::{Add, Despawn, Insert, Remove, Replace},
|
||||
};
|
||||
pub use bevy_ecs_macros::FromWorld;
|
||||
use bevy_utils::prelude::DebugName;
|
||||
pub use deferred_world::DeferredWorld;
|
||||
pub use entity_fetch::{EntityFetcher, WorldEntityFetch};
|
||||
pub use entity_ref::{
|
||||
@ -1948,7 +1949,7 @@ impl World {
|
||||
Did you forget to add it using `app.insert_resource` / `app.init_resource`?
|
||||
Resources are also implicitly added via `app.add_event`,
|
||||
and can be added by plugins.",
|
||||
core::any::type_name::<R>()
|
||||
DebugName::type_name::<R>()
|
||||
),
|
||||
}
|
||||
}
|
||||
@ -1972,7 +1973,7 @@ impl World {
|
||||
Did you forget to add it using `app.insert_resource` / `app.init_resource`?
|
||||
Resources are also implicitly added via `app.add_event`,
|
||||
and can be added by plugins.",
|
||||
core::any::type_name::<R>()
|
||||
DebugName::type_name::<R>()
|
||||
),
|
||||
}
|
||||
}
|
||||
@ -1996,7 +1997,7 @@ impl World {
|
||||
Did you forget to add it using `app.insert_resource` / `app.init_resource`?
|
||||
Resources are also implicitly added via `app.add_event`,
|
||||
and can be added by plugins.",
|
||||
core::any::type_name::<R>()
|
||||
DebugName::type_name::<R>()
|
||||
),
|
||||
}
|
||||
}
|
||||
@ -2160,7 +2161,7 @@ impl World {
|
||||
"Requested non-send resource {} does not exist in the `World`.
|
||||
Did you forget to add it using `app.insert_non_send_resource` / `app.init_non_send_resource`?
|
||||
Non-send resources can also be added by plugins.",
|
||||
core::any::type_name::<R>()
|
||||
DebugName::type_name::<R>()
|
||||
),
|
||||
}
|
||||
}
|
||||
@ -2182,7 +2183,7 @@ impl World {
|
||||
"Requested non-send resource {} does not exist in the `World`.
|
||||
Did you forget to add it using `app.insert_non_send_resource` / `app.init_non_send_resource`?
|
||||
Non-send resources can also be added by plugins.",
|
||||
core::any::type_name::<R>()
|
||||
DebugName::type_name::<R>()
|
||||
),
|
||||
}
|
||||
}
|
||||
@ -2349,11 +2350,11 @@ impl World {
|
||||
)
|
||||
};
|
||||
} else {
|
||||
panic!("error[B0003]: Could not insert a bundle (of type `{}`) for entity {entity}, which {}. See: https://bevy.org/learn/errors/b0003", core::any::type_name::<B>(), self.entities.entity_does_not_exist_error_details(entity));
|
||||
panic!("error[B0003]: Could not insert a bundle (of type `{}`) for entity {entity}, which {}. See: https://bevy.org/learn/errors/b0003", DebugName::type_name::<B>(), self.entities.entity_does_not_exist_error_details(entity));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
panic!("error[B0003]: Could not insert a bundle (of type `{}`) for entity {first_entity}, which {}. See: https://bevy.org/learn/errors/b0003", core::any::type_name::<B>(), self.entities.entity_does_not_exist_error_details(first_entity));
|
||||
panic!("error[B0003]: Could not insert a bundle (of type `{}`) for entity {first_entity}, which {}. See: https://bevy.org/learn/errors/b0003", DebugName::type_name::<B>(), self.entities.entity_does_not_exist_error_details(first_entity));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2517,7 +2518,7 @@ impl World {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(TryInsertBatchError {
|
||||
bundle_type: core::any::type_name::<B>(),
|
||||
bundle_type: DebugName::type_name::<B>(),
|
||||
entities: invalid_entities,
|
||||
})
|
||||
}
|
||||
@ -2551,7 +2552,7 @@ impl World {
|
||||
#[track_caller]
|
||||
pub fn resource_scope<R: Resource, U>(&mut self, f: impl FnOnce(&mut World, Mut<R>) -> U) -> U {
|
||||
self.try_resource_scope(f)
|
||||
.unwrap_or_else(|| panic!("resource does not exist: {}", core::any::type_name::<R>()))
|
||||
.unwrap_or_else(|| panic!("resource does not exist: {}", DebugName::type_name::<R>()))
|
||||
}
|
||||
|
||||
/// Temporarily removes the requested resource from this [`World`] if it exists, runs custom user code,
|
||||
@ -2591,7 +2592,7 @@ impl World {
|
||||
assert!(!self.contains_resource::<R>(),
|
||||
"Resource `{}` was inserted during a call to World::resource_scope.\n\
|
||||
This is not allowed as the original resource is reinserted to the world after the closure is invoked.",
|
||||
core::any::type_name::<R>());
|
||||
DebugName::type_name::<R>());
|
||||
|
||||
OwningPtr::make(value, |ptr| {
|
||||
// SAFETY: pointer is of type R
|
||||
@ -2632,7 +2633,7 @@ impl World {
|
||||
let Some(mut events_resource) = self.get_resource_mut::<Events<E>>() else {
|
||||
log::error!(
|
||||
"Unable to send event `{}`\n\tEvent must be added to the app with `add_event()`\n\thttps://docs.rs/bevy/*/bevy/app/struct.App.html#method.add_event ",
|
||||
core::any::type_name::<E>()
|
||||
DebugName::type_name::<E>()
|
||||
);
|
||||
return None;
|
||||
};
|
||||
@ -3633,6 +3634,7 @@ mod tests {
|
||||
};
|
||||
use bevy_ecs_macros::Component;
|
||||
use bevy_platform::collections::{HashMap, HashSet};
|
||||
use bevy_utils::prelude::DebugName;
|
||||
use core::{
|
||||
any::TypeId,
|
||||
panic,
|
||||
@ -3816,12 +3818,12 @@ mod tests {
|
||||
let mut iter = world.iter_resources();
|
||||
|
||||
let (info, ptr) = iter.next().unwrap();
|
||||
assert_eq!(info.name(), core::any::type_name::<TestResource>());
|
||||
assert_eq!(info.name(), DebugName::type_name::<TestResource>());
|
||||
// SAFETY: We know that the resource is of type `TestResource`
|
||||
assert_eq!(unsafe { ptr.deref::<TestResource>().0 }, 42);
|
||||
|
||||
let (info, ptr) = iter.next().unwrap();
|
||||
assert_eq!(info.name(), core::any::type_name::<TestResource2>());
|
||||
assert_eq!(info.name(), DebugName::type_name::<TestResource2>());
|
||||
assert_eq!(
|
||||
// SAFETY: We know that the resource is of type `TestResource2`
|
||||
unsafe { &ptr.deref::<TestResource2>().0 },
|
||||
@ -3844,14 +3846,14 @@ mod tests {
|
||||
let mut iter = world.iter_resources_mut();
|
||||
|
||||
let (info, mut mut_untyped) = iter.next().unwrap();
|
||||
assert_eq!(info.name(), core::any::type_name::<TestResource>());
|
||||
assert_eq!(info.name(), DebugName::type_name::<TestResource>());
|
||||
// SAFETY: We know that the resource is of type `TestResource`
|
||||
unsafe {
|
||||
mut_untyped.as_mut().deref_mut::<TestResource>().0 = 43;
|
||||
};
|
||||
|
||||
let (info, mut mut_untyped) = iter.next().unwrap();
|
||||
assert_eq!(info.name(), core::any::type_name::<TestResource2>());
|
||||
assert_eq!(info.name(), DebugName::type_name::<TestResource2>());
|
||||
// SAFETY: We know that the resource is of type `TestResource2`
|
||||
unsafe {
|
||||
mut_untyped.as_mut().deref_mut::<TestResource2>().0 = "Hello, world?".to_string();
|
||||
|
@ -4,8 +4,8 @@ use core::any::TypeId;
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
use alloc::string::{String, ToString};
|
||||
use bevy_reflect::{Reflect, ReflectFromPtr};
|
||||
use bevy_utils::prelude::DebugName;
|
||||
|
||||
use crate::{prelude::*, world::ComponentId};
|
||||
|
||||
@ -77,10 +77,7 @@ impl World {
|
||||
};
|
||||
|
||||
let Some(comp_ptr) = self.get_by_id(entity, component_id) else {
|
||||
let component_name = self
|
||||
.components()
|
||||
.get_name(component_id)
|
||||
.map(|name| name.to_string());
|
||||
let component_name = self.components().get_name(component_id);
|
||||
|
||||
return Err(GetComponentReflectError::EntityDoesNotHaveComponent {
|
||||
entity,
|
||||
@ -166,10 +163,7 @@ impl World {
|
||||
|
||||
// HACK: Only required for the `None`-case/`else`-branch, but it borrows `self`, which will
|
||||
// already be mutably borrowed by `self.get_mut_by_id()`, and I didn't find a way around it.
|
||||
let component_name = self
|
||||
.components()
|
||||
.get_name(component_id)
|
||||
.map(|name| name.to_string());
|
||||
let component_name = self.components().get_name(component_id).clone();
|
||||
|
||||
let Some(comp_mut_untyped) = self.get_mut_by_id(entity, component_id) else {
|
||||
return Err(GetComponentReflectError::EntityDoesNotHaveComponent {
|
||||
@ -223,7 +217,7 @@ pub enum GetComponentReflectError {
|
||||
component_id: ComponentId,
|
||||
/// The name corresponding to the [`Component`] with the given [`TypeId`], or `None`
|
||||
/// if not available.
|
||||
component_name: Option<String>,
|
||||
component_name: Option<DebugName>,
|
||||
},
|
||||
|
||||
/// The [`World`] was missing the [`AppTypeRegistry`] resource.
|
||||
|
@ -346,6 +346,8 @@ web = [
|
||||
|
||||
hotpatching = ["bevy_app/hotpatching", "bevy_ecs/hotpatching"]
|
||||
|
||||
debug = ["bevy_utils/debug"]
|
||||
|
||||
[dependencies]
|
||||
# bevy (no_std)
|
||||
bevy_app = { path = "../bevy_app", version = "0.16.0-dev", default-features = false, features = [
|
||||
|
@ -21,7 +21,9 @@ bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev", features = [
|
||||
] }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev" }
|
||||
bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev" }
|
||||
bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev" }
|
||||
bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev", features = [
|
||||
"debug",
|
||||
] }
|
||||
bevy_platform = { path = "../bevy_platform", version = "0.16.0-dev", default-features = false, features = [
|
||||
"std",
|
||||
"serialize",
|
||||
|
@ -1130,7 +1130,7 @@ pub fn process_remote_list_request(In(params): In<Option<Value>>, world: &World)
|
||||
let Some(component_info) = world.components().get_info(component_id) else {
|
||||
continue;
|
||||
};
|
||||
response.push(component_info.name().to_owned());
|
||||
response.push(component_info.name().to_string());
|
||||
}
|
||||
}
|
||||
// If `None`, list all registered components.
|
||||
@ -1189,7 +1189,7 @@ pub fn process_remote_list_watching_request(
|
||||
let Some(component_info) = world.components().get_info(component_id) else {
|
||||
continue;
|
||||
};
|
||||
response.added.push(component_info.name().to_owned());
|
||||
response.added.push(component_info.name().to_string());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1202,7 +1202,7 @@ pub fn process_remote_list_watching_request(
|
||||
let Some(component_info) = world.components().get_info(*component_id) else {
|
||||
continue;
|
||||
};
|
||||
response.removed.push(component_info.name().to_owned());
|
||||
response.removed.push(component_info.name().to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ impl Scene {
|
||||
type_registry
|
||||
.get(type_id)
|
||||
.ok_or_else(|| SceneSpawnError::UnregisteredType {
|
||||
std_type_name: component_info.name().to_string(),
|
||||
std_type_name: component_info.name(),
|
||||
})?;
|
||||
let reflect_resource = registration.data::<ReflectResource>().ok_or_else(|| {
|
||||
SceneSpawnError::UnregisteredResource {
|
||||
@ -133,7 +133,7 @@ impl Scene {
|
||||
let registration = type_registry
|
||||
.get(component_info.type_id().unwrap())
|
||||
.ok_or_else(|| SceneSpawnError::UnregisteredType {
|
||||
std_type_name: component_info.name().to_string(),
|
||||
std_type_name: component_info.name(),
|
||||
})?;
|
||||
let reflect_component =
|
||||
registration.data::<ReflectComponent>().ok_or_else(|| {
|
||||
|
@ -10,6 +10,7 @@ use bevy_ecs::{
|
||||
};
|
||||
use bevy_platform::collections::{HashMap, HashSet};
|
||||
use bevy_reflect::Reflect;
|
||||
use bevy_utils::prelude::DebugName;
|
||||
use thiserror::Error;
|
||||
use uuid::Uuid;
|
||||
|
||||
@ -105,7 +106,7 @@ pub enum SceneSpawnError {
|
||||
)]
|
||||
UnregisteredType {
|
||||
/// The [type name](std::any::type_name) for the unregistered type.
|
||||
std_type_name: String,
|
||||
std_type_name: DebugName,
|
||||
},
|
||||
/// Scene contains an unregistered type which has a `TypePath`.
|
||||
#[error(
|
||||
|
@ -16,9 +16,14 @@ wgpu_wrapper = ["dep:send_wrapper"]
|
||||
# Provides access to the `Parallel` type.
|
||||
parallel = ["bevy_platform/std", "dep:thread_local"]
|
||||
|
||||
std = ["disqualified/alloc"]
|
||||
|
||||
debug = []
|
||||
|
||||
[dependencies]
|
||||
bevy_platform = { path = "../bevy_platform", version = "0.16.0-dev", default-features = false }
|
||||
|
||||
disqualified = { version = "1.0", default-features = false }
|
||||
thread_local = { version = "1.0", optional = true }
|
||||
|
||||
[target.'cfg(all(target_arch = "wasm32", target_feature = "atomics"))'.dependencies]
|
||||
|
102
crates/bevy_utils/src/debug_info.rs
Normal file
102
crates/bevy_utils/src/debug_info.rs
Normal file
@ -0,0 +1,102 @@
|
||||
use alloc::{borrow::Cow, fmt, string::String};
|
||||
#[cfg(feature = "debug")]
|
||||
use core::any::type_name;
|
||||
use disqualified::ShortName;
|
||||
|
||||
#[cfg(not(feature = "debug"))]
|
||||
const FEATURE_DISABLED: &'static str = "Enable the debug feature to see the name";
|
||||
|
||||
/// Wrapper to help debugging ECS issues. This is used to display the names of systems, components, ...
|
||||
///
|
||||
/// * If the `debug` feature is enabled, the actual name will be used
|
||||
/// * If it is disabled, a string mentioning the disabled feature will be used
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct DebugName {
|
||||
#[cfg(feature = "debug")]
|
||||
name: Cow<'static, str>,
|
||||
}
|
||||
|
||||
impl fmt::Display for DebugName {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
#[cfg(feature = "debug")]
|
||||
f.write_str(self.name.as_ref())?;
|
||||
#[cfg(not(feature = "debug"))]
|
||||
f.write_str(FEATURE_DISABLED)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl DebugName {
|
||||
/// Create a new `DebugName` from a `&str`
|
||||
///
|
||||
/// The value will be ignored if the `debug` feature is not enabled
|
||||
#[cfg_attr(not(feature = "debug"), expect(unused_variables))]
|
||||
pub fn borrowed(value: &'static str) -> Self {
|
||||
DebugName {
|
||||
#[cfg(feature = "debug")]
|
||||
name: Cow::Borrowed(value),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new `DebugName` from a `String`
|
||||
///
|
||||
/// The value will be ignored if the `debug` feature is not enabled
|
||||
#[cfg_attr(not(feature = "debug"), expect(unused_variables))]
|
||||
pub fn owned(value: String) -> Self {
|
||||
DebugName {
|
||||
#[cfg(feature = "debug")]
|
||||
name: Cow::Owned(value),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new `DebugName` from a type by using its [`core::any::type_name`]
|
||||
///
|
||||
/// The value will be ignored if the `debug` feature is not enabled
|
||||
pub fn type_name<T>() -> Self {
|
||||
DebugName {
|
||||
#[cfg(feature = "debug")]
|
||||
name: Cow::Borrowed(type_name::<T>()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the [`ShortName`] corresping to this debug name
|
||||
///
|
||||
/// The value will be a static string if the `debug` feature is not enabled
|
||||
pub fn shortname(&self) -> ShortName {
|
||||
#[cfg(feature = "debug")]
|
||||
return ShortName(self.name.as_ref());
|
||||
#[cfg(not(feature = "debug"))]
|
||||
return ShortName(FEATURE_DISABLED);
|
||||
}
|
||||
|
||||
/// Return the string hold by this `DebugName`
|
||||
///
|
||||
/// This is intended for debugging purpose, and only available if the `debug` feature is enabled
|
||||
#[cfg(feature = "debug")]
|
||||
pub fn as_string(&self) -> String {
|
||||
self.name.clone().into_owned()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Cow<'static, str>> for DebugName {
|
||||
#[cfg_attr(not(feature = "debug"), expect(unused_variables))]
|
||||
fn from(value: Cow<'static, str>) -> Self {
|
||||
Self {
|
||||
#[cfg(feature = "debug")]
|
||||
name: value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for DebugName {
|
||||
fn from(value: String) -> Self {
|
||||
Self::owned(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for DebugName {
|
||||
fn from(value: &'static str) -> Self {
|
||||
Self::borrowed(value)
|
||||
}
|
||||
}
|
@ -43,12 +43,14 @@ cfg::parallel! {
|
||||
///
|
||||
/// This includes the most common types in this crate, re-exported for your convenience.
|
||||
pub mod prelude {
|
||||
pub use crate::debug_info::DebugName;
|
||||
pub use crate::default;
|
||||
}
|
||||
|
||||
#[cfg(feature = "wgpu_wrapper")]
|
||||
mod wgpu_wrapper;
|
||||
|
||||
mod debug_info;
|
||||
mod default;
|
||||
mod once;
|
||||
|
||||
|
@ -41,6 +41,7 @@ The default feature set enables most of the expected features of a game engine,
|
||||
|bevy_window|Windowing layer|
|
||||
|bevy_winit|winit window and input backend|
|
||||
|custom_cursor|Enable winit custom cursor support|
|
||||
|debug|Enable collecting debug information about systems and components to help with diagnostics|
|
||||
|default_font|Include a default font, containing only ASCII characters, at the cost of a 20kB binary size increase|
|
||||
|hdr|HDR image format support|
|
||||
|ktx2|KTX2 compressed texture support|
|
||||
|
@ -104,7 +104,10 @@ fn build_ui(
|
||||
mut state: ResMut<State>,
|
||||
) {
|
||||
let mut text_spans = Vec::new();
|
||||
let mut always_run = Vec::new();
|
||||
let mut always_run: Vec<(
|
||||
bevy_ecs::intern::Interned<dyn ScheduleLabel + 'static>,
|
||||
NodeId,
|
||||
)> = Vec::new();
|
||||
|
||||
let Ok(schedule_order) = stepping.schedules() else {
|
||||
return;
|
||||
@ -131,7 +134,8 @@ fn build_ui(
|
||||
|
||||
for (node_id, system) in systems {
|
||||
// skip bevy default systems; we don't want to step those
|
||||
if system.name().starts_with("bevy") {
|
||||
#[cfg(feature = "debug")]
|
||||
if system.name().as_string().starts_with("bevy") {
|
||||
always_run.push((*label, node_id));
|
||||
continue;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user