From e392e99f7e12e8c69f7b6da57bcc341f26a70841 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=B0=D0=BD=D1=8F=20=D0=A7=D0=B5=D1=80=D0=B5=D0=BF?= Date: Wed, 15 Feb 2023 22:56:22 +0000 Subject: [PATCH] feat: improve `initialize_bundle` error message (#7464) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Objective This PR improves message that caused by duplicate components in bundle. ## Solution Show names of duplicate components. The solution is not very elegant, in my opinion, I will be happy to listen to suggestions for improving it Co-authored-by: Саня Череп <41489405+SDesya74@users.noreply.github.com> --- crates/bevy_ecs/src/bundle.rs | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/crates/bevy_ecs/src/bundle.rs b/crates/bevy_ecs/src/bundle.rs index 34d9b428ca..a2d091e549 100644 --- a/crates/bevy_ecs/src/bundle.rs +++ b/crates/bevy_ecs/src/bundle.rs @@ -3,6 +3,7 @@ //! This module contains the [`Bundle`] trait and some other helper types. pub use bevy_ecs_macros::Bundle; +use bevy_utils::HashSet; use crate::{ archetype::{ @@ -710,7 +711,7 @@ impl Bundles { let id = BundleId(bundle_infos.len()); let bundle_info = // SAFETY: T::component_id ensures info was created - unsafe { initialize_bundle(std::any::type_name::(), component_ids, id) }; + unsafe { initialize_bundle(std::any::type_name::(), components, component_ids, id) }; bundle_infos.push(bundle_info); id }); @@ -724,16 +725,35 @@ impl Bundles { /// `component_id` must be valid [`ComponentId`]'s unsafe fn initialize_bundle( bundle_type_name: &'static str, + components: &Components, component_ids: Vec, id: BundleId, ) -> BundleInfo { let mut deduped = component_ids.clone(); deduped.sort(); deduped.dedup(); - assert!( - deduped.len() == component_ids.len(), - "Bundle {bundle_type_name} has duplicate components", - ); + + if deduped.len() != component_ids.len() { + // TODO: Replace with `Vec::partition_dedup` once https://github.com/rust-lang/rust/issues/54279 is stabilized + let mut seen = HashSet::new(); + let mut dups = Vec::new(); + for id in component_ids { + if !seen.insert(id) { + dups.push(id); + } + } + + let names = dups + .into_iter() + .map(|id| { + // SAFETY: component_id exists and is therefore valid + unsafe { components.get_info_unchecked(id).name() } + }) + .collect::>() + .join(", "); + + panic!("Bundle {bundle_type_name} has duplicate components: {names}"); + } BundleInfo { id, component_ids } }