anput/
bundle.rs

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}