
## Objective The error `EntityFetchError::NoSuchEntity` has an `UnsafeWorldCell` inside it, which it uses to call `Entities::entity_does_not_exist_error_details_message` when being printed. That method returns a `String` that, if the `track_location` feature is enabled, contains the location of whoever despawned the relevant entity. I initially had to modify this error while working on #17043. The `UnsafeWorldCell` was causing borrow problems when being returned from a command, so I tried replacing it with the `String` that the method returns, since that was the world cell's only purpose. Unfortunately, `String`s are slow, and it significantly impacted performance (on top of that PR's performance hit): <details> <summary>17043 benchmarks</summary> ### With `String`  ### No `String`  </details> For that PR, I just removed the error details entirely, but I figured I'd try to find a way to keep them around. ## Solution - Replace the `String` with a helper struct that holds the location, and only turn it into a string when someone actually wants to print it. - Replace the `UnsafeWorldCell` with the aforementioned struct. - Do the same for `QueryEntityError::NoSuchEntity`. ## Benchmarking This had some interesting performance impact: <details> <summary>This PR vs main</summary>    </details> ## Other work `QueryEntityError::QueryDoesNotMatch` also has an `UnsafeWorldCell` inside it. This one would be more complicated to rework while keeping the same functionality. ## Migration Guide The errors `EntityFetchError::NoSuchEntity` and `QueryEntityError::NoSuchEntity` now contain an `EntityDoesNotExistDetails` struct instead of an `UnsafeWorldCell`. If you were just printing these, they should work identically. --------- Co-authored-by: Benjamin Brienen <benjamin.brienen@outlook.com>
51 lines
1.9 KiB
Rust
51 lines
1.9 KiB
Rust
//! Contains error types returned by bevy's schedule.
|
|
|
|
use thiserror::Error;
|
|
|
|
use crate::{
|
|
component::ComponentId,
|
|
entity::{Entity, EntityDoesNotExistDetails},
|
|
schedule::InternedScheduleLabel,
|
|
};
|
|
|
|
/// The error type returned by [`World::try_run_schedule`] if the provided schedule does not exist.
|
|
///
|
|
/// [`World::try_run_schedule`]: crate::world::World::try_run_schedule
|
|
#[derive(Error, Debug)]
|
|
#[error("The schedule with the label {0:?} was not found.")]
|
|
pub struct TryRunScheduleError(pub InternedScheduleLabel);
|
|
|
|
/// An error that occurs when dynamically retrieving components from an entity.
|
|
#[derive(Error, Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum EntityComponentError {
|
|
/// The component with the given [`ComponentId`] does not exist on the entity.
|
|
#[error("The component with ID {0:?} does not exist on the entity.")]
|
|
MissingComponent(ComponentId),
|
|
/// The component with the given [`ComponentId`] was requested mutably more than once.
|
|
#[error("The component with ID {0:?} was requested mutably more than once.")]
|
|
AliasedMutability(ComponentId),
|
|
}
|
|
|
|
/// An error that occurs when fetching entities mutably from a world.
|
|
#[derive(Error, Debug, Clone, Copy)]
|
|
pub enum EntityFetchError {
|
|
/// The entity with the given ID does not exist.
|
|
#[error("The entity with ID {0} {1}")]
|
|
NoSuchEntity(Entity, EntityDoesNotExistDetails),
|
|
/// The entity with the given ID was requested mutably more than once.
|
|
#[error("The entity with ID {0} was requested mutably more than once")]
|
|
AliasedMutability(Entity),
|
|
}
|
|
|
|
impl PartialEq for EntityFetchError {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
match (self, other) {
|
|
(Self::NoSuchEntity(e1, _), Self::NoSuchEntity(e2, _)) if e1 == e2 => true,
|
|
(Self::AliasedMutability(e1), Self::AliasedMutability(e2)) if e1 == e2 => true,
|
|
_ => false,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Eq for EntityFetchError {}
|