1use crate::{
2 archetype::{ArchetypeColumnInfo, ArchetypeEntityRowAccess},
3 component::Component,
4};
5use intuicio_core::object::{DynamicObject, TypedDynamicObject};
6use intuicio_data::{
7 lifetime::{ValueReadAccess, ValueWriteAccess},
8 managed::DynamicManaged,
9 non_zero_dealloc,
10 type_hash::TypeHash,
11};
12
13#[derive(Default)]
14pub struct DynamicBundle {
15 components: Vec<DynamicManaged>,
16}
17
18impl DynamicBundle {
19 pub fn extend<I: IntoIterator<Item = DynamicManaged>>(mut self, iter: I) -> Self {
20 self.components.extend(iter);
21 self
22 }
23
24 pub fn merge(mut self, other: Self) -> Self {
25 self.components.extend(other.components);
26 self
27 }
28
29 pub fn append(&mut self, other: Self) {
30 self.components.extend(other.components);
31 }
32
33 pub fn with_component<T: Component>(mut self, component: T) -> Result<Self, T> {
34 self.add_component(component)?;
35 Ok(self)
36 }
37
38 pub fn with_component_raw(mut self, component: DynamicManaged) -> Self {
39 self.add_component_raw(component);
40 self
41 }
42
43 pub fn new<T: Component>(component: T) -> Result<Self, T> {
44 Ok(Self::new_raw(DynamicManaged::new(component)?))
45 }
46
47 pub fn new_raw(component: DynamicManaged) -> Self {
48 Self {
49 components: vec![component],
50 }
51 }
52
53 pub fn is_empty(&self) -> bool {
54 self.components.is_empty()
55 }
56
57 pub fn len(&self) -> usize {
58 self.components.len()
59 }
60
61 pub fn clear(&mut self) {
62 self.components.clear();
63 }
64
65 pub fn add_component<T: Component>(&mut self, component: T) -> Result<(), T> {
66 self.add_component_raw(DynamicManaged::new(component)?);
67 Ok(())
68 }
69
70 pub fn add_component_raw(&mut self, component: DynamicManaged) {
71 if let Some(index) = self
72 .components
73 .iter()
74 .position(|c| c.type_hash() == component.type_hash())
75 {
76 self.components[index] = component;
77 } else {
78 self.components.push(component);
79 }
80 }
81
82 pub fn remove_component<T: Component>(&mut self) -> Option<T> {
83 self.remove_component_raw(TypeHash::of::<T>())?
84 .consume()
85 .ok()
86 }
87
88 pub fn remove_component_raw(&mut self, type_hash: TypeHash) -> Option<DynamicManaged> {
89 if let Some(index) = self
90 .components
91 .iter()
92 .position(|component| component.type_hash() == &type_hash)
93 {
94 Some(self.components.swap_remove(index))
95 } else {
96 None
97 }
98 }
99
100 pub fn components(&self) -> &[DynamicManaged] {
101 &self.components
102 }
103
104 pub fn component<T: Component>(&'_ self) -> Option<ValueReadAccess<'_, T>> {
105 self.component_raw(TypeHash::of::<T>())
106 .and_then(|c| c.read())
107 }
108
109 pub fn component_raw(&self, type_hash: TypeHash) -> Option<&DynamicManaged> {
110 self.components.iter().find(|c| c.type_hash() == &type_hash)
111 }
112
113 pub fn component_mut<T: Component>(&'_ mut self) -> Option<ValueWriteAccess<'_, T>> {
114 self.component_mut_raw(TypeHash::of::<T>())
115 .and_then(|c| c.write())
116 }
117
118 pub fn component_mut_raw(&mut self, type_hash: TypeHash) -> Option<&mut DynamicManaged> {
119 self.components
120 .iter_mut()
121 .find(|c| c.type_hash() == &type_hash)
122 }
123}
124
125pub trait BundleColumns {
126 fn columns_static() -> Vec<ArchetypeColumnInfo>;
127
128 fn columns(&self) -> Vec<ArchetypeColumnInfo> {
129 Self::columns_static()
130 }
131}
132
133impl BundleColumns for () {
134 fn columns_static() -> Vec<ArchetypeColumnInfo> {
135 vec![]
136 }
137}
138
139impl BundleColumns for Vec<ArchetypeColumnInfo> {
140 fn columns_static() -> Vec<ArchetypeColumnInfo> {
141 unreachable!()
142 }
143
144 fn columns(&self) -> Vec<ArchetypeColumnInfo> {
145 self.to_owned()
146 }
147}
148
149impl BundleColumns for DynamicObject {
150 fn columns_static() -> Vec<ArchetypeColumnInfo> {
151 unreachable!()
152 }
153
154 fn columns(&self) -> Vec<ArchetypeColumnInfo> {
155 self.property_values()
156 .map(|object| {
157 let handle = object.type_handle();
158 unsafe {
159 ArchetypeColumnInfo::new_raw(
160 handle.type_hash(),
161 *handle.layout(),
162 handle.finalizer(),
163 )
164 }
165 })
166 .collect()
167 }
168}
169
170impl BundleColumns for TypedDynamicObject {
171 fn columns_static() -> Vec<ArchetypeColumnInfo> {
172 unreachable!()
173 }
174
175 fn columns(&self) -> Vec<ArchetypeColumnInfo> {
176 self.property_values()
177 .map(|object| {
178 let handle = object.type_handle();
179 unsafe {
180 ArchetypeColumnInfo::new_raw(
181 handle.type_hash(),
182 *handle.layout(),
183 handle.finalizer(),
184 )
185 }
186 })
187 .collect()
188 }
189}
190
191impl BundleColumns for DynamicBundle {
192 fn columns_static() -> Vec<ArchetypeColumnInfo> {
193 unreachable!()
194 }
195
196 fn columns(&self) -> Vec<ArchetypeColumnInfo> {
197 self.components
198 .iter()
199 .map(|component| unsafe {
200 ArchetypeColumnInfo::new_raw(
201 *component.type_hash(),
202 *component.layout(),
203 component.finalizer(),
204 )
205 })
206 .collect()
207 }
208}
209
210macro_rules! impl_bundle_columns_tuple {
211 ($($type:ident),+) => {
212 impl<$($type: Component),+> BundleColumns for ($($type,)+) {
213 fn columns_static() -> Vec<ArchetypeColumnInfo> {
214 vec![$(ArchetypeColumnInfo::new::<$type>()),+]
215 }
216 }
217 };
218}
219
220impl_bundle_columns_tuple!(A);
221impl_bundle_columns_tuple!(A, B);
222impl_bundle_columns_tuple!(A, B, C);
223impl_bundle_columns_tuple!(A, B, C, D);
224impl_bundle_columns_tuple!(A, B, C, D, E);
225impl_bundle_columns_tuple!(A, B, C, D, E, F);
226impl_bundle_columns_tuple!(A, B, C, D, E, F, G);
227impl_bundle_columns_tuple!(A, B, C, D, E, F, G, H);
228impl_bundle_columns_tuple!(A, B, C, D, E, F, G, H, I);
229impl_bundle_columns_tuple!(A, B, C, D, E, F, G, H, I, J);
230impl_bundle_columns_tuple!(A, B, C, D, E, F, G, H, I, J, K);
231impl_bundle_columns_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);
232impl_bundle_columns_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M);
233impl_bundle_columns_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
234impl_bundle_columns_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
235impl_bundle_columns_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
236
237pub trait Bundle: BundleColumns {
238 fn initialize_into(self, access: &ArchetypeEntityRowAccess);
239}
240
241impl Bundle for () {
242 fn initialize_into(self, _: &ArchetypeEntityRowAccess) {}
243}
244
245impl Bundle for DynamicObject {
246 fn initialize_into(mut self, access: &ArchetypeEntityRowAccess) {
247 for (_, object) in self.drain() {
248 unsafe {
249 let (handle, source_memory) = object.into_inner();
250 let target_memory = access.data(handle.type_hash()).unwrap();
251 target_memory.copy_from(source_memory, handle.layout().size());
252 non_zero_dealloc(source_memory, *handle.layout());
253 }
254 }
255 }
256}
257
258impl Bundle for TypedDynamicObject {
259 fn initialize_into(mut self, access: &ArchetypeEntityRowAccess) {
260 for (_, object) in self.drain() {
261 unsafe {
262 let (handle, source_memory) = object.into_inner();
263 let target_memory = access.data(handle.type_hash()).unwrap();
264 target_memory.copy_from(source_memory, handle.layout().size());
265 non_zero_dealloc(source_memory, *handle.layout());
266 }
267 }
268 }
269}
270
271impl Bundle for DynamicBundle {
272 fn initialize_into(self, access: &ArchetypeEntityRowAccess) {
273 for component in self.components {
274 unsafe {
275 let (type_hash, _, source_memory, layout, _) = component.into_inner();
276 let target_memory = access.data(type_hash).unwrap();
277 target_memory.copy_from(source_memory, layout.size());
278 non_zero_dealloc(source_memory, layout);
279 }
280 }
281 }
282}
283
284macro_rules! impl_bundle_tuple {
285 ($($type:ident),+) => {
286 impl<$($type: Component),+> Bundle for ($($type,)+) {
287 fn initialize_into(self, access: &ArchetypeEntityRowAccess) {
288 #[allow(non_snake_case)]
289 let ($($type,)+) = self;
290 $(
291 unsafe { access.initialize($type).unwrap(); };
292 )+
293 }
294 }
295 };
296}
297
298impl_bundle_tuple!(A);
299impl_bundle_tuple!(A, B);
300impl_bundle_tuple!(A, B, C);
301impl_bundle_tuple!(A, B, C, D);
302impl_bundle_tuple!(A, B, C, D, E);
303impl_bundle_tuple!(A, B, C, D, E, F);
304impl_bundle_tuple!(A, B, C, D, E, F, G);
305impl_bundle_tuple!(A, B, C, D, E, F, G, H);
306impl_bundle_tuple!(A, B, C, D, E, F, G, H, I);
307impl_bundle_tuple!(A, B, C, D, E, F, G, H, I, J);
308impl_bundle_tuple!(A, B, C, D, E, F, G, H, I, J, K);
309impl_bundle_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);
310impl_bundle_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M);
311impl_bundle_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
312impl_bundle_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
313impl_bundle_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
314
315pub struct BundleChain<A: Bundle, B: Bundle>(pub A, pub B);
316
317impl<A: Bundle, B: Bundle> BundleColumns for BundleChain<A, B> {
318 fn columns_static() -> Vec<ArchetypeColumnInfo> {
319 let mut result = A::columns_static();
320 result.extend(B::columns_static());
321 result
322 }
323}
324
325impl<A: Bundle, B: Bundle> Bundle for BundleChain<A, B> {
326 fn initialize_into(self, access: &ArchetypeEntityRowAccess) {
327 self.0.initialize_into(access);
328 self.1.initialize_into(access);
329 }
330}
331
332pub struct BundleOnce<T: Component>(pub T);
333
334impl<T: Component> BundleColumns for BundleOnce<T> {
335 fn columns_static() -> Vec<ArchetypeColumnInfo> {
336 vec![ArchetypeColumnInfo::new::<T>()]
337 }
338}
339
340impl<T: Component> Bundle for BundleOnce<T> {
341 fn initialize_into(self, access: &ArchetypeEntityRowAccess) {
342 unsafe { access.initialize(self.0).unwrap() };
343 }
344}
345
346#[cfg(test)]
347mod tests {
348 use super::*;
349
350 #[test]
351 fn test_dynamic_bundle() {
352 let bundle = DynamicBundle::default()
353 .with_component(42i32)
354 .unwrap()
355 .with_component(4.2f32)
356 .unwrap()
357 .with_component("Hello World".to_owned())
358 .unwrap();
359
360 assert_eq!(
361 bundle.columns(),
362 vec![
363 ArchetypeColumnInfo::new::<i32>(),
364 ArchetypeColumnInfo::new::<f32>(),
365 ArchetypeColumnInfo::new::<String>()
366 ]
367 );
368 }
369}