1use crate::{
2 archetype::{ArchetypeColumnInfo, ArchetypeEntityRowAccess},
3 Component,
4};
5use intuicio_core::object::{DynamicObject, TypedDynamicObject};
6use intuicio_data::{managed::DynamicManaged, type_hash::TypeHash};
7use std::alloc::dealloc;
8
9#[derive(Default)]
10pub struct DynamicBundle {
11 components: Vec<DynamicManaged>,
12}
13
14impl DynamicBundle {
15 pub fn with_component<T>(mut self, data: T) -> Result<Self, T> {
16 self.add_component(data)?;
17 Ok(self)
18 }
19
20 pub fn with_component_raw(mut self, data: DynamicManaged) -> Self {
21 self.add_component_raw(data);
22 self
23 }
24
25 pub fn add_component<T>(&mut self, data: T) -> Result<(), T> {
26 self.add_component_raw(DynamicManaged::new(data)?);
27 Ok(())
28 }
29
30 pub fn add_component_raw(&mut self, data: DynamicManaged) {
31 if let Some(index) = self
32 .components
33 .iter()
34 .position(|component| component.type_hash() == data.type_hash())
35 {
36 self.components[index] = data;
37 } else {
38 self.components.push(data);
39 }
40 }
41
42 pub fn remove_component<T>(&mut self) -> Option<T> {
43 self.remove_component_raw(TypeHash::of::<T>())?
44 .consume()
45 .ok()
46 }
47
48 pub fn remove_component_raw(&mut self, type_hash: TypeHash) -> Option<DynamicManaged> {
49 if let Some(index) = self
50 .components
51 .iter()
52 .position(|component| component.type_hash() == &type_hash)
53 {
54 Some(self.components.swap_remove(index))
55 } else {
56 None
57 }
58 }
59}
60
61pub trait BundleColumns {
62 fn columns_static() -> Vec<ArchetypeColumnInfo>;
63
64 fn columns(&self) -> Vec<ArchetypeColumnInfo> {
65 Self::columns_static()
66 }
67}
68
69impl BundleColumns for () {
70 fn columns_static() -> Vec<ArchetypeColumnInfo> {
71 vec![]
72 }
73}
74
75impl BundleColumns for Vec<ArchetypeColumnInfo> {
76 fn columns_static() -> Vec<ArchetypeColumnInfo> {
77 vec![]
78 }
79
80 fn columns(&self) -> Vec<ArchetypeColumnInfo> {
81 self.to_owned()
82 }
83}
84
85impl BundleColumns for DynamicObject {
86 fn columns_static() -> Vec<ArchetypeColumnInfo> {
87 vec![]
88 }
89
90 fn columns(&self) -> Vec<ArchetypeColumnInfo> {
91 self.property_values()
92 .map(|object| {
93 let handle = object.type_handle();
94 unsafe {
95 ArchetypeColumnInfo::new_raw(
96 handle.type_hash(),
97 *handle.layout(),
98 handle.finalizer(),
99 )
100 }
101 })
102 .collect()
103 }
104}
105
106impl BundleColumns for TypedDynamicObject {
107 fn columns_static() -> Vec<ArchetypeColumnInfo> {
108 vec![]
109 }
110
111 fn columns(&self) -> Vec<ArchetypeColumnInfo> {
112 self.property_values()
113 .map(|object| {
114 let handle = object.type_handle();
115 unsafe {
116 ArchetypeColumnInfo::new_raw(
117 handle.type_hash(),
118 *handle.layout(),
119 handle.finalizer(),
120 )
121 }
122 })
123 .collect()
124 }
125}
126
127impl BundleColumns for DynamicBundle {
128 fn columns_static() -> Vec<ArchetypeColumnInfo> {
129 vec![]
130 }
131
132 fn columns(&self) -> Vec<ArchetypeColumnInfo> {
133 self.components
134 .iter()
135 .map(|component| unsafe {
136 ArchetypeColumnInfo::new_raw(
137 *component.type_hash(),
138 *component.layout(),
139 component.finalizer(),
140 )
141 })
142 .collect()
143 }
144}
145
146macro_rules! impl_bundle_columns_tuple {
147 ($($type:ident),+) => {
148 impl<$($type: Component),+> BundleColumns for ($($type,)+) {
149 fn columns_static() -> Vec<ArchetypeColumnInfo> {
150 vec![$(ArchetypeColumnInfo::new::<$type>()),+]
151 }
152 }
153 };
154}
155
156impl_bundle_columns_tuple!(A);
157impl_bundle_columns_tuple!(A, B);
158impl_bundle_columns_tuple!(A, B, C);
159impl_bundle_columns_tuple!(A, B, C, D);
160impl_bundle_columns_tuple!(A, B, C, D, E);
161impl_bundle_columns_tuple!(A, B, C, D, E, F);
162impl_bundle_columns_tuple!(A, B, C, D, E, F, G);
163impl_bundle_columns_tuple!(A, B, C, D, E, F, G, H);
164impl_bundle_columns_tuple!(A, B, C, D, E, F, G, H, I);
165impl_bundle_columns_tuple!(A, B, C, D, E, F, G, H, I, J);
166impl_bundle_columns_tuple!(A, B, C, D, E, F, G, H, I, J, K);
167impl_bundle_columns_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);
168impl_bundle_columns_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M);
169impl_bundle_columns_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
170impl_bundle_columns_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
171impl_bundle_columns_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
172
173pub trait Bundle: BundleColumns {
174 fn initialize_into(self, access: &ArchetypeEntityRowAccess);
175}
176
177impl Bundle for () {
178 fn initialize_into(self, _: &ArchetypeEntityRowAccess) {}
179}
180
181impl Bundle for DynamicObject {
182 fn initialize_into(mut self, access: &ArchetypeEntityRowAccess) {
183 for (_, object) in self.drain() {
184 unsafe {
185 let (handle, source_memory) = object.into_inner();
186 let target_memory = access.data(handle.type_hash()).unwrap();
187 target_memory.copy_from(source_memory, handle.layout().size());
188 dealloc(source_memory, *handle.layout());
189 }
190 }
191 }
192}
193
194impl Bundle for TypedDynamicObject {
195 fn initialize_into(mut self, access: &ArchetypeEntityRowAccess) {
196 for (_, object) in self.drain() {
197 unsafe {
198 let (handle, source_memory) = object.into_inner();
199 let target_memory = access.data(handle.type_hash()).unwrap();
200 target_memory.copy_from(source_memory, handle.layout().size());
201 dealloc(source_memory, *handle.layout());
202 }
203 }
204 }
205}
206
207impl Bundle for DynamicBundle {
208 fn initialize_into(self, access: &ArchetypeEntityRowAccess) {
209 for component in self.components {
210 unsafe {
211 let (type_hash, _, source_memory, layout, _) = component.into_inner();
212 let target_memory = access.data(type_hash).unwrap();
213 target_memory.copy_from(source_memory, layout.size());
214 dealloc(source_memory, layout);
215 }
216 }
217 }
218}
219
220macro_rules! impl_bundle_tuple {
221 ($($type:ident),+) => {
222 impl<$($type: Component),+> Bundle for ($($type,)+) {
223 fn initialize_into(self, access: &ArchetypeEntityRowAccess) {
224 #[allow(non_snake_case)]
225 let ($($type,)+) = self;
226 $(
227 unsafe { access.initialize($type).unwrap(); };
228 )+
229 }
230 }
231 };
232}
233
234impl_bundle_tuple!(A);
235impl_bundle_tuple!(A, B);
236impl_bundle_tuple!(A, B, C);
237impl_bundle_tuple!(A, B, C, D);
238impl_bundle_tuple!(A, B, C, D, E);
239impl_bundle_tuple!(A, B, C, D, E, F);
240impl_bundle_tuple!(A, B, C, D, E, F, G);
241impl_bundle_tuple!(A, B, C, D, E, F, G, H);
242impl_bundle_tuple!(A, B, C, D, E, F, G, H, I);
243impl_bundle_tuple!(A, B, C, D, E, F, G, H, I, J);
244impl_bundle_tuple!(A, B, C, D, E, F, G, H, I, J, K);
245impl_bundle_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);
246impl_bundle_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M);
247impl_bundle_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
248impl_bundle_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
249impl_bundle_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
250
251pub struct BundleChain<A: Bundle, B: Bundle>(pub A, pub B);
252
253impl<A: Bundle, B: Bundle> BundleColumns for BundleChain<A, B> {
254 fn columns_static() -> Vec<ArchetypeColumnInfo> {
255 let mut result = A::columns_static();
256 result.extend(B::columns_static());
257 result
258 }
259}
260
261impl<A: Bundle, B: Bundle> Bundle for BundleChain<A, B> {
262 fn initialize_into(self, access: &ArchetypeEntityRowAccess) {
263 self.0.initialize_into(access);
264 self.1.initialize_into(access);
265 }
266}