bevy/tests/ecs/ambiguity_detection.rs
Clar Fon 711246aa34
Update hashbrown to 0.15 (#15801)
Updating dependencies; adopted version of #15696. (Supercedes #15696.)

Long answer: hashbrown is no longer using ahash by default, meaning that
we can't use the default-hasher methods with ahasher. So, we have to use
the longer-winded versions instead. This takes the opportunity to also
switch our default hasher as well, but without actually enabling the
default-hasher feature for hashbrown, meaning that we'll be able to
change our hasher more easily at the cost of all of these method calls
being obnoxious forever.

One large change from 0.15 is that `insert_unique_unchecked` is now
`unsafe`, and for cases where unsafe code was denied at the crate level,
I replaced it with `insert`.

## Migration Guide

`bevy_utils` has updated its version of `hashbrown` to 0.15 and now
defaults to `foldhash` instead of `ahash`. This means that if you've
hard-coded your hasher to `bevy_utils::AHasher` or separately used the
`ahash` crate in your code, you may need to switch to `foldhash` to
ensure that everything works like it does in Bevy.
2024-12-10 19:45:50 +00:00

80 lines
3 KiB
Rust

//! A test to confirm that `bevy` doesn't regress its system ambiguities count when using [`DefaultPlugins`].
//! This is run in CI.
//!
//! Note that because this test requires rendering, it isn't actually an integration test!
//! Instead, it's secretly an example: you can run this test manually using `cargo run --example ambiguity_detection`.
use bevy::{
ecs::schedule::{InternedScheduleLabel, LogLevel, ScheduleBuildSettings},
prelude::*,
render::pipelined_rendering::RenderExtractApp,
utils::HashMap,
};
fn main() {
let mut app = App::new();
app.add_plugins(DefaultPlugins);
let main_app = app.main_mut();
configure_ambiguity_detection(main_app);
let render_extract_app = app.sub_app_mut(RenderExtractApp);
configure_ambiguity_detection(render_extract_app);
// Ambiguities in the RenderApp are currently allowed.
// Eventually, we should forbid these: see https://github.com/bevyengine/bevy/issues/7386
// Uncomment the lines below to show the current ambiguities in the RenderApp.
// let sub_app = app.sub_app_mut(bevy_render::RenderApp);
// configure_ambiguity_detection(sub_app);
app.finish();
app.cleanup();
app.update();
let main_app_ambiguities = count_ambiguities(app.main());
assert_eq!(
main_app_ambiguities.total(),
0,
"Main app has unexpected ambiguities among the following schedules: \n{main_app_ambiguities:#?}.",
);
// RenderApp is not checked here, because it is not within the App at this point.
let render_extract_ambiguities = count_ambiguities(app.sub_app(RenderExtractApp));
assert_eq!(
render_extract_ambiguities.total(),
0,
"RenderExtract app has unexpected ambiguities among the following schedules: \n{render_extract_ambiguities:#?}",
);
}
/// Contains the number of conflicting systems per schedule.
#[derive(Debug, Deref, DerefMut)]
struct AmbiguitiesCount(pub HashMap<InternedScheduleLabel, usize>);
impl AmbiguitiesCount {
fn total(&self) -> usize {
self.values().sum()
}
}
fn configure_ambiguity_detection(sub_app: &mut SubApp) {
let mut schedules = sub_app.world_mut().resource_mut::<Schedules>();
for (_, schedule) in schedules.iter_mut() {
schedule.set_build_settings(ScheduleBuildSettings {
// NOTE: you can change this to `LogLevel::Ignore` to easily see the current number of ambiguities.
ambiguity_detection: LogLevel::Warn,
use_shortnames: false,
..default()
});
}
}
/// Returns the number of conflicting systems per schedule.
fn count_ambiguities(sub_app: &SubApp) -> AmbiguitiesCount {
let schedules = sub_app.world().resource::<Schedules>();
let mut ambiguities = <HashMap<_, _>>::default();
for (_, schedule) in schedules.iter() {
let ambiguities_in_schedule = schedule.graph().conflicting_systems().len();
ambiguities.insert(schedule.label(), ambiguities_in_schedule);
}
AmbiguitiesCount(ambiguities)
}