1- use core:: { alloc :: Layout , ptr:: NonNull } ;
1+ use core:: ptr:: NonNull ;
22
33use bevy:: {
44 ecs:: component:: { ComponentId , Mutable } ,
55 prelude:: * ,
6- ptr:: PtrMut ,
6+ ptr:: OwningPtr ,
77} ;
8+ use bumpalo:: Bump ;
89
910/// Like [`EntityWorldMut`], but buffers all structural changes.
1011///
@@ -106,9 +107,9 @@ impl DeferredChanges {
106107/// Buffered insertions stored in type-erased way.
107108#[ derive( Default ) ]
108109pub ( crate ) struct DeferredInsertions {
110+ ptrs : Vec < NonNull < u8 > > ,
109111 ids : Vec < ComponentId > ,
110- offsets : Vec < usize > ,
111- data : Vec < u8 > ,
112+ bump : Bump ,
112113}
113114
114115impl DeferredInsertions {
@@ -119,39 +120,14 @@ impl DeferredInsertions {
119120 /// Component ID should correspond to the passed type, otherwise [`Self::apply`] won't
120121 /// write the data correctly.
121122 unsafe fn insert < C : Component > ( & mut self , component : C , component_id : ComponentId ) {
122- let layout = Layout :: new :: < C > ( ) ;
123-
124- // If items would otherwise not be aligned, add alignment.
125- let align = layout. align ( ) ;
126- let extra_offset = if !self . data . len ( ) . is_multiple_of ( align) {
127- align - ( self . data . len ( ) % align)
128- } else {
129- 0
130- } ;
131-
132- let grow = layout. size ( ) + extra_offset;
133- let offset = self . data . len ( ) + extra_offset;
134-
123+ let ptr: NonNull < _ > = self . bump . alloc ( component) . into ( ) ;
124+ self . ptrs . push ( ptr. cast ( ) ) ;
135125 self . ids . push ( component_id) ;
136- self . offsets . push ( offset) ;
137- self . data . resize ( self . data . len ( ) + grow, 0 ) ;
138-
139- // SAFETY: pointer references a properly allocated memory.
140- unsafe {
141- let ptr = self . data . as_mut_ptr ( ) . byte_add ( offset) as * mut C ;
142- ptr. write ( component) ;
143- }
144126 }
145127
146128 fn apply ( & mut self , entity : & mut EntityWorldMut ) {
147- // SAFETY: iterator produces valid pointers for each component ID.
148- unsafe {
149- let iter = self . offsets . iter ( ) . map ( |& offset| {
150- let ptr = PtrMut :: new ( NonNull :: new_unchecked ( self . data . as_mut_ptr ( ) ) ) ;
151- ptr. byte_add ( offset) . promote ( )
152- } ) ;
153- entity. insert_by_ids ( & self . ids , iter) ;
154- }
129+ // SAFETY: each pointer is valid and points to a value of the type corresponding to its ID.
130+ unsafe { entity. insert_by_ids ( & self . ids , self . ptrs . iter ( ) . map ( |& p| OwningPtr :: new ( p) ) ) } ;
155131 }
156132
157133 fn is_empty ( & self ) -> bool {
@@ -160,11 +136,14 @@ impl DeferredInsertions {
160136
161137 fn clear ( & mut self ) {
162138 self . ids . clear ( ) ;
163- self . offsets . clear ( ) ;
164- self . data . clear ( ) ;
139+ self . ptrs . clear ( ) ;
140+ self . bump . reset ( ) ;
165141 }
166142}
167143
144+ // SAFETY: `NonNull` pointers are unique and allocated by a private arena.
145+ unsafe impl Send for DeferredInsertions { }
146+
168147#[ cfg( test) ]
169148mod tests {
170149 use alloc:: sync:: Arc ;
0 commit comments