@@ -3,14 +3,15 @@ use bevy_platform::collections::{HashMap, HashSet};
3
3
use bevy_ptr:: OwningPtr ;
4
4
use bevy_utils:: TypeIdMap ;
5
5
use core:: { any:: TypeId , ptr:: NonNull } ;
6
+ use indexmap:: { IndexMap , IndexSet } ;
6
7
7
8
use crate :: {
8
9
archetype:: { Archetype , BundleComponentStatus , ComponentStatus } ,
9
10
bundle:: { Bundle , DynamicBundle } ,
10
11
change_detection:: MaybeLocation ,
11
12
component:: {
12
- ComponentId , Components , ComponentsRegistrator , RequiredComponentConstructor ,
13
- RequiredComponents , StorageType , Tick ,
13
+ ComponentId , Components , ComponentsRegistrator , RequiredComponentConstructor , StorageType ,
14
+ Tick ,
14
15
} ,
15
16
entity:: Entity ,
16
17
query:: DebugCheckedUnwrap as _,
@@ -59,6 +60,7 @@ pub enum InsertMode {
59
60
/// [`World`]: crate::world::World
60
61
pub struct BundleInfo {
61
62
pub ( super ) id : BundleId ,
63
+
62
64
/// The list of all components contributed by the bundle (including Required Components). This is in
63
65
/// the order `[EXPLICIT_COMPONENTS][REQUIRED_COMPONENTS]`
64
66
///
@@ -67,9 +69,10 @@ pub struct BundleInfo {
67
69
/// must have its storage initialized (i.e. columns created in tables, sparse set created),
68
70
/// and the range (0..`explicit_components_len`) must be in the same order as the source bundle
69
71
/// type writes its components in.
70
- pub ( super ) component_ids : Vec < ComponentId > ,
71
- pub ( super ) required_components : Vec < RequiredComponentConstructor > ,
72
- pub ( super ) explicit_components_len : usize ,
72
+ pub ( super ) contributed_components : Vec < ComponentId > ,
73
+
74
+ /// The list of constructors for all required components indirectly contributed by this bundle.
75
+ pub ( super ) required_component_constructors : Vec < RequiredComponentConstructor > ,
73
76
}
74
77
75
78
impl BundleInfo {
@@ -86,11 +89,10 @@ impl BundleInfo {
86
89
mut component_ids : Vec < ComponentId > ,
87
90
id : BundleId ,
88
91
) -> BundleInfo {
92
+ let explicit_component_ids = component_ids. iter ( ) . copied ( ) . collect :: < IndexSet < _ > > ( ) ;
93
+
89
94
// check for duplicates
90
- let mut deduped = component_ids. clone ( ) ;
91
- deduped. sort_unstable ( ) ;
92
- deduped. dedup ( ) ;
93
- if deduped. len ( ) != component_ids. len ( ) {
95
+ if explicit_component_ids. len ( ) != component_ids. len ( ) {
94
96
// TODO: Replace with `Vec::partition_dedup` once https://github.com/rust-lang/rust/issues/54279 is stabilized
95
97
let mut seen = <HashSet < _ > >:: default ( ) ;
96
98
let mut dups = Vec :: new ( ) ;
@@ -111,41 +113,39 @@ impl BundleInfo {
111
113
panic ! ( "Bundle {bundle_type_name} has duplicate components: {names:?}" ) ;
112
114
}
113
115
114
- // handle explicit components
115
- let explicit_components_len = component_ids. len ( ) ;
116
- let mut required_components = RequiredComponents :: default ( ) ;
117
- for component_id in component_ids. iter ( ) . copied ( ) {
116
+ let mut depth_first_components = IndexMap :: new ( ) ;
117
+ for & component_id in & component_ids {
118
118
// SAFETY: caller has verified that all ids are valid
119
119
let info = unsafe { components. get_info_unchecked ( component_id) } ;
120
- required_components. merge ( info. required_components ( ) ) ;
120
+
121
+ for ( & required_id, required_component) in & info. required_components ( ) . all {
122
+ depth_first_components
123
+ . entry ( required_id)
124
+ . or_insert_with ( || required_component. clone ( ) ) ;
125
+ }
126
+
121
127
storages. prepare_component ( info) ;
122
128
}
123
- required_components. remove_explicit_components ( & component_ids) ;
124
-
125
- // handle required components
126
- let required_components = required_components
127
- . 0
128
- . into_iter ( )
129
- . map ( |( component_id, v) | {
130
- // Safety: These ids came out of the passed `components`, so they must be valid.
131
- let info = unsafe { components. get_info_unchecked ( component_id) } ;
132
- storages. prepare_component ( info) ;
133
- // This adds required components to the component_ids list _after_ using that list to remove explicitly provided
134
- // components. This ordering is important!
135
- component_ids. push ( component_id) ;
136
- v. constructor
129
+
130
+ let required_components = depth_first_components
131
+ . iter ( )
132
+ . filter ( |& ( required_id, _) | !explicit_component_ids. contains ( required_id) )
133
+ . inspect ( |& ( & required_id, _) | {
134
+ // SAFETY: These ids came out of the passed `components`, so they must be valid.
135
+ storages. prepare_component ( unsafe { components. get_info_unchecked ( required_id) } ) ;
136
+ component_ids. push ( required_id) ;
137
137
} )
138
- . collect ( ) ;
138
+ . map ( |( _, required_component) | required_component. constructor . clone ( ) )
139
+ . collect :: < Vec < _ > > ( ) ;
139
140
140
141
// SAFETY: The caller ensures that component_ids:
141
142
// - is valid for the associated world
142
143
// - has had its storage initialized
143
144
// - is in the same order as the source bundle type
144
145
BundleInfo {
145
146
id,
146
- component_ids,
147
- required_components,
148
- explicit_components_len,
147
+ contributed_components : component_ids,
148
+ required_component_constructors : required_components,
149
149
}
150
150
}
151
151
@@ -155,27 +155,32 @@ impl BundleInfo {
155
155
self . id
156
156
}
157
157
158
+ /// Returns the length of the explicit components part of the [contributed_components](Self::contributed_components) list.
159
+ pub ( super ) fn explicit_components_len ( & self ) -> usize {
160
+ self . contributed_components . len ( ) - self . required_component_constructors . len ( )
161
+ }
162
+
158
163
/// Returns the [ID](ComponentId) of each component explicitly defined in this bundle (ex: Required Components are excluded).
159
164
///
160
165
/// For all components contributed by this bundle (including Required Components), see [`BundleInfo::contributed_components`]
161
166
#[ inline]
162
167
pub fn explicit_components ( & self ) -> & [ ComponentId ] {
163
- & self . component_ids [ 0 ..self . explicit_components_len ]
168
+ & self . contributed_components [ 0 ..self . explicit_components_len ( ) ]
164
169
}
165
170
166
171
/// Returns the [ID](ComponentId) of each Required Component needed by this bundle. This _does not include_ Required Components that are
167
172
/// explicitly provided by the bundle.
168
173
#[ inline]
169
174
pub fn required_components ( & self ) -> & [ ComponentId ] {
170
- & self . component_ids [ self . explicit_components_len ..]
175
+ & self . contributed_components [ self . explicit_components_len ( ) ..]
171
176
}
172
177
173
178
/// Returns the [ID](ComponentId) of each component contributed by this bundle. This includes Required Components.
174
179
///
175
180
/// For only components explicitly defined in this bundle, see [`BundleInfo::explicit_components`]
176
181
#[ inline]
177
182
pub fn contributed_components ( & self ) -> & [ ComponentId ] {
178
- & self . component_ids
183
+ & self . contributed_components
179
184
}
180
185
181
186
/// Returns an iterator over the [ID](ComponentId) of each component explicitly defined in this bundle (ex: this excludes Required Components).
@@ -190,7 +195,7 @@ impl BundleInfo {
190
195
/// To iterate only components explicitly defined in this bundle, see [`BundleInfo::iter_explicit_components`]
191
196
#[ inline]
192
197
pub fn iter_contributed_components ( & self ) -> impl Iterator < Item = ComponentId > + Clone + ' _ {
193
- self . component_ids . iter ( ) . copied ( )
198
+ self . contributed_components ( ) . iter ( ) . copied ( )
194
199
}
195
200
196
201
/// Returns an iterator over the [ID](ComponentId) of each Required Component needed by this bundle. This _does not include_ Required Components that are
@@ -236,7 +241,7 @@ impl BundleInfo {
236
241
// bundle_info.component_ids are also in "bundle order"
237
242
let mut bundle_component = 0 ;
238
243
let after_effect = bundle. get_components ( & mut |storage_type, component_ptr| {
239
- let component_id = * self . component_ids . get_unchecked ( bundle_component) ;
244
+ let component_id = * self . contributed_components . get_unchecked ( bundle_component) ;
240
245
// SAFETY: bundle_component is a valid index for this bundle
241
246
let status = unsafe { bundle_component_status. get_status ( bundle_component) } ;
242
247
match storage_type {
0 commit comments